From b59c7bfc95ecd0a75c4a35dcfb7fba1ac587e89c Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Tue, 22 Apr 2014 14:29:58 +0200 Subject: [PATCH] MEDIUM: http: headers must be forwarded even if data was already inspected Currently, we forward headers only if the incoming message is still before HTTP_MSG_CHUNK_SIZE, otherwise they'll be considered as data. In practice this is always true for the response since there's no data inspection, and for the request there is no compression so there's no problem with forwarding them as data. But the principle is incorrect and will make it difficult to later add data processing features. So better fix it now. The new principle is simple : - if headers were not yet forwarded, forward them now. - while doing so, check if we need to update the state --- src/proto_http.c | 59 +++++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/src/proto_http.c b/src/proto_http.c index 45ffd0013..8af97ac02 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -5027,20 +5027,26 @@ int http_request_forward_body(struct session *s, struct channel *req, int an_bit * an "Expect: 100-continue" header. */ - if (msg->msg_state < HTTP_MSG_CHUNK_SIZE) { - /* we have msg->sov which points to the first byte of message body. - * req->buf->p still points to the beginning of the message. We - * must save the body in msg->next because it survives buffer - * re-alignments. + if (msg->sov) { + /* we have msg->sov which points to the first byte of message + * body, and req->buf.p still points to the beginning of the + * message. We forward the headers now, as we don't need them + * anymore, and we want to flush them. */ - channel_forward(req, msg->sov); - msg->next = 0; - msg->sov = 0; + b_adv(req->buf, msg->sov); + msg->next -= msg->sov; + msg->sov = 0; - if (msg->flags & HTTP_MSGF_TE_CHNK) - msg->msg_state = HTTP_MSG_CHUNK_SIZE; - else - msg->msg_state = HTTP_MSG_DATA; + /* The previous analysers guarantee that the state is somewhere + * between MSG_BODY and the first MSG_DATA. So msg->sol and + * msg->next are always correct. + */ + if (msg->msg_state < HTTP_MSG_CHUNK_SIZE) { + if (msg->flags & HTTP_MSGF_TE_CHNK) + msg->msg_state = HTTP_MSG_CHUNK_SIZE; + else + msg->msg_state = HTTP_MSG_DATA; + } } /* Some post-connect processing might want us to refrain from starting to @@ -6184,19 +6190,26 @@ int http_response_forward_body(struct session *s, struct channel *res, int an_bi goto aborted_xfer; /* no memory */ } - if (msg->msg_state < HTTP_MSG_CHUNK_SIZE) { - /* we have msg->sov which points to the first byte of message body. - * res->buf.p still points to the beginning of the message. We - * forward the headers, we don't need them. + if (msg->sov) { + /* we have msg->sov which points to the first byte of message + * body, and res->buf.p still points to the beginning of the + * message. We forward the headers now, as we don't need them + * anymore, and we want to flush them. */ - channel_forward(res, msg->sov); - msg->next = 0; - msg->sov = 0; + b_adv(res->buf, msg->sov); + msg->next -= msg->sov; + msg->sov = 0; - if (msg->flags & HTTP_MSGF_TE_CHNK) - msg->msg_state = HTTP_MSG_CHUNK_SIZE; - else - msg->msg_state = HTTP_MSG_DATA; + /* The previous analysers guarantee that the state is somewhere + * between MSG_BODY and the first MSG_DATA. So msg->sol and + * msg->next are always correct. + */ + if (msg->msg_state < HTTP_MSG_CHUNK_SIZE) { + if (msg->flags & HTTP_MSGF_TE_CHNK) + msg->msg_state = HTTP_MSG_CHUNK_SIZE; + else + msg->msg_state = HTTP_MSG_DATA; + } } if (s->comp_algo != NULL) {