7 Commits

Author SHA1 Message Date
Willy Tarreau
2510f702f9 MINOR: h1: add a function to measure the trailers length
This is needed in the H2->H1 gateway so that we know how long the trailers
block is in chunked encoding. It returns the number of bytes, or 0 if some
are missing, or -1 in case of parse error.
2017-10-31 17:18:10 +01:00
Willy Tarreau
d22e83abd9 MINOR: h1: store the status code in the H1 message
It was painful not to have the status code available, especially when
it was computed. Let's store it and ensure we don't claim content-length
anymore on 1xx, only 0 body bytes.
2017-10-31 08:43:29 +01:00
Willy Tarreau
8ea0f38c75 MEDIUM: h1: ensure that 1xx, 204 and 304 don't have a payload body
It's important for the H2 to H1 gateway that the response parser properly
clears the H1 message's body_len when seeing these status codes so that we
don't hang waiting to transfer data that will not come.
2017-10-30 19:33:22 +01:00
Willy Tarreau
794f9af894 MEDIUM: h1: reimplement the http/1 response parser for the gateway
The HTTP/2->HTTP/1 gateway will need to process HTTP/1 responses. We
cannot sanely rely on the HTTP/1 txn to parse a response because :

  1) responses generated by haproxy such as error messages, redirects,
     stats or Lua are neither parsed nor indexed ; this could be
     addressed over the long term but will take time.

  2) the http txn is useless to parse the body : the states present there
     are only meaningful to received bytes (ie next bytes to parse) and
     not at all to sent bytes. Thus chunks cannot be followed at all.
     Even when implementing this later, it's unsure whether it will be
     possible when dealing with compression.

So using the HTTP txn is now out of the equation and the only remaining
solution is to call an HTTP/1 message parser. We already have one, it was
slightly modified to avoid keeping states by benefitting from the fact
that the response was produced by haproxy and this is entirely available.
It assumes the following rules are true, or that incuring an extra cost
to work around them is acceptable :
  - the response buffer is read-write and supports modifications in place

  - headers sent through / by haproxy are not folded. Folding is still
    implemented by replacing CR/LF/tabs/spaces with spaces if encountered

  - HTTP/0.9 responses are never sent by haproxy and have never been
    supported at all

  - haproxy will not send partial responses, the whole headers block will
    be sent at once ; this means that we don't need to keep expensive
    states and can afford to restart the parsing from the beginning when
    facing a partial response ;

  - response is contiguous (does not wrap). This was already the case
    with the original parser and ensures we can safely dereference all
    fields with (ptr,len)

The parser replaces all of the http_msg fields that were necessary with
local variables. The parser is not called on an http_msg but on a string
with a start and an end. The HTTP/1 states were reused for ease of use,
though the request-specific ones have not been implemented for now. The
error position and error state are supported and optional ; these ones
may be used later for bug hunting.

The parser issues the list of all the headers into a caller-allocated
array of struct ist.

The content-length/transfer-encoding header are checked and the relevant
info fed the h1 message state (flags + body_len).
2017-10-22 09:54:15 +02:00
Willy Tarreau
8740c8b1b2 REORG: http: move the HTTP/1 header block parser to h1.c
Since it still depends on http_msg, it was not renamed yet.
2017-10-22 09:54:13 +02:00
Willy Tarreau
db4893d6a4 REORG: http: move the HTTP/1 chunk parser to h1.{c,h}
Functions http_parse_chunk_size(), http_skip_chunk_crlf() and
http_forward_trailers() were moved to h1.h and h1.c respectively so
that they can be called from outside. The parts that were inline
remained inline as it's critical for performance (+41% perf
difference reported in an earlier test). For now the "http_" prefix
remains in their name since they still depend on the http_msg type.
2017-10-22 09:54:13 +02:00
Willy Tarreau
0da5b3bddc REORG: http: move some very http1-specific parts to h1.{c,h}
Certain types and enums are very specific to the HTTP/1 parser, and we'll
need to share them with the HTTP/2 to HTTP/1 translation code. Let's move
them to h1.c/h1.h. Those with very few occurrences or only used locally
were renamed to explicitly mention the relevant HTTP version :

  enum ht_state      -> h1_state.
  http_msg_state_str -> h1_msg_state_str
  HTTP_FLG_*         -> H1_FLG_*
  http_char_classes  -> h1_char_classes

Others like HTTP_IS_*, HTTP_MSG_* are left to be done later.
2017-10-22 09:54:13 +02:00