725 Commits

Author SHA1 Message Date
Christopher Faulet
35757d38ce MINOR: mux-h2: Set REFUSED_STREAM error to reset a stream if no data was never sent
According to the H2 spec (see #8.1.4), setting the REFUSED_STREAM error code
is a way to indicate that the stream is being closed prior to any processing
having occurred, such as when a server-side H1 keepalive connection is closed
without sending anything (which differs from the regular error case since
haproxy doesn't even generate an error message). Any request that was sent on
the reset stream can be safely retried. So, when a stream is closed, if no
data was ever sent back (ie. the flag H2_SF_HEADERS_SENT is not set), we can
set the REFUSED_STREAM error code on the RST_STREAM frame.

This patch may be backported to 1.9.
2019-03-18 15:50:23 +01:00
Christopher Faulet
f02ca00a36 BUG/MEDIUM: mux-h2: Always wakeup streams with no id to avoid frozen streams
This only happens for server streams because their id is assigned when the first
message is sent. If these streams are not woken up, some events can be lost
leading to frozen streams. For instance, it happens when a server closes its
connection before sending its preface.

This patch must be backported to 1.9.
2019-03-18 15:50:23 +01:00
Willy Tarreau
7196dd6071 MINOR: mux-h2: always pass HTX_FL_PARSING_ERROR between h2s and buf on RX
In order to allow the H2 parser to report parsing errors, we must make
sure to always pass the HTX_FL_PARSING_ERROR flag from the h2s htx to
the conn_stream's htx.
2019-03-05 10:56:34 +01:00
Willy Tarreau
927b88ba00 BUG/MAJOR: mux-h2: fix race condition between close on both ends
A crash in H2 was reported in issue #52. It turns out that there is a
small but existing race by which a conn_stream could detach itself
using h2_detach(), not being able to destroy the h2s due to pending
output data blocked by flow control, then upon next h2s activity
(transfer_data or trailers parsing), an ES flag may need to be turned
into a CS_FL_REOS bit, causing a dereference of a NULL stream. This is
a side effect of the fact that we still have a few places which
incorrectly depend on the CS flags, while these flags should only be
set by h2_rcv_buf() and h2_snd_buf().

All candidate locations along this path have been secured against this
risk, but the code should really evolve to stop depending on CS anymore.

This fix must be backported to 1.9 and possibly partially to 1.8.
2019-03-04 08:17:12 +01:00
Willy Tarreau
0bbad6bb06 BUG/MEDIUM: h2: advertise to servers that we don't support push
The h2c_send_settings() function was initially made to serve on the
frontend. Here we don't need to advertise that we don't support PUSH
since we don't do that ourselves. But on the backend side it's
different because PUSH is enabled by default so we must announce that
we don't want the server to use it.

This must be backported to 1.9.
2019-02-26 16:07:27 +01:00
Willy Tarreau
67b8caefc9 BUG/MEDIUM: mux-h2/htx: send an empty DATA frame on empty HTX trailers
When chunked-encoding is used in HTX mode, a trailers HTX block is always
made due to the way trailers are currently implemented (verbatim copy of
the H1 representation). Because of this it's not possible to know when
processing data that we've reached the end of the stream, and it's up
to the function encoding the trailers (h2s_htx_make_trailers) to put the
end of stream. But when there are no trailers and only an empty HTX block,
this one cannot produce a HEADERS frame, thus it cannot send the END_STREAM
flag either, leaving the other end with an incomplete message, waiting for
either more data or some trailers. This is particularly visible with POST
requests where the server continues to wait.

What this patch does is transform the HEADERS frame into an empty DATA
frame when meeting an empty trailers block. It is possible to do this
because we've not sent any trailers so the other end is still waiting
for DATA frames. The check is made after attempting to encode the list
of headers, so as to minimize the specific code paths.

Thanks to Dragan Dosen for reporting the issue with a reproducer.

This fix must be backported to 1.9.
2019-02-21 18:22:26 +01:00
Willy Tarreau
a24b35ca18 MINOR: mux-h2: make the H2 MAX_FRAME_SIZE setting configurable
This creates a new tunable "tune.h2.max-frame-size" to adjust the
advertised max frame size. When not set it still defaults to the buffer
size. It is convenient to advertise sizes lower than the buffer size,
for example when using very large buffers.
2019-02-21 17:30:59 +01:00
Christopher Faulet
eaf0d2a936 MINOR: mux-h2: Set HTX extra value when possible
For now, this can be only done when a content-length is specified. In fact, it
is the same value than h2s->body_len, the remaining body length according to
content-length. Setting this field allows the fast forwarding at the channel
layer, improving significantly data transfer for big objects.

This patch may be backported to 1.9.
2019-02-19 16:26:14 +01:00
Christopher Faulet
0b46548a68 BUG/MEDIUM: h2/htx: Correctly handle interim responses when HTX is enabled
1xx responses does not work in HTTP2 when the HTX is enabled. First of all, when
a response is parsed, only one HEADERS frame is expected. So when an interim
response is received, the flag H2_SF_HEADERS_RCVD is set and the next HEADERS
frame (for another interim repsonse or the final one) is parsed as a trailers
one. Then when the response is sent, because an EOM block is found at the end of
the interim HTX response, the ES flag is added on the frame, closing too early
the stream. Here, it is a design problem of the HTX. Iterim responses are
considered as full messages, leading to some ambiguities when HTX messages are
processed. This will not be fixed now, but we need to keep it in mind for future
improvements.

To fix the parsing bug, the flag H2_MSGF_RSP_1XX is added when the response
headers are decoded. When this flag is set, an EOM block is added into the HTX
message, despite the fact that there is no ES flag on the frame. And we don't
set the flag H2_SF_HEADERS_RCVD on the corresponding H2S. So the next HEADERS
frame will not be parsed as a trailers one.

To fix the sending bug, the ES flag is not set on the frame when an interim
response is processed and the flag H2_SF_HEADERS_SENT is not set on the
corresponding H2S.

This patch must be backported to 1.9.
2019-02-19 16:26:14 +01:00
Christopher Faulet
fd74267264 BUG/MINOR: mux-h2: Don't add ":status" pseudo-header on trailers
It is a cut-paste bug. Pseudo-header fields MUST NOT appear in trailers.

This patch must be backported to 1.9.
2019-02-18 16:25:06 +01:00
Christopher Faulet
37070b2b15 BUG/MEDIUM: mux-h2/htx: Always set CS flags before exiting h2_rcv_buf()
It is especially important when some data are blocked in the RX buf and the
channel buffer is already full. In such case, instead of exiting the function
directly, we need to set right flags on the conn_stream. CS_FL_RCV_MORE and
CS_FL_WANT_ROOM must be set, otherwise, the stream-interface will subscribe to
receive events, thinking it is not blocked.

This bug leads to connection freeze when everything was received with some data
blocked in the RX buf and a channel full.

This patch must be backported to 1.9.
2019-02-18 16:25:06 +01:00
Willy Tarreau
053c15750b BUG/MEDIUM: mux-h2: always set :authority on request output
PiBa-NL reported that some servers don't fall back to the Host header when
:authority is absent. After studying all the combinations of Host and
:authority, it appears that we always have to send the latter, hence we
never need the former. In case of CONNECT method, the authority is retrieved
from the URI part, otherwise it's extracted from the Host field.

The tricky part is that we have to scan all headers for the Host header
before dumping other headers. This is due to the fact that we must emit
pseudo headers before other ones. One improvement could possibly be made
later in the request parser to search and emit the Host header immediately
if authority was not found. This would cost nothing on the vast marjority
of requests and make the lookup faster on output since Host would appear
first.

This fix must be backported to 1.9.
2019-02-01 16:47:46 +01:00
Willy Tarreau
5be92ff23f BUG/MEDIUM: mux-h2: always omit :scheme and :path for the CONNECT method
This is mandated by RFC7540 #8.3, these pseudo-headers must not be emitted
with the CONNECT method.

This must be backported to 1.9.
2019-02-01 16:47:46 +01:00
Olivier Houchard
9c9da5ee89 MINOR: muxes: Don't bother to LIST_DEL(&conn->list) before calling conn_free().
conn_free() already removes the connection from any idle list, so there's no
need to do it in the mux code, just before calling conn_free().
2019-01-31 19:38:25 +01:00
Willy Tarreau
8694978892 BUG/MEDIUM: mux-h2: properly consider the peer's advertised max-concurrent-streams
Till now we used to only rely on tune.h2.max-concurrent-streams but if
a peer advertises a lower limit this can cause streams to be reset or
even the conection to be killed. Let's respect the peer's value for
outgoing streams.

This patch should be backported to 1.9, though it depends on the following
ones :
    BUG/MINOR: server: fix logic flaw in idle connection list management
    MINOR: mux-h2: max-concurrent-streams should be unsigned
    MINOR: mux-h2: make sure to only check concurrency limit on the frontend
    MINOR: mux-h2: learn and store the peer's advertised MAX_CONCURRENT_STREAMS setting
2019-01-31 19:38:25 +01:00
Willy Tarreau
2e2083ae5b MINOR: mux-h2: learn and store the peer's advertised MAX_CONCURRENT_STREAMS setting
We used not to take it into account because we only used the configured
parameter everywhere. This patch makes sure we can actually learn the
value advertised by the peer. We still enforce our own limit on top of
it however, to make sure we can actually limit resources or stream
concurrency in case of suboptimal server settings.
2019-01-31 19:38:25 +01:00
Willy Tarreau
fa1d357f05 MINOR: mux-h2: make sure to only check concurrency limit on the frontend
h2_has_too_many_cs() was renamed to h2_frt_has_too_many_cs() to make it
clear it's only used to throttle the frontend connection, and the call
places were adjusted to only call this code on a front connection. In
practice it was already the case since the H2_CF_DEM_TOOMANY flag is
only set there. But now the ambiguity is removed.
2019-01-31 19:38:25 +01:00
Willy Tarreau
5a490b669e MINOR: mux-h2: max-concurrent-streams should be unsigned
We compare it to other unsigned values, let's make it unsigned as well.
2019-01-31 19:38:25 +01:00
Willy Tarreau
00f18a36b6 BUG/MINOR: server: fix logic flaw in idle connection list management
With variable connection limits, it's not possible to accurately determine
whether the mux is still in use by comparing usage and max to be equal due
to the fact that one determines the capacity and the other one takes care
of the context. This can cause some connections to be dropped before they
reach their stream ID limit.

It seems it could also cause some connections to be terminated with
streams still alive if the limit was reduced to match the newly computed
avail_streams() value, though this cannot yet happen with existing muxes.

Instead let's switch to usage reports and simply check whether connections
are both unused and available before adding them to the idle list.

This should be backported to 1.9.
2019-01-31 19:38:25 +01:00
Willy Tarreau
180590409f BUG/MEDIUM: mux-h2: do not close the connection on aborted streams
We used to rely on a hint that a shutw() or shutr() without data is an
indication that the upper layer had performed a tcp-request content reject
and really wanted to kill the connection, but sadly there is another
situation where this happens, which is failed keep-alive request to a
server. In this case the upper layer stream silently closes to let the
client retry. In our case this had the side effect of killing all the
connection.

Instead of relying on such hints, let's address the problem differently
and rely on information passed by the upper layers about the intent to
kill the connection. During shutr/shutw, this is detected because the
flag CS_FL_KILL_CONN is set on the connstream. Then only in this case
we send a GOAWAY(ENHANCE_YOUR_CALM), otherwise we only send the reset.

This makes sure that failed backend requests only fail frontend requests
and not the whole connections anymore.

This fix relies on the two previous patches adding SI_FL_KILL_CONN and
CS_FL_KILL_CONN as well as the fix for the connection close, and it must
be backported to 1.9 and 1.8, though the code in 1.8 could slightly differ
(cs is always valid) :

  BUG/MEDIUM: mux-h2: wait for the mux buffer to be empty before closing the connection
  MINOR: stream-int: add a new flag to mention that we want the connection to be killed
  MINOR: connstream: have a new flag CS_FL_KILL_CONN to kill a connection
2019-01-31 19:38:25 +01:00
Willy Tarreau
4dbda620f2 BUG/MEDIUM: mux-h2: wait for the mux buffer to be empty before closing the connection
When finishing to respond on a stream, a shutw() is called (resulting
in either an end of stream or RST), then h2_detach() is called, and may
decide to kill the connection is a number of conditions are satisfied.
Actually one of these conditions is that a GOAWAY frame was already sent
or attempted to be sent. This one is wrong, because it can happen in at
least these two situations :
  - a shutw() sends a GOAWAY to obey tcp-request content reject
  - a graceful shutdown is pending

In both cases, the connection will be aborted with the mux buffer holding
some data. In case of a strong abort the client will not see the GOAWAY or
RST and might want to try again, which is counter-productive. In case of
the graceful shutdown, it could result in truncated data. It looks like a
valid candidate for the issue reported here :

    https://www.mail-archive.com/haproxy@formilux.org/msg32433.html

A backport to 1.9 and 1.8 is necessary.
2019-01-31 19:38:25 +01:00
Willy Tarreau
a9b7796862 MINOR: mux-h2: consistently rely on the htx variable to detect the mode
In h2_frt_transfer_data(), we support both HTX and legacy modes. The
HTX mode is detected from the proxy option and sets a valid pointer
into the htx variable. Better rely on this variable in all the function
rather than testing the option again. This way the code is clearer and
even the compiler knows this pointer is valid when it's dereferenced.

This should be backported to 1.9 if the b_is_null() patch is backported.
2019-01-31 08:07:17 +01:00
Willy Tarreau
1f035507af BUG/MINOR: mux-h2: make sure request trailers on aborted streams don't break the connection
We used to respond a connection error in case we received a trailers
frame on a closed stream, but it's a problem to do this if the error
was caused by a reset because the sender has not yet received it and
is just a victim of the timing. Thus we must not close the connection
in this case.

This patch may be backported to 1.9 but then it requires the following
previous ones :
   MINOR: h2: add a generic frame checker
   MEDIUM: mux-h2: check the frame validity before considering the stream state
   CLEANUP: mux-h2: remove stream ID and frame length checks from the frame parsers
2019-01-30 19:37:20 +01:00
Willy Tarreau
b860c73756 CLEANUP: mux-h2: remove stream ID and frame length checks from the frame parsers
It's not convenient to have such structural checks mixed with the ones
related to the stream state. Let's remove all these basic tests that are
already covered once for all when reading the frame header.
2019-01-30 19:37:20 +01:00
Willy Tarreau
54f46e53dd MEDIUM: mux-h2: check the frame validity before considering the stream state
There are some uneasy situation where it's difficult to validate a frame's
format without being in an appropriate state. This patch makes sure that
each frame passes through h2_frame_check() before being checked in the
context of the stream's state. This makes sure we can always return a GOAWAY
for protocol violations even if we can't process the frame.
2019-01-30 19:37:20 +01:00
Willy Tarreau
08bb1d6109 BUG/MINOR: mux-h2: make sure response HEADERS are not received in other states than OPEN and HLOC
RFC7540#5.1 states that these are the only states allowing any frame
type. For response HEADERS frames, we cannot accept that they are
delivered on idle streams of course, so we're left with these two
states only. It is important to test this so that we can remove the
generic CLOSE_STREAM test for such frames in the main loop.

This must be backported to 1.9 (1.8 doesn't have response HEADERS).
2019-01-30 19:37:14 +01:00
Willy Tarreau
8d9ac3ed8b BUG/MEDIUM: mux-h2: do not abort HEADERS frame before decoding them
If a response HEADERS frame arrives on a closed connection (due to a
client abort sending an RST_STREAM), it's currently immediately rejected
with an RST_STREAM, like any other frame. This is incorrect, as HEADERS
frames must first be decoded to keep the HPACK decoder synchronized,
possibly breaking subsequent responses.

This patch excludes HEADERS/CONTINUATION/PUSH_PROMISE frames from the
central closed state test and leaves to the respective frame parsers
the responsibility to decode the frame then send RST_STREAM.

This fix must be backported to 1.9. 1.8 is not directly impacted since
it doesn't have response HEADERS nor trailers thus cannot recover from
such situations anyway.
2019-01-30 19:36:21 +01:00
Willy Tarreau
24ff1f8341 BUG/MEDIUM: mux-h2: make sure never to send GOAWAY on too old streams
The H2 spec requires to send GOAWAY when the client sends a frame after
it has already closed using END_STREAM. Here the corresponding case was
the fallback of a series of tests on the stream state, but it unfortunately
also catches old closed streams which we don't know anymore. Thus any late
packet after we've sent an RST_STREAM will trigger this GOAWAY and break
other streams on the connection.

This can happen when launching two tabs in a browser targetting the same
slow page through an H2-to-H2 proxy, and pressing Escape to stop one of
them. The other one gets an error when the page finally responds (and it
generally retries), and the logs in the middle indicate SD-- flags since
the late response was cancelled.

This patch takes care to only send GOAWAY on streams we still know.

It must be backported to 1.9 and 1.8.
2019-01-30 19:35:42 +01:00
Willy Tarreau
fc10f599cc BUG/MEDIUM: mux-h2: fix two half-closed to closed transitions
When receiving a HEADERS or DATA frame with END_STREAM set, we would
inconditionally switch to half-closed(remote). This is wrong because we
could already have been in half-closed(local) and need to switch to closed.
This happens in the following situations :
    - receipt of the end of a client upload after we've already responded
      (e.g. redirects to POST requests)
    - receipt of a response on the backend side after we've already finished
      sending the request (most common case).

This may possibly have caused some streams to stay longer than needed
at the end of a transfer, though this is not apparent in tests.

This must be backported to 1.9 and 1.8.
2019-01-30 19:34:40 +01:00
Willy Tarreau
b1c9edc579 BUG/MEDIUM: mux-h2: wake up flow-controlled streams on initial window update
When a settings frame updates the initial window, all affected streams's
window is updated as well. However the streams are not put back into the
send list if they were already blocked on flow control. The effect is that
such a stream will only be woken up by a WINDOW_UPDATE message but not by
a SETTINGS changing the initial window size. This can be verified with
h2spec's test http2/6.9.2/1 which occasionally fails without this patch.

It is unclear whether this situation is really met in field, but the
fix is trivial, it consists in adding each unblocked streams to the
wait list as is done for the window updates.

This fix must be backported to 1.9. For 1.8 the patch needs quite
a few adaptations. It's better to copy-paste the code block from
h2c_handle_window_update() adding the stream to the send_list when
its mws is > 0.
2019-01-30 16:21:39 +01:00
Willy Tarreau
6432dc8783 CLEANUP: mux-h2: remove misleading leftover test on h2s' nullity
The WINDOW_UPDATE and DATA frame handlers used to still have a check on
h2s to return either h2s_error() or h2c_error(). This is a leftover from
the early code. The h2s cannot be null there anymore as it has already
been dereferenced before reaching these locations.
2019-01-30 15:45:02 +01:00
Olivier Houchard
2b09443e04 BUG/MEDIUM: h2: In h2_send(), stop the loop if we failed to alloc a buf.
In h2_send(), make sure we break the loop if we failed to alloc a buffer,
or we'd end up looping endlessly.

This should be backported to 1.9.
2019-01-29 19:47:20 +01:00
Willy Tarreau
f1e6fa35de CLEANUP: mux-h2: remove two useless but misleading assignments
h2c->st0 was assigned to H2_CS_ERROR right after returning from
h2c_error(), which had already done it. It's useless and confusing,
let's remove this.
2019-01-29 18:51:41 +01:00
Willy Tarreau
3ad5d31bdf BUG/MEDIUM: mux-h2: only close connection on request frames on closed streams
A subtle bug was introduced with H2 on the backend. RFC7540 states that
an attempt to create a stream on an ID not higher than the max known is
a connection error. This was translated into rejecting HEADERS frames
for closed streams. But with H2 on the backend, if the client aborts
and causes an RST_STREAM to be emitted, the stream is effectively closed,
and if/once the server responds, it starts by emitting a HEADERS frame
with this ID thus it is interpreted as a connection error.

This test must of course consider the side the mux is installed on and
not take this for a connection error on responses.

The effect is that an aborted stream on an outgoing H2 connection, for
example due to a client stopping a transfer with option abortonclose
set, would lead to an abort of all other streams. In the logs, this
appears as one or several CD-- line(s) followed by one or several SD--
lines which are victims.

Thanks to Luke Seelenbinder for reporting this problem and providing
enough elements to help understanding how to reproduce it.

This fix must be backported to 1.9.
2019-01-29 18:49:27 +01:00
Willy Tarreau
6afec46ba3 BUG/MINOR: mux-h2: do not report available outgoing streams after GOAWAY
The calculation of available outgoing H2 streams was improved by commit
d64a3ebe6 ("BUG/MINOR: mux-h2: always check the stream ID limit in
h2_avail_streams()"), but it still is incorrect because RFC7540#6.8
specifically forbids the creation of new streams after a GOAWAY frame
was received. Thus we must not mark the connection as available anymore
in order to be able to handle a graceful shutdown.

This needs to be backported to 1.9.
2019-01-28 06:44:53 +01:00
Tim Duesterhus
4707033932 CLEANUP: h2: Remove debug printf in mux_h2.c
It was introduced by 1915ca273832ba542d72eb0645dd7ccb6d5b945f
and should be backported to 1.9.
2019-01-25 05:22:07 +01:00
Willy Tarreau
1915ca2738 BUG/MINOR: mux-h2: always compare content-length to the sum of DATA frames
This is mandated by RFC7541#8.1.2.6. Till now we didn't have a copy of
the content-length header field. But now that it's already parsed, it's
easy to add the check.

The reg-test was updated to match the new behaviour as the previous one
expected unadvertised data to be silently discarded.

This should be backported to 1.9 along with previous patch (MEDIUM: h2:
always parse and deduplicate the content-length header) after it has got
a bit more exposure.
2019-01-24 19:45:27 +01:00
Willy Tarreau
4790f7c907 MEDIUM: h2: always parse and deduplicate the content-length header
The header used to be parsed only in HTX but not in legacy. And even in
HTX mode, the value was dropped. Let's always parse it and report the
parsed value back so that we'll be able to store it in the streams.
2019-01-24 19:07:26 +01:00
Willy Tarreau
e9634bdc22 MINOR: mux-h2: always consider a server's max-reuse parameter
This parameter allows to limit the number of successive requests sent
on a connection. Let's compare it to the number of streams already sent
on the connection to decide if the connection may still appear in the
idle list or not. This may be used to help certain servers work around
resource leaks, and also helps dealing with the issue of the GOAWAY in
flight which requires to set a usage limit on the client to be reliable.

This must be backported to 1.9.
2019-01-24 19:06:43 +01:00
Willy Tarreau
a80dca8535 BUG/MINOR: mux-h2: refuse to allocate a stream with too high an ID
One of the reasons for the excessive number of aborted requests when a
server sets a limit on the highest stream ID is that we don't check
this limit while allocating a new stream.

This patch does this at two locations :
  - when a backend stream is allocated, we verify that there are still
    IDs left ;
  - when the ID is assigned, we verify that it's not higher than the
    advertised limit.

This should be backported to 1.9.
2019-01-24 19:06:43 +01:00
Willy Tarreau
d64a3ebe64 BUG/MINOR: mux-h2: always check the stream ID limit in h2_avail_streams()
This function is used to decide whether to put an idle connection back
into the idle pool. While it considers the limit in number of concurrent
requests, it does not consider the limit in number of streams, so if a
server announces a low limit in a GOAWAY frame, it will be ignored.

However there is a caveat : since we assign the stream IDs when sending
them, we have a number of allocated streams which max_id doesn't take
care of. This can be addressed by adding a new nb_reserved count on each
connection to keep track of the ID-less streams.

This patch makes sure we take care of the remaining number of streams
if such a limit was announced, or of the number of streams before the
highest ID. Now it is possible to accurately know how many streams
can be allocated, and the number of failed outgoing streams has dropped
in half.

This must be backported to 1.9.
2019-01-24 19:06:43 +01:00
Willy Tarreau
175cebb38a BUG/MINOR: mux-h2: make it possible to set the error code on an already closed stream
When sending RST_STREAM in response to a frame delivered on an already
closed stream, we used not to be able to update the error code and
deliver an RST_STREAM with a wrong code (e.g. H2_ERR_CANCEL). Let's
always allow to update the code so that RST_STREAM is always sent
with the appropriate error code (most often H2_ERR_STREAM_CLOSED).

This should be backported to 1.9 and possibly to 1.8.
2019-01-24 15:27:06 +01:00
Willy Tarreau
5b4eae33de BUG/MINOR: mux-h2: headers-type frames in HREM are always a connection error
There are incompatible MUST statements in the HTTP/2 specification. Some
require a stream error and others a connection error for the same situation.
As discussed in the thread below, let's always apply the connection error
when relevant (headers-like frame in half-closed(remote)) :

  https://mailarchive.ietf.org/arch/msg/httpbisa/pOIWRBRBdQrw5TDHODZXp8iblcE

This must be backported to 1.9, possibly to 1.8 as well.
2019-01-24 15:27:06 +01:00
Willy Tarreau
113c7a2794 BUG/MINOR: mux-h2: CONTINUATION in closed state must always return GOAWAY
Since we now support CONTINUATION frames, we must take care of properly
aborting the connection when they are sent on a closed stream. By default
we'd get a stream error which is not sufficient since the compression
context is modified and unrecoverable.

More info in this discussion :

   https://mailarchive.ietf.org/arch/msg/httpbisa/azZ1jiOkvM3xrpH4jX-Q72KoH00

This needs to be backported to 1.9 and possibly to 1.8 (less important there).
2019-01-24 15:27:06 +01:00
Willy Tarreau
31e846a071 BUG/MEDIUM: mux-h2: properly abort on trailers decoding errors
There was an incomplete test in h2c_frt_handle_headers() resulting
in negative return values from h2c_decode_headers() not being taken
as errors. The effect is that the stream is then aborted on timeout
only.

This fix must be backported to 1.9.
2019-01-24 15:27:06 +01:00
Willy Tarreau
759ca1eacc BUG/MAJOR: mux-h2: don't destroy the stream on failed allocation in h2_snd_buf()
In case we cannot allocate a stream ID for an outgoing stream, the stream
will be aborted. The problem is that we also release it and it will be
destroyed again by the application detecting the error, leading to a NULL
dereference in h2_shutr() and h2_shutw(). Let's only mark the error on the
CS and let the rest of the code handle the close.

This should be backported to 1.9.
2019-01-24 13:52:10 +01:00
Christopher Faulet
a413e958fd BUG/MEDIUM: mux-h2/htx: Respect the channel's reserve
When data are pushed in the channel's buffer, in h2_rcv_buf(), the mux-h2 must
respect the reserve if the flag CO_RFL_KEEP_RSV is set. In HTX, because the
stream-interface always sees the buffer as full, there is no other way to know
the reserve must be respected.

This patch must be backported to 1.9.
2019-01-23 11:27:34 +01:00
Willy Tarreau
a01f45e3ce BUG/CRITICAL: mux-h2: re-check the frame length when PRIORITY is used
Tim Düsterhus reported a possible crash in the H2 HEADERS frame decoder
when the PRIORITY flag is present. A check is missing to ensure the 5
extra bytes needed with this flag are actually part of the frame. As per
RFC7540#4.2, let's return a connection error with code FRAME_SIZE_ERROR.

Many thanks to Tim for responsibly reporting this issue with a working
config and reproducer. This issue was assigned CVE-2018-20615.

This fix must be backported to 1.9 and 1.8.
2019-01-08 13:20:59 +01:00
Willy Tarreau
1bb812fd80 MEDIUM: mux-h2: emit HEADERS frames when facing HTX trailers blocks
Now the H2 mux will parse and encode the HTX trailers blocks and send
the corresponding HEADERS frame. Since these blocks contain pure H1
trailers which may be fragmented on line boundaries, if first needs
to collect all of them, parse them using the H1 parser, build a list
and finally encode all of them at once once the EOM is met. Note that
this HEADERS frame always carries the end-of-headers and end-of-stream
flags.

This was tested using the helloworld examples from the grpc project,
as well as with the h2c tools. It doesn't seem possible at the moment
to test tailers using varnishtest though.
2019-01-04 10:56:26 +01:00
Willy Tarreau
7eeb10a5b5 MINOR: mux-h2: make HTX_BLK_EOM processing idempotent
We want to make sure we won't emit another empty DATA frame if we meet
HTX_BLK_EOM after and end of stream was already sent. For now it cannot
happen as far as HTX is respected, but with trailers it may become
ambiguous.
2019-01-04 09:28:17 +01:00