MINOR: ha-inject: Move some mux h1 parsing functions to cfgparse-mux_h1.c

Add cfgparse-mux_h1.c new C file to avoid compiling such code for ha-inject.
Move mux_h1.c parsing functions to this new file.
This commit is contained in:
Frederic Lecaille 2025-12-10 18:37:01 +01:00
parent 7b801abb65
commit 27a30ab5fa
4 changed files with 275 additions and 258 deletions

View File

@ -1005,7 +1005,8 @@ OBJS_COMMON += src/mux_h2.o src/mux_h1.o src/mux_fcgi.o \
src/version.o src/ncbmbuf.o src/ech.o \
OBJS += $(OBJS_COMMON) src/acl.o src/cfgdiag.o src/cfgparse.o \
src/cfgparse-global.o src/cfgparse-listen.o src/cfgparse-mux_h2.o \
src/cfgparse-global.o src/cfgparse-listen.o src/cfgparse-mux_h1.o \
src/cfgparse-mux_h2.o \
src/cfgparse-tcp.o src/cfgparse-thread.o \
src/cfgparse-unix.o src/check.o src/dns.o src/dns_ring.o src/event_hdl.o \
src/extcheck.o src/filters.o src/flt_bwlim.o src/flt_http_comp.o \

View File

@ -22,6 +22,8 @@
#ifndef _HAPROXY_MUX_H1_T_H
#define _HAPROXY_MUX_H1_T_H
#include <import/ist.h>
#include <haproxy/api-t.h>
#include <haproxy/show_flags-t.h>
@ -112,6 +114,21 @@ static forceinline char *h1c_show_flags(char *buf, size_t len, const char *delim
#define H1S_F_BODYLESS_REQ 0x00040000 /* Bodyless request message */
#define H1S_F_BODYLESS_RESP 0x00080000 /* Bodyless response message */
/* An entry in a headers map */
struct h1_hdr_entry {
struct ist name;
struct ebpt_node node;
};
/* Map of headers used to convert outgoing headers */
struct h1_hdrs_map {
char *name;
struct eb_root map;
};
extern struct h1_hdrs_map hdrs_map;
extern int accept_payload_with_any_method;
/* This function is used to report flags in debugging tools. Please reflect
* below any single-bit flag addition above in the same order via the
* __APPEND_FLAG macro. The new end of the buffer is returned.

254
src/cfgparse-mux_h1.c Normal file
View File

@ -0,0 +1,254 @@
#include <string.h>
#include <import/ebistree.h>
#include <haproxy/api.h>
#include <haproxy/cfgparse.h>
#include <haproxy/errors.h>
#include <haproxy/mux_h1-t.h>
#include <haproxy/tools.h>
/* Add an entry in the headers map. Returns -1 on error and 0 on success. */
static int add_hdr_case_adjust(const char *from, const char *to, char **err)
{
struct h1_hdr_entry *entry;
/* Be sure there is a non-empty <to> */
if (!strlen(to)) {
memprintf(err, "expect <to>");
return -1;
}
/* Be sure only the case differs between <from> and <to> */
if (strcasecmp(from, to) != 0) {
memprintf(err, "<from> and <to> must not differ except the case");
return -1;
}
/* Be sure <from> does not already existsin the tree */
if (ebis_lookup(&hdrs_map.map, from)) {
memprintf(err, "duplicate entry '%s'", from);
return -1;
}
/* Create the entry and insert it in the tree */
entry = malloc(sizeof(*entry));
if (!entry) {
memprintf(err, "out of memory");
return -1;
}
entry->node.key = strdup(from);
entry->name = ist(strdup(to));
if (!entry->node.key || !isttest(entry->name)) {
free(entry->node.key);
istfree(&entry->name);
free(entry);
memprintf(err, "out of memory");
return -1;
}
ebis_insert(&hdrs_map.map, &entry->node);
return 0;
}
static void h1_hdeaders_case_adjust_deinit()
{
struct ebpt_node *node, *next;
struct h1_hdr_entry *entry;
node = ebpt_first(&hdrs_map.map);
while (node) {
next = ebpt_next(node);
ebpt_delete(node);
entry = container_of(node, struct h1_hdr_entry, node);
free(entry->node.key);
istfree(&entry->name);
free(entry);
node = next;
}
free(hdrs_map.name);
}
static int cfg_h1_headers_case_adjust_postparser()
{
FILE *file = NULL;
char *c, *key_beg, *key_end, *value_beg, *value_end;
char *err;
int rc, line = 0, err_code = 0;
if (!hdrs_map.name)
goto end;
file = fopen(hdrs_map.name, "r");
if (!file) {
ha_alert("h1-headers-case-adjust-file '%s': failed to open file.\n",
hdrs_map.name);
err_code |= ERR_ALERT | ERR_FATAL;
goto end;
}
/* now parse all lines. The file may contain only two header name per
* line, separated by spaces. All heading and trailing spaces will be
* ignored. Lines starting with a # are ignored.
*/
while (fgets(trash.area, trash.size, file) != NULL) {
line++;
c = trash.area;
/* strip leading spaces and tabs */
while (*c == ' ' || *c == '\t')
c++;
/* ignore emptu lines, or lines beginning with a dash */
if (*c == '#' || *c == '\0' || *c == '\r' || *c == '\n')
continue;
/* look for the end of the key */
key_beg = c;
while (*c != '\0' && *c != ' ' && *c != '\t' && *c != '\n' && *c != '\r')
c++;
key_end = c;
/* strip middle spaces and tabs */
while (*c == ' ' || *c == '\t')
c++;
/* look for the end of the value, it is the end of the line */
value_beg = c;
while (*c && *c != '\n' && *c != '\r')
c++;
value_end = c;
/* trim possibly trailing spaces and tabs */
while (value_end > value_beg && (value_end[-1] == ' ' || value_end[-1] == '\t'))
value_end--;
/* set final \0 and check entries */
*key_end = '\0';
*value_end = '\0';
err = NULL;
rc = add_hdr_case_adjust(key_beg, value_beg, &err);
if (rc < 0) {
ha_alert("h1-headers-case-adjust-file '%s' : %s at line %d.\n",
hdrs_map.name, err, line);
err_code |= ERR_ALERT | ERR_FATAL;
free(err);
goto end;
}
if (rc > 0) {
ha_warning("h1-headers-case-adjust-file '%s' : %s at line %d.\n",
hdrs_map.name, err, line);
err_code |= ERR_WARN;
free(err);
}
}
end:
if (file)
fclose(file);
hap_register_post_deinit(h1_hdeaders_case_adjust_deinit);
return err_code;
}
/* config parser for global "h1-accept-payload_=-with-any-method" */
static int cfg_parse_h1_accept_payload_with_any_method(char **args, int section_type, struct proxy *curpx,
const struct proxy *defpx, const char *file, int line,
char **err)
{
if (too_many_args(0, args, err, NULL))
return -1;
accept_payload_with_any_method = 1;
return 0;
}
/* config parser for global "h1-header-case-adjust" */
static int cfg_parse_h1_header_case_adjust(char **args, int section_type, struct proxy *curpx,
const struct proxy *defpx, const char *file, int line,
char **err)
{
if (too_many_args(2, args, err, NULL))
return -1;
if (!*(args[1]) || !*(args[2])) {
memprintf(err, "'%s' expects <from> and <to> as argument.", args[0]);
return -1;
}
return add_hdr_case_adjust(args[1], args[2], err);
}
/* config parser for global "h1-headers-case-adjust-file" */
static int cfg_parse_h1_headers_case_adjust_file(char **args, int section_type, struct proxy *curpx,
const struct proxy *defpx, const char *file, int line,
char **err)
{
if (too_many_args(1, args, err, NULL))
return -1;
if (!*(args[1])) {
memprintf(err, "'%s' expects <file> as argument.", args[0]);
return -1;
}
free(hdrs_map.name);
hdrs_map.name = strdup(args[1]);
if (!hdrs_map.name) {
memprintf(err, "'%s %s' : out of memory", args[0], args[1]);
return -1;
}
return 0;
}
/* config parser for global "tune.h1.zero-copy-fwd-recv" */
static int cfg_parse_h1_zero_copy_fwd_rcv(char **args, int section_type, struct proxy *curpx,
const struct proxy *defpx, const char *file, int line,
char **err)
{
if (too_many_args(1, args, err, NULL))
return -1;
if (strcmp(args[1], "on") == 0)
global.tune.no_zero_copy_fwd &= ~NO_ZERO_COPY_FWD_H1_RCV;
else if (strcmp(args[1], "off") == 0)
global.tune.no_zero_copy_fwd |= NO_ZERO_COPY_FWD_H1_RCV;
else {
memprintf(err, "'%s' expects 'on' or 'off'.", args[0]);
return -1;
}
return 0;
}
/* config parser for global "tune.h1.zero-copy-fwd-send" */
static int cfg_parse_h1_zero_copy_fwd_snd(char **args, int section_type, struct proxy *curpx,
const struct proxy *defpx, const char *file, int line,
char **err)
{
if (too_many_args(1, args, err, NULL))
return -1;
if (strcmp(args[1], "on") == 0)
global.tune.no_zero_copy_fwd &= ~NO_ZERO_COPY_FWD_H1_SND;
else if (strcmp(args[1], "off") == 0)
global.tune.no_zero_copy_fwd |= NO_ZERO_COPY_FWD_H1_SND;
else {
memprintf(err, "'%s' expects 'on' or 'off'.", args[0]);
return -1;
}
return 0;
}
/* config keyword parsers */
static struct cfg_kw_list cfg_kws = {{ }, {
{ CFG_GLOBAL, "h1-accept-payload-with-any-method", cfg_parse_h1_accept_payload_with_any_method },
{ CFG_GLOBAL, "h1-case-adjust", cfg_parse_h1_header_case_adjust },
{ CFG_GLOBAL, "h1-case-adjust-file", cfg_parse_h1_headers_case_adjust_file },
{ CFG_GLOBAL, "tune.h1.zero-copy-fwd-recv", cfg_parse_h1_zero_copy_fwd_rcv },
{ CFG_GLOBAL, "tune.h1.zero-copy-fwd-send", cfg_parse_h1_zero_copy_fwd_snd },
{ 0, NULL, NULL },
}
};
INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
REGISTER_CONFIG_POSTPARSER("h1-headers-map", cfg_h1_headers_case_adjust_postparser);

View File

@ -79,21 +79,9 @@ struct h1s {
char ws_key[25]; /* websocket handshake key */
};
/* Map of headers used to convert outgoing headers */
struct h1_hdrs_map {
char *name;
struct eb_root map;
};
/* An entry in a headers map */
struct h1_hdr_entry {
struct ist name;
struct ebpt_node node;
};
/* Declare the headers map */
static struct h1_hdrs_map hdrs_map = { .name = NULL, .map = EB_ROOT };
static int accept_payload_with_any_method = 0;
struct h1_hdrs_map hdrs_map = { .name = NULL, .map = EB_ROOT };
int accept_payload_with_any_method = 0;
/* trace source and events */
static void h1_trace(enum trace_level level, uint64_t mask,
@ -5589,49 +5577,6 @@ static int h1_show_sd(struct buffer *msg, struct sedesc *sd, const char *pfx)
}
/* Add an entry in the headers map. Returns -1 on error and 0 on success. */
static int add_hdr_case_adjust(const char *from, const char *to, char **err)
{
struct h1_hdr_entry *entry;
/* Be sure there is a non-empty <to> */
if (!strlen(to)) {
memprintf(err, "expect <to>");
return -1;
}
/* Be sure only the case differs between <from> and <to> */
if (strcasecmp(from, to) != 0) {
memprintf(err, "<from> and <to> must not differ except the case");
return -1;
}
/* Be sure <from> does not already existsin the tree */
if (ebis_lookup(&hdrs_map.map, from)) {
memprintf(err, "duplicate entry '%s'", from);
return -1;
}
/* Create the entry and insert it in the tree */
entry = malloc(sizeof(*entry));
if (!entry) {
memprintf(err, "out of memory");
return -1;
}
entry->node.key = strdup(from);
entry->name = ist(strdup(to));
if (!entry->node.key || !isttest(entry->name)) {
free(entry->node.key);
istfree(&entry->name);
free(entry);
memprintf(err, "out of memory");
return -1;
}
ebis_insert(&hdrs_map.map, &entry->node);
return 0;
}
/* Migrate the the connection to the current thread.
* Return 0 if successful, non-zero otherwise.
* Expected to be called with the old thread lock held.
@ -5724,206 +5669,6 @@ static int h1_takeover(struct connection *conn, int orig_tid, int release)
return -1;
}
static void h1_hdeaders_case_adjust_deinit()
{
struct ebpt_node *node, *next;
struct h1_hdr_entry *entry;
node = ebpt_first(&hdrs_map.map);
while (node) {
next = ebpt_next(node);
ebpt_delete(node);
entry = container_of(node, struct h1_hdr_entry, node);
free(entry->node.key);
istfree(&entry->name);
free(entry);
node = next;
}
free(hdrs_map.name);
}
static int cfg_h1_headers_case_adjust_postparser()
{
FILE *file = NULL;
char *c, *key_beg, *key_end, *value_beg, *value_end;
char *err;
int rc, line = 0, err_code = 0;
if (!hdrs_map.name)
goto end;
file = fopen(hdrs_map.name, "r");
if (!file) {
ha_alert("h1-headers-case-adjust-file '%s': failed to open file.\n",
hdrs_map.name);
err_code |= ERR_ALERT | ERR_FATAL;
goto end;
}
/* now parse all lines. The file may contain only two header name per
* line, separated by spaces. All heading and trailing spaces will be
* ignored. Lines starting with a # are ignored.
*/
while (fgets(trash.area, trash.size, file) != NULL) {
line++;
c = trash.area;
/* strip leading spaces and tabs */
while (*c == ' ' || *c == '\t')
c++;
/* ignore emptu lines, or lines beginning with a dash */
if (*c == '#' || *c == '\0' || *c == '\r' || *c == '\n')
continue;
/* look for the end of the key */
key_beg = c;
while (*c != '\0' && *c != ' ' && *c != '\t' && *c != '\n' && *c != '\r')
c++;
key_end = c;
/* strip middle spaces and tabs */
while (*c == ' ' || *c == '\t')
c++;
/* look for the end of the value, it is the end of the line */
value_beg = c;
while (*c && *c != '\n' && *c != '\r')
c++;
value_end = c;
/* trim possibly trailing spaces and tabs */
while (value_end > value_beg && (value_end[-1] == ' ' || value_end[-1] == '\t'))
value_end--;
/* set final \0 and check entries */
*key_end = '\0';
*value_end = '\0';
err = NULL;
rc = add_hdr_case_adjust(key_beg, value_beg, &err);
if (rc < 0) {
ha_alert("h1-headers-case-adjust-file '%s' : %s at line %d.\n",
hdrs_map.name, err, line);
err_code |= ERR_ALERT | ERR_FATAL;
free(err);
goto end;
}
if (rc > 0) {
ha_warning("h1-headers-case-adjust-file '%s' : %s at line %d.\n",
hdrs_map.name, err, line);
err_code |= ERR_WARN;
free(err);
}
}
end:
if (file)
fclose(file);
hap_register_post_deinit(h1_hdeaders_case_adjust_deinit);
return err_code;
}
/* config parser for global "h1-accept-payload_=-with-any-method" */
static int cfg_parse_h1_accept_payload_with_any_method(char **args, int section_type, struct proxy *curpx,
const struct proxy *defpx, const char *file, int line,
char **err)
{
if (too_many_args(0, args, err, NULL))
return -1;
accept_payload_with_any_method = 1;
return 0;
}
/* config parser for global "h1-header-case-adjust" */
static int cfg_parse_h1_header_case_adjust(char **args, int section_type, struct proxy *curpx,
const struct proxy *defpx, const char *file, int line,
char **err)
{
if (too_many_args(2, args, err, NULL))
return -1;
if (!*(args[1]) || !*(args[2])) {
memprintf(err, "'%s' expects <from> and <to> as argument.", args[0]);
return -1;
}
return add_hdr_case_adjust(args[1], args[2], err);
}
/* config parser for global "h1-headers-case-adjust-file" */
static int cfg_parse_h1_headers_case_adjust_file(char **args, int section_type, struct proxy *curpx,
const struct proxy *defpx, const char *file, int line,
char **err)
{
if (too_many_args(1, args, err, NULL))
return -1;
if (!*(args[1])) {
memprintf(err, "'%s' expects <file> as argument.", args[0]);
return -1;
}
free(hdrs_map.name);
hdrs_map.name = strdup(args[1]);
if (!hdrs_map.name) {
memprintf(err, "'%s %s' : out of memory", args[0], args[1]);
return -1;
}
return 0;
}
/* config parser for global "tune.h1.zero-copy-fwd-recv" */
static int cfg_parse_h1_zero_copy_fwd_rcv(char **args, int section_type, struct proxy *curpx,
const struct proxy *defpx, const char *file, int line,
char **err)
{
if (too_many_args(1, args, err, NULL))
return -1;
if (strcmp(args[1], "on") == 0)
global.tune.no_zero_copy_fwd &= ~NO_ZERO_COPY_FWD_H1_RCV;
else if (strcmp(args[1], "off") == 0)
global.tune.no_zero_copy_fwd |= NO_ZERO_COPY_FWD_H1_RCV;
else {
memprintf(err, "'%s' expects 'on' or 'off'.", args[0]);
return -1;
}
return 0;
}
/* config parser for global "tune.h1.zero-copy-fwd-send" */
static int cfg_parse_h1_zero_copy_fwd_snd(char **args, int section_type, struct proxy *curpx,
const struct proxy *defpx, const char *file, int line,
char **err)
{
if (too_many_args(1, args, err, NULL))
return -1;
if (strcmp(args[1], "on") == 0)
global.tune.no_zero_copy_fwd &= ~NO_ZERO_COPY_FWD_H1_SND;
else if (strcmp(args[1], "off") == 0)
global.tune.no_zero_copy_fwd |= NO_ZERO_COPY_FWD_H1_SND;
else {
memprintf(err, "'%s' expects 'on' or 'off'.", args[0]);
return -1;
}
return 0;
}
/* config keyword parsers */
static struct cfg_kw_list cfg_kws = {{ }, {
{ CFG_GLOBAL, "h1-accept-payload-with-any-method", cfg_parse_h1_accept_payload_with_any_method },
{ CFG_GLOBAL, "h1-case-adjust", cfg_parse_h1_header_case_adjust },
{ CFG_GLOBAL, "h1-case-adjust-file", cfg_parse_h1_headers_case_adjust_file },
{ CFG_GLOBAL, "tune.h1.zero-copy-fwd-recv", cfg_parse_h1_zero_copy_fwd_rcv },
{ CFG_GLOBAL, "tune.h1.zero-copy-fwd-send", cfg_parse_h1_zero_copy_fwd_snd },
{ 0, NULL, NULL },
}
};
INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
REGISTER_CONFIG_POSTPARSER("h1-headers-map", cfg_h1_headers_case_adjust_postparser);
/****************************************/
/* MUX initialization and instantiation */
/****************************************/