Commit Graph

9271 Commits

Author SHA1 Message Date
Christopher Faulet
3949c9d90d BUG/MEDIUM: mux-h1: Don't add "transfer-encoding" if message-body is forbidden
When a HTTP/1.1 or above response is emitted to a client, if the flag
H1_MF_XFER_LEN is set whereas H1_MF_CLEN and H1_MF_CHNK are not, the header
"transfer-encoding" is added. It is a way to make HTX chunking consistent with
H2. But we must exclude all cases where the message-body is explicitly forbidden
by the RFC:

 * for all 1XX, 204 and 304 responses
 * for any responses to HEAD requests
 * for 200 responses to CONNECT requests

For these 3 cases, the flag H1_MF_XFER_LEN is set but H1_MF_CLEN and H1_MF_CHNK
not. And the header "transfer-encoding" must not be added.

See issue #27 on github for details about the bug.

This patch must be backported in 1.9.
2019-01-31 11:07:17 +01:00
Frédéric Lécaille
04636b7bac BUG/MEDIUM: peers: Peer addresses parsing broken.
This bug was introduced by 355b203 commit which prevented the peer
addresses to be parsed for the local peer of a "peers" section.
When adding "parse_addr" boolean parameter to parse_server(), this commit
missed the case where the syntax with "peer" keyword should still be
supported in addition to the new syntax with "server"+"bind" keyword.

May be backported as fas as 1.5.
2019-01-31 09:56:39 +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
e5fcfbed5c MINOR: htx: never check for null htx pointer in htx_is_{,not_}empty()
The previous patch clarifies the fact that the htx pointer is never null
along all the code. This test for a null will never match, didn't catch
the pointer 1 before the fix for b_is_null(), but it confuses the compiler
letting it think that any dereferences made to this pointer after this
test could actually mean we're dereferencing a null. Let's now drop this
test. This saves us from having to add impossible tests everywhere to
avoid the warning.

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
245d189cce DOC: htx: make it clear that htxbuf() and htx_from_buf() always return valid pointers
Update the comments above htxbuf() and htx_from_buf() to make it clear
that they always return valid htx pointers so that callers know they do
not have to test them. This is only true after the fix on b_is_null()
which was the only known corner case.

This should be backported to 1.9 if the b_is_null() patch is backported.
2019-01-31 08:07:17 +01:00
Olivier Houchard
203d735cac BUG/MEDIUM: buffer: Make sure b_is_null handles buffers waiting for allocation.
In b_is_null(), make sure we return 1 if the buffer is waiting for its
allocation, as users assume there's memory allocated if b_is_null() returns
0.

The indirect impact of not having this was that htxbuf() would not match
b_is_null() for a buffer waiting for an allocation, and would thus return
the value 1 for the htx pointer, causing various crashes under low memory
condition.

Note that this patch makes gcc versions 6 and above report two null-deref
warnings in proto_htx.c since htx_is_empty() continues to check for a null
pointer without knowing that this is protected by the test on b_is_null().
This is addressed by the following patches.

This should be backported to 1.9.
2019-01-31 08:07:17 +01:00
Tim Duesterhus
bb48c9a0ee DOC: compression: Update the reasons for disabled compression
- Update the list of status codes to include 201 - 203.
- Remove the fact about the temporary workaround for chunked responses
  (this is verified using reg-test compression/h00000.vtc).
- Add malformed ETags

see b229f018ee

This commit should be backported together with b229f018ee
the changes should be correct until 1.7 at the very least, possibly older.
2019-01-31 04:33:07 +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
9c84d8299a MINOR: h2: add a generic frame checker
The new function h2_frame_check() checks the protocol limits for the
received frame (length, ID, direction) and returns a verdict made of
a connection error code. The purpose is to be able to validate any
frame regardless of the state and the ability to call the frame handler,
and to emit a GOAWAY early in this case.
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
Kevin Zhu
13ebef7ecb BUG/MINOR: deinit: tcp_rep.inspect_rules not deinit, add to deinit
It seems like this can be backported as far as 1.5.
2019-01-30 10:22:34 +01:00
Tim Duesterhus
b229f018ee BUG/MEDIUM: compression: Rewrite strong ETags
RFC 7232 section 2.3.3 states:

> Note: Content codings are a property of the representation data,
> so a strong entity-tag for a content-encoded representation has to
> be distinct from the entity tag of an unencoded representation to
> prevent potential conflicts during cache updates and range
> requests.  In contrast, transfer codings (Section 4 of [RFC7230])
> apply only during message transfer and do not result in distinct
> entity-tags.

Thus a strong ETag must be changed when compressing. Usually this is done
by converting it into a weak ETag, which represents a semantically, but not
byte-by-byte identical response. A conversion to a weak ETag still allows
If-None-Match to work.

This should be backported to 1.9 and might be backported to every supported
branch with compression.
2019-01-29 20:26:06 +01:00
Olivier Houchard
7493114729 BUG/MEDIUM: servers: Close the connection if we failed to install the mux.
If we failed to install the mux, just close the connection, or
conn_fd_handler() will be called for the FD, and crash as soon as it attempts
to access the mux' wake method.

This should be backported to 1.9.
2019-01-29 19:53:09 +01:00
Olivier Houchard
ef60ff38fb BUG/MEDIUM: peers: Handle mux creation failure.
If the mux fails to properly be created by conn_install_mux, fail, instead
of silently ignoring it.

This should be backported to 1.9.
2019-01-29 19:47:20 +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
Olivier Houchard
a48437bb5e BUG/MEDIUM: checks: Don't try to set ALPN if connection failed.
If we failed to connect, don't attempt to set the ALPN, as we don't have
a SSL context, anyway.

This should be backported to 1.9.
2019-01-29 19:47:20 +01:00
Olivier Houchard
26da323cb9 BUG/MEDIUM: servers: Don't add an incomplete conn to the server idle list.
If we failed to add the connection to the session, only try to add it back
to the server idle list if it has a mux, otherwise the connection is
incomplete and unusable.

This should be backported to 1.9.
2019-01-29 19:47:20 +01:00
Olivier Houchard
4dc85538ba BUG/MEDIUM: servers: Only destroy a conn_stream we just allocated.
In connect_server(), if we failed to add the connection to the session,
only destroy the conn_stream if we just allocated it, otherwise it may
have been allocated outside connect_server(), along with a connection which
has its destination address set.
Also use si_release_endpoint() instead of cs_destroy(), to make sure the
stream_interface doesn't reference it anymore.

This should be backported to 1.9.
2019-01-29 19:47:20 +01:00
Olivier Houchard
f67be93ae0 BUG/MEDIUM: checks: Check that conn_install_mux succeeded.
If conn_install_mux failed, then the connection has no mux and won't be
usable, so just give up is on failure instead of ignoring it.

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
6254a9257e BUILD/MINOR: peers: shut up a build warning introduced during last cleanup
A new warning appears when building at -O0 since commit 3f0fb9df6 ("MINOR:
peers: move "hello" message treatment code to reduce the size of the I/O
handler."), it is related to the fact that proto_len is initialized from
strlen() which is not a constant. Let's replace it with sizeof-1 instead
and also mark the variable as static since it's useless outside of the file.
2019-01-29 17:45:23 +01:00
Willy Tarreau
6f731f33ac CLEANUP: peers: factor error handling in peer_treat_definedmsg()
This is a trivial code refactoring of similar parsing error code
under a single label.
2019-01-29 11:11:23 +01:00
Willy Tarreau
1e82a14c34 CLEANUP: peers: factor the error handling code in peer_treet_updatemsg()
The error handling code was extremely repetitive and error-prone due
to the numerous copy-pastes, some involving unlocks or free. Let's
factor this out. The code could be further simplified, but 12 locations
were already cleaned without taking risks.
2019-01-29 11:08:06 +01:00
Frédéric Lécaille
4b2fd9bf71 MINOR: peers: move peer initializations code to reduce the size of the I/O handler.
Implements two new functions to init peer flags and other stuff after
having accepted or connected them with the peer I/O handler so that
to reduce its size.

May be backported as far as 1.5.
2019-01-29 10:29:54 +01:00
Frédéric Lécaille
3f0fb9df6c MINOR: peers: move "hello" message treatment code to reduce the size of the I/O handler.
This patch implements three functions to read and parse the three
line of a "hello" peer protocol message so that to call them from the
peer I/O handler and reduce its size.

May be backported as far as 1.5.
2019-01-29 10:29:54 +01:00
Frédéric Lécaille
be825e5c05 CLEANUP: peers: Remove useless statements.
When implementing peer_recv_msg() we added the statements reached with
a "goto imcomplete" at the end of this function. This statements
are executed only when co_getblk() returns something <0. So they
are useless for now on, and may be safely removed. The following
section wich was responsible of sending any peer protocol messages
were reached only when co_getblk() returned 0 (no more message to
read). In this case we replace the "goto impcomplete" statement by
a "goto send_msgs" to reach this only when peer_recv_msg() returns 0.

May be backported as far as 1.5.
2019-01-29 10:29:54 +01:00
Frédéric Lécaille
25e1d5e435 MINOR: peers: move send code to reduce the size of the I/O handler.
This patch extracts the code responsible of sending peer protocol
messages from the peer I/O handler to create a new function and to
reduce the size of this handler.

May be backported as far as 1.5.
2019-01-29 10:29:54 +01:00
Frédéric Lécaille
444243c62c MINOR: peers: move messages treatment code to reduce the size of the I/O handler.
Extract the code of the peer I/O handler responsible of treating
any peer protocol message to create peer_treat_awaited_msg() function.
Also rename peer_recv_updatemsg() to peer_treat_updatemsg() as this
function only parse a stick-table update message already received
by peer_recv_msg().

May be backported as far as 1.5.
2019-01-29 10:29:54 +01:00
Frédéric Lécaille
7d0ceeec80 MINOR: peers: move error handling to reduce the size of the I/O handler.
Implement new functions to send error and control class stick-table
messages.

May be backported as far as 1.5.
2019-01-29 10:29:54 +01:00
Frédéric Lécaille
d5fe14bb96 CLEANUP: peers: Be more generic.
Make usage of a C union to pass parameters to all the peer_prepare_*()
functions (more readable).

May be backported as far as 1.5.
2019-01-29 10:29:54 +01:00
Frédéric Lécaille
95203f2185 MINOR: peers: Move high level receive code to reduce the size of I/O handler.
Implement a new function to read incoming stick-table messages.

May be backported as far as 1.5.
2019-01-29 10:29:54 +01:00
Frédéric Lécaille
d27b09400c MINOR: peers: Move ack, switch and definition receive code to reduce the size of the I/O handler.
Implement three new functions to treat peer acks, switch and
definition messages extracting the code from the big swich-case
of the peer I/O handler to give more chances to this latter to be
readable.

May be backported as far as 1.5.
2019-01-29 10:29:54 +01:00
Frédéric Lécaille
168a34b45f MINOR: peers: Move update receive code to reduce the size of the I/O handler.
This patch implements a new function to treat the stick-table
update messages so that to reduce the size of the peer I/O handler
by ~200 lines.

May be backported as far as 1.5.
2019-01-29 10:29:54 +01:00
Frédéric Lécaille
6a8303d49e MEDIUM: peers: synchronizaiton code factorization to reduce the size of the I/O handler.
Factorize the code responsible of synchronizing the peers upon startup.

May be backported as far as 1.5.
2019-01-29 10:29:54 +01:00
Frédéric Lécaille
87f554c9fb MINOR: peers: Add new functions to send code and reduce the I/O handler.
This patch reduces the size of the peer I/O handler implementing
a new function named peer_send_updatemsg() which uses the already
implement peer_prepare_updatemsg(), then ci_putblk().
Reuse the code used to implement peer_send_(ack|swith)msg() function
especially the more generic function peer_send_msg().

May be backported as far as 1.5.
2019-01-29 10:29:54 +01:00
Frédéric Lécaille
ec44ea8692 MINOR: peers: send code factorization.
Implements peer_send_*msg() functions for switch and ack messages which call the
already defined peer_prepare_*msg() before calling ci_putblk().
These two new functions are used at three places in the peer_io_handler().

May be backported as far as 1.5.
2019-01-29 10:29:54 +01:00
Frédéric Lécaille
a8725ec372 CLEANUP: peers: Indentation fixes.
May be backported as far as 1.5.
2019-01-29 10:29:54 +01:00
Frédéric Lécaille
ce02557aad MINOR: peers: Extract some code to be reused.
May be backported as far as 1.5.
2019-01-29 10:29:54 +01:00
Willy Tarreau
9589c3bce7 SCRIPTS: add the issue tracker URL to the announce script
This way it's easier for users to follow the status of pending issues
with each release.
2019-01-29 06:51:16 +01:00
Willy Tarreau
d822013f45 BUG/MEDIUM: backend: always call si_detach_endpoint() on async connection failure
In case an asynchronous connection (ALPN) succeeds but the mux fails to
attach, we must release the stream interface's endpoint, otherwise we
leave the stream interface with an endpoint pointing to a freed connection
with si_ops == si_conn_ops, and sess_update_st_cer() calls si_shutw() on
it, causing it to crash.

This must be backported to 1.9 only.
2019-01-28 16:33:35 +01:00
Olivier Houchard
9ef5155ba6 BUG/MEDIUM: servers: Attempt to reuse an unfinished connection on retry.
In connect_server(), if the previous connection failed, but had an alpn, no
mux was created, and thus the stream_interface's endpoint would be the
connection. In this case, instead of forgetting about it, and overriding
the stream_interface's endpoint later, try to reuse the connection, or the
connection will still be in the session's connection list, and will reference
to a stream that was probably destroyed.

This should be backported to 1.9.
2019-01-28 16:33:31 +01:00
Willy Tarreau
13afcb7ab3 BUG/MINOR: task: fix possibly missed event in inter-thread wakeups
There's a very small but existing uncertainty window when waking another
thread up where it is possible for task_wakeup() not to wake the other
task up because it's still running while this once is in the process of
finishing and loses its TASK_RUNNING flag. In this case the wakeup will
be missed.

The problem is that we have a single flag to store 3 states, since the
transition from running to sleeping isn't atomic. Thus we need to have
another flag to cover this part. This patch introduces TASK_QUEUED to
mention that the task is already in the run queue, running or not. This
bit will be removed while TASK_RUNNING is kept once dequeued, and will
be used when removing TASK_RUNNING to check if the task has been requeued.

It might be possible to slightly improve this but the occurrence rate
is quite low and we don't really need to complexify the scheduler to
optimize for a rare case.

The impact with the current code is very low since we have few inter-
thread wakeups. Most of them are caused by checks killing sessions.

This must be backported to 1.9.
2019-01-28 15:03:04 +01:00