From: Willy Tarreau Date: Thu, 2 Apr 2009 09:35:18 +0000 (+0200) Subject: [MEDIUM] http: add options to ignore invalid header names X-Git-Tag: v1.3.18~35 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=32a4ec0ed758c794ea1010f164658219cbf2e9ae;p=thirdparty%2Fhaproxy.git [MEDIUM] http: add options to ignore invalid header names Sometimes it is required to let invalid requests pass because applications sometimes take time to be fixed and other servers do not care. Thus we provide two new options : option accept-invalid-http-request (for the frontend) option accept-invalid-http-response (for the backend) When those options are set, invalid requests or responses do not cause a 403/502 error to be generated. --- diff --git a/include/types/proto_http.h b/include/types/proto_http.h index 7313e25c79..c0350d2458 100644 --- a/include/types/proto_http.h +++ b/include/types/proto_http.h @@ -231,6 +231,7 @@ struct http_msg { } st; /* status line : field, length */ } sl; /* start line */ unsigned long long hdr_content_len; /* cache for parsed header value */ + int err_pos; /* err handling: -2=block, -1=pass, 0+=detected */ }; /* This is an HTTP transaction. It contains both a request message and a diff --git a/include/types/proxy.h b/include/types/proxy.h index 432b27bb3e..b10fc10345 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -112,6 +112,8 @@ #define PR_O2_SPLIC_RTR 0x00000002 /* transfer responses using linux kernel's splice() */ #define PR_O2_SPLIC_AUT 0x00000004 /* automatically use linux kernel's splice() */ #define PR_O2_SPLIC_ANY (PR_O2_SPLIC_REQ|PR_O2_SPLIC_RTR|PR_O2_SPLIC_AUT) +#define PR_O2_REQBUG_OK 0x00000008 /* let buggy requests pass through */ +#define PR_O2_RSPBUG_OK 0x00000010 /* let buggy responses pass through */ /* This structure is used to apply fast weighted round robin on a server group */ struct fwrr_group { diff --git a/src/cfgparse.c b/src/cfgparse.c index a0b8d63554..3f86ce4def 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -123,6 +123,8 @@ static const struct cfg_opt cfg_opts2[] = { "splice-response", PR_O2_SPLIC_RTR, PR_CAP_FE|PR_CAP_BE, 0 }, { "splice-auto", PR_O2_SPLIC_AUT, PR_CAP_FE|PR_CAP_BE, 0 }, #endif + { "accept-invalid-http-request", PR_O2_REQBUG_OK, PR_CAP_FE, 0 }, + { "accept-invalid-http-response", PR_O2_RSPBUG_OK, PR_CAP_BE, 0 }, { NULL, 0, 0, 0 } }; diff --git a/src/client.c b/src/client.c index 02c7c02daa..b3e19804d5 100644 --- a/src/client.c +++ b/src/client.c @@ -266,6 +266,9 @@ int event_accept(int fd) { txn->rsp.msg_state = HTTP_MSG_RPBEFORE; /* at the very beginning of the response */ txn->req.sol = txn->req.eol = NULL; txn->req.som = txn->req.eoh = 0; /* relative to the buffer */ + txn->req.err_pos = txn->rsp.err_pos = -2; /* block buggy requests/responses */ + if (p->options2 & PR_O2_REQBUG_OK) + txn->req.err_pos = -1; /* let buggy requests pass */ txn->auth_hdr.len = -1; if (p->nb_req_cap > 0) { diff --git a/src/proto_http.c b/src/proto_http.c index 359488bea5..a77ab79bda 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -1375,7 +1375,14 @@ void http_msg_analyzer(struct buffer *buf, struct http_msg *msg, struct hdr_idx EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP); } - goto http_msg_invalid; + if (likely(msg->err_pos < -1) || *ptr == '\n') + goto http_msg_invalid; + + if (msg->err_pos == -1) /* capture error pointer */ + msg->err_pos = ptr - buf->data; /* >= 0 now */ + + /* and we still accept this non-token character */ + EAT_AND_JUMP_OR_RETURN(http_msg_hdr_name, HTTP_MSG_HDR_NAME); http_msg_hdr_l1_sp: case HTTP_MSG_HDR_L1_SP: @@ -2055,6 +2062,8 @@ int http_process_request(struct session *s, struct buffer *req) s->rep->rto = s->req->wto = s->be->timeout.server; s->req->cto = s->be->timeout.connect; s->conn_retries = s->be->conn_retries; + if (s->be->options2 & PR_O2_RSPBUG_OK) + s->txn.rsp.err_pos = -1; /* let buggy responses pass */ s->flags |= SN_BE_ASSIGNED; break; } @@ -2076,6 +2085,8 @@ int http_process_request(struct session *s, struct buffer *req) s->rep->rto = s->req->wto = s->be->timeout.server; s->req->cto = s->be->timeout.connect; s->conn_retries = s->be->conn_retries; + if (s->be->options2 & PR_O2_RSPBUG_OK) + s->txn.rsp.err_pos = -1; /* let buggy responses pass */ s->flags |= SN_BE_ASSIGNED; } } while (s->be != cur_proxy); /* we loop only if s->be has changed */ @@ -3054,6 +3065,8 @@ int apply_filter_to_req_headers(struct session *t, struct buffer *req, struct hd t->rep->rto = t->req->wto = t->be->timeout.server; t->req->cto = t->be->timeout.connect; t->conn_retries = t->be->conn_retries; + if (t->be->options2 & PR_O2_RSPBUG_OK) + t->txn.rsp.err_pos = -1; /* let buggy responses pass */ last_hdr = 1; break; @@ -3175,6 +3188,8 @@ int apply_filter_to_req_line(struct session *t, struct buffer *req, struct hdr_e t->rep->rto = t->req->wto = t->be->timeout.server; t->req->cto = t->be->timeout.connect; t->conn_retries = t->be->conn_retries; + if (t->be->options2 & PR_O2_RSPBUG_OK) + t->txn.rsp.err_pos = -1; /* let buggy responses pass */ done = 1; break;