From ac1932da3ec4614f60f3ce22518a9a0a61a11c67 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 24 Oct 2011 19:14:41 +0200 Subject: MEDIUM: tune.http.maxhdr makes it possible to configure the maximum number of HTTP headers For a long time, the max number of headers was taken as a part of the buffer size. Since the header size can be configured at runtime, it does not make much sense anymore. Nothing was making it necessary to have a static value, so let's turn this into a tunable with a default value of 101 which equals what was previously used. --- doc/configuration.txt | 12 ++++++++++++ include/common/defaults.h | 4 ++-- include/types/global.h | 1 + include/types/proto_http.h | 2 +- src/cfgparse.c | 13 ++++++++++++- src/frontend.c | 2 +- src/proxy.c | 2 +- 7 files changed, 30 insertions(+), 6 deletions(-) diff --git a/doc/configuration.txt b/doc/configuration.txt index 5cce3b4..afe1bfc 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -458,6 +458,7 @@ The following keywords are supported in the "global" section : - spread-checks - tune.bufsize - tune.chksize + - tune.http.maxhdr - tune.maxaccept - tune.maxpollevents - tune.maxrewrite @@ -725,6 +726,17 @@ tune.chksize build time. It is not recommended to change this value, but to use better checks whenever possible. +tune.http.maxhdr + Sets the maximum number of headers in a request. When a request comes with a + number of headers greater than this value (including the first line), it is + rejected with a "400 Bad Request" status code. Similarly, too large responses + are blocked with "502 Bad Gateway". The default value is 101, which is enough + for all usages, considering that the widely deployed Apache server uses the + same limit. It can be useful to push this limit further to temporarily allow + a buggy application to work by the time it gets fixed. Keep in mind that each + new header consumes 32bits of memory for each session, so don't push this + limit too high. + tune.maxaccept Sets the maximum number of consecutive accepts that a process may perform on a single wake up. High values give higher priority to high connection rates, diff --git a/include/common/defaults.h b/include/common/defaults.h index 0a4f420..8647131 100644 --- a/include/common/defaults.h +++ b/include/common/defaults.h @@ -58,9 +58,9 @@ #define MAX_MATCH 10 // max # of headers in one HTTP request or response -// By default, about 100 headers per 8 kB. +// By default, about 100 headers (+1 for the first line) #ifndef MAX_HTTP_HDR -#define MAX_HTTP_HDR ((BUFSIZE+79)/80) +#define MAX_HTTP_HDR 101 #endif // max # of headers in history when looking for header #-X diff --git a/include/types/global.h b/include/types/global.h index 078a1d5..56110e8 100644 --- a/include/types/global.h +++ b/include/types/global.h @@ -97,6 +97,7 @@ struct global { int server_rcvbuf; /* set server rcvbuf to this value if not null */ int chksize; /* check buffer size in bytes, defaults to BUFSIZE */ int pipesize; /* pipe size in bytes, system defaults if zero */ + int max_http_hdr; /* max number of HTTP headers, use MAX_HTTP_HDR if zero */ } tune; struct { char *prefix; /* path prefix of unix bind socket */ diff --git a/include/types/proto_http.h b/include/types/proto_http.h index d9bf830..f1b3eef 100644 --- a/include/types/proto_http.h +++ b/include/types/proto_http.h @@ -322,7 +322,7 @@ struct http_req_rule { */ struct http_txn { struct http_msg req; /* HTTP request message */ - struct hdr_idx hdr_idx; /* array of header indexes (max: MAX_HTTP_HDR) */ + struct hdr_idx hdr_idx; /* array of header indexes (max: global.tune.max_http_hdr) */ unsigned int flags; /* transaction flags */ http_meth_t meth; /* HTTP method */ diff --git a/src/cfgparse.c b/src/cfgparse.c index dac6bca..5ddfbe2 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -596,6 +596,14 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) } global.tune.pipesize = atol(args[1]); } + else if (!strcmp(args[0], "tune.http.maxhdr")) { + if (*(args[1]) == 0) { + Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + global.tune.max_http_hdr = atol(args[1]); + } else if (!strcmp(args[0], "uid")) { if (global.uid != 0) { Alert("parsing [%s:%d] : user/uid already specified. Continuing.\n", file, linenum); @@ -6595,8 +6603,11 @@ out_uri_auth_compat: } } + if (!global.tune.max_http_hdr) + global.tune.max_http_hdr = MAX_HTTP_HDR; + pool2_hdr_idx = create_pool("hdr_idx", - MAX_HTTP_HDR * sizeof(struct hdr_idx_elem), + global.tune.max_http_hdr * sizeof(struct hdr_idx_elem), MEM_F_SHARED); if (cfgerr > 0) diff --git a/src/frontend.c b/src/frontend.c index 195a424..19980c0 100644 --- a/src/frontend.c +++ b/src/frontend.c @@ -134,7 +134,7 @@ int frontend_accept(struct session *s) * that we may make use of them. This of course includes * (mode == PR_MODE_HTTP). */ - s->txn.hdr_idx.size = MAX_HTTP_HDR; + s->txn.hdr_idx.size = global.tune.max_http_hdr; if (unlikely((s->txn.hdr_idx.v = pool_alloc2(pool2_hdr_idx)) == NULL)) goto out_free_rspcap; /* no memory */ diff --git a/src/proxy.c b/src/proxy.c index d274dfe..caec45d 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -819,7 +819,7 @@ int session_set_backend(struct session *s, struct proxy *be) /* and now initialize the HTTP transaction state */ http_init_txn(s); - s->txn.hdr_idx.size = MAX_HTTP_HDR; + s->txn.hdr_idx.size = global.tune.max_http_hdr; hdr_idx_init(&s->txn.hdr_idx); } -- 1.7.2.3