[MINOR] http: capture incorrectly chunked message bodies

It is possible to block on incorrectly chunked requests or responses,
but this becomes very hard to debug when it happens once in a while.
This patch adds the ability to also capture incorrectly chunked requests
and responses. The chunk will appear in the error buffer and will be
verifiable with the usual "show errors". The incorrect byte will match
the error location.
This commit is contained in:
Willy Tarreau 2010-12-12 13:10:11 +01:00
parent 81f2fb97fe
commit e1582eb7f6

View File

@ -2085,13 +2085,13 @@ int http_parse_chunk_size(struct buffer *buf, struct http_msg *msg)
if (++ptr >= end)
ptr = buf->data;
if (chunk & 0xF000000) /* overflow will occur */
return -1;
goto error;
chunk = (chunk << 4) + c;
}
/* empty size not allowed */
if (ptr == buf->lr)
return -1;
goto error;
while (http_is_spht[(unsigned char)*ptr]) {
if (++ptr >= end)
@ -2114,7 +2114,7 @@ int http_parse_chunk_size(struct buffer *buf, struct http_msg *msg)
}
if (*ptr != '\n')
return -1;
goto error;
if (++ptr >= end)
ptr = buf->data;
/* done */
@ -2137,7 +2137,7 @@ int http_parse_chunk_size(struct buffer *buf, struct http_msg *msg)
continue;
}
else
return -1;
goto error;
}
/* OK we found our CRLF and now <ptr> points to the next byte,
@ -2149,6 +2149,9 @@ int http_parse_chunk_size(struct buffer *buf, struct http_msg *msg)
msg->hdr_content_len = chunk;
msg->msg_state = chunk ? HTTP_MSG_DATA : HTTP_MSG_TRAILERS;
return 1;
error:
msg->err_pos = ptr - buf->data;
return -1;
}
/* This function skips trailers in the buffer <buf> associated with HTTP
@ -2187,8 +2190,10 @@ int http_forward_trailers(struct buffer *buf, struct http_msg *msg)
}
if (*ptr == '\r') {
if (p1)
if (p1) {
msg->err_pos = ptr - buf->data;
return -1;
}
p1 = ptr;
}
@ -2255,8 +2260,10 @@ int http_skip_chunk_crlf(struct buffer *buf, struct http_msg *msg)
if (bytes > buf->l - buf->send_max)
return 0;
if (*ptr != '\n')
if (*ptr != '\n') {
msg->err_pos = ptr - buf->data;
return -1;
}
ptr++;
if (ptr >= buf->data + buf->size)
@ -4361,6 +4368,8 @@ int http_request_forward_body(struct session *s, struct buffer *req, int an_bit)
goto missing_data;
else if (ret < 0) {
session_inc_http_err_ctr(s);
if (msg->err_pos >= 0)
http_capture_bad_message(&s->fe->invalid_req, s, req, msg, HTTP_MSG_CHUNK_SIZE, s->be);
goto return_bad_req;
}
/* otherwise we're in HTTP_MSG_DATA or HTTP_MSG_TRAILERS state */
@ -4382,6 +4391,8 @@ int http_request_forward_body(struct session *s, struct buffer *req, int an_bit)
goto missing_data;
else if (ret < 0) {
session_inc_http_err_ctr(s);
if (msg->err_pos >= 0)
http_capture_bad_message(&s->fe->invalid_req, s, req, msg, HTTP_MSG_DATA_CRLF, s->be);
goto return_bad_req;
}
/* we're in MSG_CHUNK_SIZE now */
@ -4393,11 +4404,15 @@ int http_request_forward_body(struct session *s, struct buffer *req, int an_bit)
goto missing_data;
else if (ret < 0) {
session_inc_http_err_ctr(s);
if (msg->err_pos >= 0)
http_capture_bad_message(&s->fe->invalid_req, s, req, msg, HTTP_MSG_TRAILERS, s->be);
goto return_bad_req;
}
/* we're in HTTP_MSG_DONE now */
}
else {
int old_state = msg->msg_state;
/* other states, DONE...TUNNEL */
/* for keep-alive we don't want to forward closes on DONE */
if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL ||
@ -4417,6 +4432,8 @@ int http_request_forward_body(struct session *s, struct buffer *req, int an_bit)
if (!(s->flags & SN_FINST_MASK))
s->flags |= SN_FINST_D;
}
if (msg->err_pos >= 0)
http_capture_bad_message(&s->fe->invalid_req, s, req, msg, old_state, s->be);
goto return_bad_req;
}
return 1;
@ -5352,8 +5369,11 @@ int http_response_forward_body(struct session *s, struct buffer *res, int an_bit
if (!ret)
goto missing_data;
else if (ret < 0)
else if (ret < 0) {
if (msg->err_pos >= 0)
http_capture_bad_message(&s->be->invalid_rep, s, res, msg, HTTP_MSG_CHUNK_SIZE, s->fe);
goto return_bad_res;
}
/* otherwise we're in HTTP_MSG_DATA or HTTP_MSG_TRAILERS state */
/* Don't set a PUSH at the end of that chunk if it's not the last one */
if (msg->msg_state == HTTP_MSG_DATA)
@ -5371,8 +5391,11 @@ int http_response_forward_body(struct session *s, struct buffer *res, int an_bit
if (!ret)
goto missing_data;
else if (ret < 0)
else if (ret < 0) {
if (msg->err_pos >= 0)
http_capture_bad_message(&s->be->invalid_rep, s, res, msg, HTTP_MSG_DATA_CRLF, s->fe);
goto return_bad_res;
}
/* we're in MSG_CHUNK_SIZE now */
}
else if (msg->msg_state == HTTP_MSG_TRAILERS) {
@ -5380,11 +5403,16 @@ int http_response_forward_body(struct session *s, struct buffer *res, int an_bit
if (ret == 0)
goto missing_data;
else if (ret < 0)
else if (ret < 0) {
if (msg->err_pos >= 0)
http_capture_bad_message(&s->be->invalid_rep, s, res, msg, HTTP_MSG_TRAILERS, s->fe);
goto return_bad_res;
}
/* we're in HTTP_MSG_DONE now */
}
else {
int old_state = msg->msg_state;
/* other states, DONE...TUNNEL */
/* for keep-alive we don't want to forward closes on DONE */
if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL ||
@ -5405,6 +5433,8 @@ int http_response_forward_body(struct session *s, struct buffer *res, int an_bit
if (!(s->flags & SN_FINST_MASK))
s->flags |= SN_FINST_D;
}
if (msg->err_pos >= 0)
http_capture_bad_message(&s->be->invalid_rep, s, res, msg, old_state, s->fe);
goto return_bad_res;
}
return 1;