[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.
This commit is contained in:
Willy Tarreau 2009-04-02 11:35:18 +02:00
parent 61d188920e
commit 32a4ec0ed7
5 changed files with 24 additions and 1 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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 }
};

View File

@ -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) {

View File

@ -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;