diff --git a/include/types/proto_http.h b/include/types/proto_http.h index 7313e25c7..c0350d245 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 432b27bb3..b10fc1034 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 a0b8d6355..3f86ce4de 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 02c7c02da..b3e19804d 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 359488bea..a77ab79bd 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;