diff --git a/doc/internals/body-parsing.txt b/doc/internals/body-parsing.txt index e9c8b4b6a6..5baa5492cc 100644 --- a/doc/internals/body-parsing.txt +++ b/doc/internals/body-parsing.txt @@ -67,12 +67,17 @@ msg.next : points to the next byte to inspect. This offset is automatically automatically adjusted to the number of bytes already inspected. msg.sov : start of value. First character of the header's value in the header - states, start of the body in the data states until headers are - forwarded. This offset is automatically adjusted when inserting or - removing some headers. In data states, it always constains the size - of the whole HTTP headers (including the trailing CRLF) that needs - to be forwarded before the first byte of body. Once the headers are - forwarded, this value drops to zero. + states, start of the body in the data states. Strictly positive + values indicate that headers were not forwarded yet ( is + before the start of the body), and null or positive values are seen + after headers are forwarded ( is at or past the start of the + body). The value stops changing when data start to leave the buffer + (in order to avoid integer overflows). So the maximum possible range + is - to +. This offset is automatically adjusted + when inserting or removing some headers. It is useful to rewind the + request buffer to the beginning of the body at any phase. The + response buffer does not really use it since it is immediately + forwarded to the client. msg.sol : start of line. Points to the beginning of the current header line while parsing headers. It is cleared to zero in the BODY state, @@ -97,7 +102,8 @@ msg.eol : end of line. Points to the CRLF or LF of the current header line states nor by forwarding. The beginning of the message headers can always be found this way even after -headers have been forwarded : +headers or data have been forwarded, provided that everything is still present +in the buffer : headers = buf.p + msg->sov - msg->eoh - msg->eol diff --git a/include/types/proto_http.h b/include/types/proto_http.h index 12e114171a..c53c7fdd4b 100644 --- a/include/types/proto_http.h +++ b/include/types/proto_http.h @@ -329,7 +329,8 @@ enum { * message or a response message. * * The values there are a little bit obscure, because their meaning can change - * during the parsing : + * during the parsing. Please read carefully doc/internal/body-parsing.txt if + * you need to manipulate them. Quick reminder : * * - eoh (End of Headers) : relative offset in the buffer of first byte that * is not part of a completely processed header. @@ -344,9 +345,9 @@ enum { * - sov (start of value) : Before HTTP_MSG_BODY, points to the value of * the header being parsed. Starting from * HTTP_MSG_BODY, will point to the start of the - * body (relative to buffer's origin), or to data - * following a chunk size. Thus bytes of - * headers will have to be sent only once. + * body (relative to buffer's origin). It can be + * negative when forwarding data. It stops growing + * once data start to leave the buffer. * * - next (parse pointer) : next relative byte to be parsed. Always points * to a byte matching the current state. @@ -372,7 +373,7 @@ struct http_msg { /* 6 bytes unused here */ struct channel *chn; /* pointer to the channel transporting the message */ unsigned int next; /* pointer to next byte to parse, relative to buf->p */ - unsigned int sov; /* current header: start of value */ + int sov; /* current header: start of value ; data: start of body */ unsigned int eoh; /* End Of Headers, relative to buffer */ unsigned int sol; /* start of current line during parsing otherwise zero */ unsigned int eol; /* end of line */ diff --git a/src/proto_http.c b/src/proto_http.c index 4a862b054c..94afed7488 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -5315,7 +5315,7 @@ int http_request_forward_body(struct session *s, struct channel *req, int an_bit * an "Expect: 100-continue" header. */ - if (msg->sov) { + if (msg->sov > 0) { /* 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 @@ -5429,6 +5429,8 @@ int http_request_forward_body(struct session *s, struct channel *req, int an_bit * such as last chunk of data or trailers. */ b_adv(req->buf, msg->next); + if (unlikely(!(s->rep->flags & CF_READ_ATTACHED))) + msg->sov -= msg->next; msg->next = 0; /* for keep-alive we don't want to forward closes on DONE */ @@ -5479,6 +5481,9 @@ int http_request_forward_body(struct session *s, struct channel *req, int an_bit missing_data: /* we may have some pending data starting at req->buf->p */ b_adv(req->buf, msg->next); + if (unlikely(!(s->rep->flags & CF_READ_ATTACHED))) + msg->sov -= msg->next + MIN(msg->chunk_len, req->buf->i); + msg->next = 0; msg->chunk_len -= channel_forward(req, msg->chunk_len); @@ -6493,7 +6498,7 @@ int http_response_forward_body(struct session *s, struct channel *res, int an_bi /* in most states, we should abort in case of early close */ channel_auto_close(res); - if (msg->sov) { + if (msg->sov > 0) { /* 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