You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

79 lines
4.0 KiB

  1. commit 9a408abbb8559df5718bc696bd9c3934c6500d63
  2. Author: Willy Tarreau <w@1wt.eu>
  3. Date: Fri Aug 23 08:11:36 2019 +0200
  4. BUG/MEDIUM: mux-h1: do not truncate trailing 0CRLF on buffer boundary
  5. The H1 message parser calls the various message block parsers with an
  6. offset indicating where in the buffer to start from, and only consumes
  7. the data at the end of the parsing. The headers and trailers parsers
  8. have a condition detecting if a headers or trailers block is too large
  9. to fit into the buffer. This is detected by an incomplete block while
  10. the buffer is full. Unfortunately it doesn't take into account the fact
  11. that the block may be parsed after other blocks that are still present
  12. in the buffer, resulting in aborting some transfers early as reported
  13. in issue #231. This typically happens if a trailers block is incomplete
  14. at the end of a buffer full of data, which typically happens with data
  15. sizes multiple of the buffer size minus less than the trailers block
  16. size. It also happens with the CRLF that follows the 0-sized chunk of
  17. any transfer-encoded contents is itself on such a boundary since this
  18. CRLF is technically part of the trailers block. This can be reproduced
  19. by asking a server to retrieve exactly 31532 or 31533 bytes of static
  20. data using chunked encoding with curl, which reports:
  21. transfer closed with outstanding read data remaining
  22. This issue was revealed in 2.0 and does not affect 1.9 because in 1.9
  23. the trailers block was processed at once as part of the data block
  24. processing, and would simply give up and wait for the rest of the data
  25. to arrive.
  26. It's interesting to note that the headers block parsing is also affected
  27. by this issue but in practice it has a much more limited impact since a
  28. headers block is normally only parsed at the beginning of a buffer. The
  29. only case where it seems to matter is when dealing with a response buffer
  30. full of 100-continue header blocks followed by a regular header block,
  31. which will then be rejected for the same reason.
  32. This fix must be backported to 2.0 and partially to 1.9 (the headers
  33. block part).
  34. (cherry picked from commit 347f464d4e5a8a2bf3acd2411a6c8228e605e7f6)
  35. Signed-off-by: Willy Tarreau <w@1wt.eu>
  36. diff --git a/src/mux_h1.c b/src/mux_h1.c
  37. index fa694c41..01f225a2 100644
  38. --- a/src/mux_h1.c
  39. +++ b/src/mux_h1.c
  40. @@ -995,10 +995,11 @@ static size_t h1_process_headers(struct h1s *h1s, struct h1m *h1m, struct htx *h
  41. ret = h1_headers_to_hdr_list(b_peek(buf, *ofs), b_tail(buf),
  42. hdrs, sizeof(hdrs)/sizeof(hdrs[0]), h1m, &h1sl);
  43. if (ret <= 0) {
  44. - /* Incomplete or invalid message. If the buffer is full, it's an
  45. - * error because headers are too large to be handled by the
  46. - * parser. */
  47. - if (ret < 0 || (!ret && !buf_room_for_htx_data(buf)))
  48. + /* Incomplete or invalid message. If the input buffer only
  49. + * contains headers and is full, which is detected by it being
  50. + * full and the offset to be zero, it's an error because
  51. + * headers are too large to be handled by the parser. */
  52. + if (ret < 0 || (!ret && !*ofs && !buf_room_for_htx_data(buf)))
  53. goto error;
  54. goto end;
  55. }
  56. @@ -1339,10 +1340,11 @@ static size_t h1_process_trailers(struct h1s *h1s, struct h1m *h1m, struct htx *
  57. ret = h1_headers_to_hdr_list(b_peek(buf, *ofs), b_tail(buf),
  58. hdrs, sizeof(hdrs)/sizeof(hdrs[0]), &tlr_h1m, NULL);
  59. if (ret <= 0) {
  60. - /* Incomplete or invalid trailers. If the buffer is full, it's
  61. - * an error because traliers are too large to be handled by the
  62. - * parser. */
  63. - if (ret < 0 || (!ret && !buf_room_for_htx_data(buf)))
  64. + /* Incomplete or invalid trailers. If the input buffer only
  65. + * contains trailers and is full, which is detected by it being
  66. + * full and the offset to be zero, it's an error because
  67. + * trailers are too large to be handled by the parser. */
  68. + if (ret < 0 || (!ret && !*ofs && !buf_room_for_htx_data(buf)))
  69. goto error;
  70. goto end;
  71. }