]> git.ipfire.org Git - thirdparty/haproxy.git/log
thirdparty/haproxy.git
4 years agoMEDIUM: contrib/prometheus-exporter: Use dynamic labels instead of static ones
Christopher Faulet [Thu, 28 Jan 2021 10:24:17 +0000 (11:24 +0100)] 
MEDIUM: contrib/prometheus-exporter: Use dynamic labels instead of static ones

Instead of using static labels for metrics, we now use an array of labels,
filled for each metrics if necessary and passed to the dump function. This
way, it is easier to extend the promex service. For now, there are at most 8
labels per metrics. This limit may be raised by changing PROMEX_MAX_LABELS
value. And to ease labels addition, a label is defined as a key/value
pair. The formatting is handled by the dump function.

For the proxies and servers, the first entry of the array is always the
proxy name. In addition, for the servers, the second entry is always the
server name.

4 years agoMAJOR: contrib/prometheus-exporter: move ftd/bkd/srv states to labels
William Dauchy [Wed, 27 Jan 2021 21:40:17 +0000 (22:40 +0100)] 
MAJOR: contrib/prometheus-exporter: move ftd/bkd/srv states to labels

this patch is a breaking change between v2.3 and v2.4: we move from
using gauge value for frontend/backend/servers states to labels values.

the main motivation being I realised it is very difficult to make use of
it without hard coded quirks on prometheus client side; especially
because the main use is often to group by state, which is harder when
the state is the value of the metric.

in order to achieve that we iterate on the status metric to generate
labels, and so as many metrics.

this is the first step to resolve github issue #1029
A second step should address health check states.

Signed-off-by: William Dauchy <wdauchy@gmail.com>
4 years agoMINOR: contrib/prometheus-exporter: declare states for objects
William Dauchy [Wed, 27 Jan 2021 21:40:16 +0000 (22:40 +0100)] 
MINOR: contrib/prometheus-exporter: declare states for objects

in preparation to change state gauge values as labels, declare them as
enum associated with the string definition

Signed-off-by: William Dauchy <wdauchy@gmail.com>
4 years agoMINOR: mux-h2: Slightly improve request HEADERS frames sending
Christopher Faulet [Fri, 29 Jan 2021 10:49:16 +0000 (11:49 +0100)] 
MINOR: mux-h2: Slightly improve request HEADERS frames sending

In h2s_bck_make_req_headers() function, in the loop on the HTX blocks, the
most common blocks, the headers, are now handled in first, before the
start-line. The same change was already performed on the response HEADERS
frames. Thus the code is more consistent now.

4 years agoMINOR: mux-h2: Don't tests the start-line when sending HEADERS frame
Christopher Faulet [Fri, 29 Jan 2021 10:39:43 +0000 (11:39 +0100)] 
MINOR: mux-h2: Don't tests the start-line when sending HEADERS frame

When a HEADERS frame is sent, it is always when an HTX start-line block is
found. Thus, in h2s_bck_make_req_headers() and h2s_frt_make_resp_headers()
functions, it is useless to tests the start-line. Instead of being too
defensive, we use BUG_ON() now because it must not happen and must be
handled as a bug.

This patch should fix the issue #1086.

4 years agoMINOR: ssl-sample: Don't check if argument list is set in sample fetches
Christopher Faulet [Fri, 29 Jan 2021 10:30:37 +0000 (11:30 +0100)] 
MINOR: ssl-sample: Don't check if argument list is set in sample fetches

The list is always defined by definition. Thus there is no reason to test
it.

4 years agoMINOR: sample: Don't check if argument list is set in sample fetches
Christopher Faulet [Fri, 29 Jan 2021 10:29:28 +0000 (11:29 +0100)] 
MINOR: sample: Don't check if argument list is set in sample fetches

The list is always defined by definition. Thus there is no reason to test
it.

4 years agoMINOR: http-conv: Don't check if argument list is set in sample converters
Christopher Faulet [Fri, 29 Jan 2021 10:25:02 +0000 (11:25 +0100)] 
MINOR: http-conv: Don't check if argument list is set in sample converters

The list is always defined by definition. Thus there is no reason to test
it.

4 years agoMINOR: http-fetch: Don't check if argument list is set in sample fetches
Christopher Faulet [Fri, 29 Jan 2021 10:22:15 +0000 (11:22 +0100)] 
MINOR: http-fetch: Don't check if argument list is set in sample fetches

The list is always defined by definition. Thus there is no reason to test
it. There is also plenty of checks on arguments types while it is already
validated during the configuration parsing. But one thing at a time.

This patch should fix the issue #1087.

4 years agoBUG/MINOR: stick-table: Always call smp_fetch_src() with a valid arg list
Christopher Faulet [Fri, 29 Jan 2021 09:27:47 +0000 (10:27 +0100)] 
BUG/MINOR: stick-table: Always call smp_fetch_src() with a valid arg list

The sample fetch functions must always be called with a valid argument
list. When called by hand, if there is no argument to pass, empty_arg_list must
be used.

In the stick-table code, there are some calls to smp_fetch_src() with NULL as
argument list. It is changed to use empty_arg_list instead. It is not really a
bug because smp_fetch_src() does not use the argument list. But it is an API
bug.

This patch may be backported to all stable branches as a cleanup.

4 years agoMINOR: mux-h1: Remove first useless test on count in h1_process_output()
Christopher Faulet [Fri, 29 Jan 2021 09:22:28 +0000 (10:22 +0100)] 
MINOR: mux-h1: Remove first useless test on count in h1_process_output()

h1_process_output() function is never called with no data to send (count ==
0). Thus, the first test on count, at the beginning of the function is
useless and may be removed. This way, by reading the code, it is obvious the
<chn_htx> variable is always defined.

This patch should fix the issue #1085.

4 years agoMINOR: stick-tables: export process_table_expire()
Willy Tarreau [Fri, 29 Jan 2021 11:39:32 +0000 (12:39 +0100)] 
MINOR: stick-tables: export process_table_expire()

This handler can take quite some time as it deletes a large number of
entries under a lock, let's export it so that it's immediately visible
in "show profiling".

4 years agoMINOR: peers: export process_peer_sync() to improve traces
Willy Tarreau [Fri, 29 Jan 2021 11:38:42 +0000 (12:38 +0100)] 
MINOR: peers: export process_peer_sync() to improve traces

This one will probably pop up from time to time in "show profiling",
better have it resolve.

4 years agoMINOR: checks: export a few functions that appear often in trace dumps
Willy Tarreau [Fri, 29 Jan 2021 11:35:24 +0000 (12:35 +0100)] 
MINOR: checks: export a few functions that appear often in trace dumps

The check I/O handler, process_chk_conn and server_warmup are often
present in complex backtraces as they're impacted by locking or I/O
issues. Let's export them so that they resolve cleanly.

4 years agoMINOR: muxes: export the timeout and shutr task handlers
Willy Tarreau [Fri, 29 Jan 2021 11:33:46 +0000 (12:33 +0100)] 
MINOR: muxes: export the timeout and shutr task handlers

These ones appear often in "show tasks" so it's handy to make them
resolve.

4 years agoMINOR: session: export session_expire_embryonic()
Willy Tarreau [Fri, 29 Jan 2021 11:27:57 +0000 (12:27 +0100)] 
MINOR: session: export session_expire_embryonic()

This is only to make it resolve nicely in "show tasks".

4 years agoMINOR: listener: export accept_queue_process
Willy Tarreau [Fri, 29 Jan 2021 11:25:23 +0000 (12:25 +0100)] 
MINOR: listener: export accept_queue_process

This is only to make it resolve in "show tasks".

4 years agoMINOR: activity: add a new "show tasks" command to list currently active tasks
Willy Tarreau [Fri, 29 Jan 2021 10:32:55 +0000 (11:32 +0100)] 
MINOR: activity: add a new "show tasks" command to list currently active tasks

This finally adds the long-awaited solution to inspect the run queues
and figure what is eating the CPU or causing latencies. We can even see
the experienced latencies when profiling is enabled. Example on a
saturated process:

> show tasks
Running tasks: 14983 (4 threads)
  function                     places     %    lat_tot   lat_avg
  process_stream                 4948   33.0   5.840m    70.82ms
  h1_io_cb                       2535   16.9      -         -
  main+0x9e670                   2508   16.7   2.930m    70.10ms
  ssl_sock_io_cb                 2499   16.6      -         -
  si_cs_io_cb                    2493   16.6      -         -

4 years agoMINOR: activity: flush scheduler stats on "set profiling tasks on"
Willy Tarreau [Fri, 29 Jan 2021 10:56:21 +0000 (11:56 +0100)] 
MINOR: activity: flush scheduler stats on "set profiling tasks on"

If a user enables profiling by hand, it makes sense to reset the stats
counters to provide fresh new measurements. Therefore it's worth using
this as the standard method to reset counters.

4 years agoMINOR: activity: also report collected tasks stats in "show profiling"
Willy Tarreau [Thu, 28 Jan 2021 23:07:40 +0000 (00:07 +0100)] 
MINOR: activity: also report collected tasks stats in "show profiling"

"show profiling" will now dump the stats collected by the scheduler if
profiling was previously enabled. This will immediately make it obvious
what functions are responsible for others' high latencies or which ones
are suffering from others, and should help spot issues like undesired
wakeups.

Example:

Per-task CPU profiling              : on      # set profiling tasks {on|auto|off}
Tasks activity:
  function                      calls   cpu_tot   cpu_avg   lat_tot   lat_avg
  si_cs_io_cb                 5569479   23.37s    4.196us      -         -
  h1_io_cb                    5558654   13.60s    2.446us      -         -
  process_stream               250841   1.476s    5.882us   3.499s    13.95us
  main+0x9e670                    198      -         -      5.526ms   27.91us
  task_run_applet                  17   1.509ms   88.77us   205.8us   12.11us
  srv_cleanup_idle_connections     12   44.51us   3.708us   25.71us   2.142us
  main+0x158c80                     9   48.72us   5.413us      -         -
  srv_cleanup_toremove_connections  5   165.1us   33.02us   123.6us   24.72us

4 years agoMEDIUM: tasks/activity: collect per-task statistics when profiling is enabled
Willy Tarreau [Thu, 28 Jan 2021 23:07:40 +0000 (00:07 +0100)] 
MEDIUM: tasks/activity: collect per-task statistics when profiling is enabled

Now when the profiling is enabled, the scheduler wlil update per-function
task-level statistics on number of calls, cpu usage and lateny, that could
later be checked using "show profiling". This will immediately make it
obvious what functions are responsible for others' high latencies or which
ones are suffering from others, and should help spot issues like undesired
wakeups. For now the stats are only collected but not reported (though they
are readable from sched_activity[] under gdb).

4 years agoMINOR: activity: declare a new structure to collect per-function activity
Willy Tarreau [Thu, 28 Jan 2021 18:19:26 +0000 (19:19 +0100)] 
MINOR: activity: declare a new structure to collect per-function activity

The new sched_activity structure will be used to collect task-level
activity based on the target function. The principle is to declare a
large enough array to make collisions rare (256 entries), and hash
the function pointer using a reduced XXH to decide where to store the
stats. On first computation an entry is definitely assigned to the
array and it's done atomically. A special entry (0) is used to store
collisions ("others"). The goal is to make it easy and inexpensive for
the scheduler code to use these to store #calls, cpu_time and lat_time
for each task.

4 years agoMINOR: activity: make profiling more manageable
Willy Tarreau [Thu, 28 Jan 2021 20:44:22 +0000 (21:44 +0100)] 
MINOR: activity: make profiling more manageable

In 2.0, commit d2d3348ac ("MINOR: activity: enable automatic profiling
turn on/off") introduced an automatic mode to enable/disable profiling.
The problem is that the automatic mode automatically changes to on/off,
which implied that the forced on/off modes aren't sticky anymore. It's
annoying when debugging because as soon as the load decreases, profiling
stops.

This makes a small change which ought to have been done first, which
consists in having two states for "auto" (auto-on, auto-off) to
distinguish them from the forced states. Setting to "auto" in the config
defaults to "auto-off" as before, and setting it on the CLI switches to
auto but keeps the current operating state.

This is simple enough to be backported to older releases if needed.

4 years agoMINOR: tools: add print_time_short() to print a condensed duration value
Willy Tarreau [Fri, 29 Jan 2021 09:47:52 +0000 (10:47 +0100)] 
MINOR: tools: add print_time_short() to print a condensed duration value

When reporting some values in debugging output we often need to have
some condensed, stable-length values. This function prints a duration
from nanosecond to years with at least 4 digits of accuracy using the
most suitable unit, always on 7 chars.

4 years agoDOC: management: fix "show resolvers" alphabetical ordering
Willy Tarreau [Fri, 29 Jan 2021 11:01:46 +0000 (12:01 +0100)] 
DOC: management: fix "show resolvers" alphabetical ordering

Not sure why it was located between "show ssl" and "show table"...
This should be backported.

4 years agoCI: Fix the coverity builds
Tim Duesterhus [Thu, 28 Jan 2021 17:58:53 +0000 (18:58 +0100)] 
CI: Fix the coverity builds

In an attempt to fix the use of DEBUG_STRICT commit
7f0f4786d1927f1450392e871480e3122796024e unfortunately broke the Coverity
builds completely.

It turns out that Coverity does not properly handle quoting within
`COVERITY_SCAN_BUILD_COMMAND`, instead breaking up single arguments at
whitespace, thus passing `-DDEBUG_USE_ABORT=1` to `make` as-is.

Fix this issue by hijacking the Makefile within the Coverity workflow. We
simply replace the default value of the `DEBUG` option with whatever values we
need. The build command now only includes the TARGET and USE_* flags, each of
which works without any spaces.

4 years agoBUG/MINOR: backend: check available list allocation for reuse
Amaury Denoyelle [Thu, 28 Jan 2021 16:33:26 +0000 (17:33 +0100)] 
BUG/MINOR: backend: check available list allocation for reuse

Do not consider reuse connection if available list is not allocated for
the target server. This will prevent a crash when using a standalone
server for an external purpose like socket_tcp/socket_ssl on hlua code.
For the idle/safe lists, they are considered allocated if
srv.max_idle_conns is not null.

Note that the hlua code is currently safe thanks to the additional
checks on proxy http mode and stream reuse policy not never. However,
this might not be sufficient for future code.

This patch should be backported in every branches containing the
following patch :
  7f68d815af356fbe1b2e1080a88b9935581c91d2 (2.4 tree)
  REORG: backend: simplify conn_backend_get

4 years agoRevert "BUG/MEDIUM: listener: do not accept connections faster than we can process...
Willy Tarreau [Thu, 28 Jan 2021 17:07:24 +0000 (18:07 +0100)] 
Revert "BUG/MEDIUM: listener: do not accept connections faster than we can process them"

This reverts commit 62e8aaa1bd5ca96089eaa88487c700c4af4617f4.

While is works extremely well to address SSL handshake floods, it prevents
establishment of new connections during regular traffic above 50-60 Gbps,
because for an unknown reason the queue seems to have ~1.7 active tasks
per connection all the time, which makes no sense as these ought to be
waiting on subscribed events. It might uncover a deeper issue but at least
for now a different solution is needed. cf issue #822.

The test is trivial to run, just start a config with tune.runqueue-depth 10
and inject on 1GB objects with more than 10 connections. Try to connect to
the stats socket, it only works once, then the listeners are not dequeued.

4 years agoREGTESTS: set_ssl_server_cert.vtc: set as broken
William Lallemand [Thu, 28 Jan 2021 17:08:36 +0000 (18:08 +0100)] 
REGTESTS: set_ssl_server_cert.vtc: set as broken

It looks like this test is broken with a low nbthread value (1 for
example). Disable this test in the CI until the problem is solved.

4 years agoBUG/MEDIUM: listener: do not accept connections faster than we can process them
Willy Tarreau [Wed, 27 Jan 2021 16:22:29 +0000 (17:22 +0100)] 
BUG/MEDIUM: listener: do not accept connections faster than we can process them

In github issue #822, user @ngaugler reported some performance problems when
dealing with many concurrent SSL connections on restarts, after migrating
from 1.6 to 2.2, indicating a long time required to re-establish connections.

The Run_queue metric in the traces showed an abnormally high number of tasks
in the run queue, likely indicating we were accepting faster than we could
process. And this is indeed one of the differences between 1.6 and 2.2, the
accept I/O loop and the TLS handshakes are totally independent, so much that
they can even run on different threads. In 1.6 the SSL handshake was handled
almost immediately after the accept(), so this was limiting the input rate.
With large maxconn values, as long as there are incoming connections, new
I/Os are scheduled and many of them pass before the handshake, being tagged
for low latency processing.

The result is that handshakes get postponed, and are further postponed as
new connections are accepted. When they are finally able to be processed,
some of them fail as the client is gone, and the client had already queued
new ones. This causes an excess number of apparent connections and total
number of handshakes to be processed, just because we were accepting
connections on a temporarily saturated machine.

The solution is to temporarily pause new incoming connections when the
load already indicates that more tasks are already queued than will be
handled in a poll loop. The difficulty with this usually is to be able
to come back to re-enable the operation, but given that the metric is
the run queue, we just have to queue the global_listener_queue task so
that it gets picked by any thread once the run queues get flushed.

Before this patch, injecting with SSL reneg with 10000 concurrent
connections resulted in 350k tasks in the run queue, and a majority of
handshake timeouts noticed by the client. With the patch, the run queue
fluctuates between 1-3x runqueue-depth, the process is constantly busy, the
accept rate is maximized and clients observe no error anymore.

It would be desirable to backport this patch to 2.3 and 2.2 after some more
testing, provided the accept loop there is compatible.

4 years agoMINOR: h1: Raise the chunk size limit up to (2^52 - 1)
Christopher Faulet [Wed, 27 Jan 2021 14:17:13 +0000 (15:17 +0100)] 
MINOR: h1: Raise the chunk size limit up to (2^52 - 1)

The allowed chunk size was historically limited to 2GB to avoid risk of
overflow. This restriction is no longer necessary because the chunk size is
immediately stored into a 64bits integer after the parsing. Thus, it is now
possible to raise this limit. However to never fed possibly bogus values
from languages that use floats for their integers, we don't get more than 13
hexa-digit (2^52 - 1). 4 petabytes is probably enough !

This patch should fix the issue #1065. It may be backported as far as
2.1. For the 2.0, the legacy HTTP part must be reviewed. But there is
honestely no reason to do so.

4 years agoMINOR: mux-fcgi/trace: add traces at level ERROR for all kind of errors
Christopher Faulet [Wed, 27 Jan 2021 11:06:54 +0000 (12:06 +0100)] 
MINOR: mux-fcgi/trace: add traces at level ERROR for all kind of errors

A number of traces could be added or changed to report errors with
TRACE_ERROR. The goal is to be able to enable error tracing only to detect
anomalies.

4 years agoMINOR: mux-h1/trace: add traces at level ERROR for all kind of errors
Christopher Faulet [Wed, 27 Jan 2021 10:27:50 +0000 (11:27 +0100)] 
MINOR: mux-h1/trace: add traces at level ERROR for all kind of errors

A number of traces could be added or changed to report errors with
TRACE_ERROR. The goal is to be able to enable error tracing only to detect
anomalies.

4 years agoREGTEST: Don't use the websocket to validate http-check
Christopher Faulet [Tue, 5 Jan 2021 14:42:51 +0000 (15:42 +0100)] 
REGTEST: Don't use the websocket to validate http-check

Now, some conformance tests are performed when an HTTP connection is
upgraded to websocket. This make the http-check-send.vtc script failed for
the backend <be6_ws>. Because the purpose of this health-check is to pass a
"Connection: Upgrade" header on an http-check send rule, we may use a dummy
protocal instead.

4 years agoREGTESTS: Fix required versions for several scripts
Christopher Faulet [Tue, 15 Dec 2020 16:13:39 +0000 (17:13 +0100)] 
REGTESTS: Fix required versions for several scripts

The following scripts require HAProxy 2.4 :

 * cache/caching_rules.vtc
 * cache/post_on_entry.vtc
 * cache/vary.vtc
 * checks/1be_40srv_odd_health_checks.vtc
 * checks/40be_2srv_odd_health_checks.vtc
 * checks/4be_1srv_health_checks.vtc
 * converter/fix.vtc
 * converter/mqtt.vtc
 * http-messaging/protocol_upgrade.vtc
 * http-messaging/websocket.vtc
 * http-set-timeout/set_timeout.vtc
 * log/log_uri.vtc

However it may change is features are backported.

4 years agoMINOR: vtc: add websocket test
Amaury Denoyelle [Fri, 11 Dec 2020 16:53:12 +0000 (17:53 +0100)] 
MINOR: vtc: add websocket test

Test the conformance of websocket rfc6455 in haproxy. In particular, if
a missing key is detected on a h1 message, haproxy must close the
connection.

Note that the case h2 client/h1 srv is not tested as I did not find a
way to calculate the key on the server side.

4 years agoMINOR: vtc: add test for h1/h2 protocol upgrade translation
Amaury Denoyelle [Fri, 11 Dec 2020 16:53:11 +0000 (17:53 +0100)] 
MINOR: vtc: add test for h1/h2 protocol upgrade translation

This test send HTTP/1.1 Get+Upgrade or HTTP/2 Extended Connect through a
haproxy instance.

4 years agoMEDIUM: h2: send connect protocol h2 settings
Amaury Denoyelle [Fri, 11 Dec 2020 16:53:10 +0000 (17:53 +0100)] 
MEDIUM: h2: send connect protocol h2 settings

In order to announce support for the Extended CONNECT h2 method by
haproxy, always send the ENABLE_CONNECT_PROTOCOL h2 settings. This new
setting has been described in the rfc 8441.

After receiving ENABLE_CONNECT_PROTOCOL, the client is free to use the
Extended CONNECT h2 method. This can notably be useful for the support
of websocket handshake on http/2.

4 years agoMEDIUM: h2: parse Extended CONNECT request to htx
Amaury Denoyelle [Fri, 11 Dec 2020 16:53:09 +0000 (17:53 +0100)] 
MEDIUM: h2: parse Extended CONNECT request to htx

Support for the rfc 8441 Bootstraping WebSockets with HTTP/2

Convert an Extended CONNECT HTTP/2 request into a htx representation.
The htx message uses the GET method with an Upgrade header field to be
fully compatible with the equivalent HTTP/1.1 Upgrade mechanism.

The Extended CONNECT is of the following form :

:method = CONNECT
:protocol = websocket
:scheme = https
:path = /chat
:authority = server.example.com

The new pseudo-header :protocol has been defined and is used to identify
an Extended CONNECT method. Contrary to standard CONNECT, Extended
CONNECT must have :scheme, :path and :authority defined.

4 years agoMEDIUM: mux_h2: generate Extended CONNECT response
Amaury Denoyelle [Fri, 11 Dec 2020 16:53:08 +0000 (17:53 +0100)] 
MEDIUM: mux_h2: generate Extended CONNECT response

Support for the rfc 8441 Bootstraping WebSockets with HTTP/2

Convert a 101 htx response message to a 200 HTTP/2 response.

4 years agoMEDIUM: h1: add a WebSocket key on handshake if needed
Amaury Denoyelle [Fri, 11 Dec 2020 16:53:07 +0000 (17:53 +0100)] 
MEDIUM: h1: add a WebSocket key on handshake if needed

Add the header Sec-Websocket-Key when generating a h1 handshake websocket
without this header. This is the case when doing h2-h1 conversion.

The key is randomly generated and base64 encoded. It is stored on the session
side to be able to verify response key and reject it if not valid.

4 years agoMEDIUM: mux_h2: generate Extended CONNECT from htx upgrade
Amaury Denoyelle [Fri, 11 Dec 2020 16:53:06 +0000 (17:53 +0100)] 
MEDIUM: mux_h2: generate Extended CONNECT from htx upgrade

Support for the rfc 8441 Bootstraping WebSockets with HTTP/2

Generate an HTTP/2 Extended CONNECT request from a htx Upgrade message.
This conversion is done when seeing the header Connection: Upgrade. A
CONNECT request is written with the :protocol pseudo-header set from the
Upgrade htx header value.

The protocol is saved in the h2s structure. This is needed on the
response side because the protocol is not present on HTTP/2 response but
is needed if the client side is using HTTP/1.1 with 101 status code.

4 years agoMEDIUM: h2: parse Extended CONNECT reponse to htx
Amaury Denoyelle [Fri, 11 Dec 2020 16:53:05 +0000 (17:53 +0100)] 
MEDIUM: h2: parse Extended CONNECT reponse to htx

Support for the rfc 8441 Bootstraping WebSockets with HTTP/2

Convert a 200 status reply from an Extended CONNECT request into a htx
representation. The htx message is set to 101 status code to be fully
compatible with the equivalent HTTP/1.1 Upgrade mechanism.

This conversion is only done if the stream flags H2_SF_EXT_CONNECT_SENT
has been set. This is true if an Extended CONNECT request has already
been seen on the stream.

Besides the 101 status, the additional headers Connection/Upgrade are
added to the htx message. The protocol is set from the value stored in
h2s. Typically it will be extracted from the client request. This is
only used if the client is using h1 as only the HTTP/1.1 101 Response
contains the Upgrade header.

4 years agoMINOR: mux_h2: define H2_SF_EXT_CONNECT_SENT stream flag
Amaury Denoyelle [Fri, 11 Dec 2020 16:53:04 +0000 (17:53 +0100)] 
MINOR: mux_h2: define H2_SF_EXT_CONNECT_SENT stream flag

This flag is used to signal that an Extended CONNECT has been sent by
the server mux on the current stream.
This will allow to convert the response to a 101 htx status message.

4 years agoMEDIUM: h1: generate WebSocket key on response if needed
Amaury Denoyelle [Fri, 11 Dec 2020 16:53:03 +0000 (17:53 +0100)] 
MEDIUM: h1: generate WebSocket key on response if needed

Add the Sec-Websocket-Accept header on a websocket handshake response.
This header may be missing if a h2 server is used with a h1 client.

The response key is calculated following the rfc6455. For this, the
handshake request key must be stored in the h1 session, as a new field
name ws_key. Note that this is only done if the message has been
prealably identified as a Websocket handshake request.

4 years agoMINOR: h1: reject websocket handshake if missing key
Amaury Denoyelle [Fri, 11 Dec 2020 16:53:02 +0000 (17:53 +0100)] 
MINOR: h1: reject websocket handshake if missing key

If a request is identified as a WebSocket handshake, it must contains a
websocket key header or else it can be reject, following the rfc6455.

A new flag H1_MF_UPG_WEBSOCKET is set on such messages.  For the request
te be identified as a WebSocket handshake, it must contains the headers:
  Connection: upgrade
  Upgrade: websocket

This commit is a compagnon of
"MEDIUM: h1: generate WebSocket key on response if needed" and
"MEDIUM: h1: add a WebSocket key on handshake if needed".

Indeed, it ensures that a WebSocket key is added only from a http/2 side
and not for a http/1 bogus peer.

4 years agoMEDIUM: http-ana: Deal with L7 retries in HTTP analysers
Christopher Faulet [Mon, 12 Oct 2020 13:18:50 +0000 (15:18 +0200)] 
MEDIUM: http-ana: Deal with L7 retries in HTTP analysers

The code dealing with the copy of requests in the L7-buffer and the
retransmits during L7 retries has been moved in the HTTP analysers. The copy
is now performed in the REQ_HTTP_XFER_BODY analyser and the L7 retries is
performed in the RES_WAIT_HTTP analyser. This way, si_cs_recv() and
si_cs_send() don't care of it anymore. It is much more natural to deal with
L7 retry in HTTP analysers.

4 years agoMEDIUM: mux-h2: Don't emit DATA frame for bodyless responses
Christopher Faulet [Wed, 2 Dec 2020 14:17:31 +0000 (15:17 +0100)] 
MEDIUM: mux-h2: Don't emit DATA frame for bodyless responses

Some responses must not contain data. Reponses to HEAD requests and 204/304
responses. But there is no warranty that this will be really respected by
the senders or even if it is possible. For instance, the method may be
rewritten by an http-request rule (HEAD->GET). Thus, it is not really
possible to always strip these data from the response at the receive
stage. And the response may be emitted by an applet or an internal service
not strictly following the spec. All that to say that we may be prepared to
handle payload for bodyless responses on the sending path.

In addition, unlike the HTTP/1, it is not really clear that the trailers is
part of the payload or not. Thus, some clients may expect to have the
trailers, if any, in the response to a HEAD request. For instance, the GRPC
status is placed in a trailer and clients rely on it. But what happens for
204 responses then.  Read the following thread for details :

  https://lists.w3.org/Archives/Public/ietf-http-wg/2020OctDec/0040.html

So, thanks to previous patches, it is now possible to know on the sending
path if a response must be bodyless or not. So, for such responses, no DATA
frame is emitted, except eventually the last empty one carring the ES
flag. However, the TRAILERS frames are still emitted. The h2s_skip_data()
function is added to take care to remove HTX DATA blocks without emitting
any DATA frame expect the last one, if there is no trailers.

4 years agoMINOR: h2/mux-h2: Add flags to notify the response is known to have no body
Christopher Faulet [Wed, 2 Dec 2020 13:26:36 +0000 (14:26 +0100)] 
MINOR: h2/mux-h2: Add flags to notify the response is known to have no body

The H2 message flag H2_MSGF_BODYLESS_RSP is now used during the request or
the response parsing to notify the mux that, considering the parsed message,
the response is known to have no body. This happens during HEAD requests
parsing and during 204/304 responses parsing.

On the H2 multiplexer, the equivalent flag is set on H2 streams. Thus the
H2_SF_BODYLESS_RESP flag is set on a H2 stream if the H2_MSGF_BODYLESS_RSP
is found after a HEADERS frame parsing. Conversely, this flag is also set
when a HEADERS frame is emitted for HEAD requests and for 204/304 responses.

The H2_SF_BODYLESS_RESP flag will be used to ignore data payload from the
response but not the trailers.

4 years agoMINOR: mux-h1: Don't add Connection close/keep-alive header for 1xx messages
Christopher Faulet [Wed, 2 Dec 2020 15:46:33 +0000 (16:46 +0100)] 
MINOR: mux-h1: Don't add Connection close/keep-alive header for 1xx messages

No connection header must be added by the H1 mux in 1xx messages, including
101. Existing connection headers remains untouched, especially the "Connection:
upgrade" of 101 responses. This patch only avoids to add "Connection: close" or
"Connection: keep-alive" to 1xx responses.

4 years agoMINOR: mux-h1: Don't emit C-L and T-E headers for 204 and 1xx responses
Christopher Faulet [Wed, 2 Dec 2020 15:17:15 +0000 (16:17 +0100)] 
MINOR: mux-h1: Don't emit C-L and T-E headers for 204 and 1xx responses

204 and 1xx responses must not have any payload. Now, the H1 mux takes care
of that in last resort. But they also must not have any C-L or T-E
headers. Thus, if found on the sending path, these headers are ignored.

4 years agoMEDIUM: mux-h1: Don't emit any payload for bodyless responses
Christopher Faulet [Wed, 2 Dec 2020 15:13:22 +0000 (16:13 +0100)] 
MEDIUM: mux-h1: Don't emit any payload for bodyless responses

Some responses must not contain data. Reponses to HEAD requests and 204/304
xresponses. But there is no warranty that this will be really respected by
the senders or even if it is possible. For instance, the method may be
rewritten by an http-request rule (HEAD->GET). Thus, it is not really
possible to always strip the payload from the response at the receive
stage. And the response may be emitted by an applet or an internal service
not strictly following the spec. All that to say that we may be prepared to
handle payload for bodyless responses on the sending path.

So, thanks to previous patches, it is now possible to know on the sending
path if a response must be bodyless or not. So, for such responses, no
payload is emitted, all HTX blocks after the EOH are silently removed
(including the trailers).

4 years agoMINOR: mux-h1: Add a flag on H1 streams with a response known to be bodyless
Christopher Faulet [Wed, 2 Dec 2020 15:08:38 +0000 (16:08 +0100)] 
MINOR: mux-h1: Add a flag on H1 streams with a response known to be bodyless

In HTTP/1, responses to HEAD requests and 204/304 must not have payload. The
H1S_F_BODYLESS_RESP flag is not set on streams that should handle such
responses, on the client side and the server side.

On the client side, this flag is set when a HEAD request is parsed and when
a 204/304 response is emitted. On the server side, this happends when a HEAD
request is emitted or a 204/304 response is parsed.

4 years agoMAJOR: htx: Remove the EOM block type and use HTX_FL_EOM instead
Christopher Faulet [Wed, 2 Dec 2020 18:12:22 +0000 (19:12 +0100)] 
MAJOR: htx: Remove the EOM block type and use HTX_FL_EOM instead

The EOM block may be removed. The HTX_FL_EOM flags is enough. Most of time,
to know if the end of the message is reached, we just need to have an empty
HTX message with HTX_FL_EOM flag set. It may also be detected when the last
block of a message with HTX_FL_EOM flag is manipulated.

Removing EOM blocks simplifies the HTX message filling. Indeed, there is no
more edge problems when the message ends but there is no more space to write
the EOM block. However, some part are more tricky. Especially the
compression filter or the FCGI mux. The compression filter must finish the
compression on the last DATA block. Before it was performed on the EOM
block, an extra DATA block with the checksum was added. Now, we must detect
the last DATA block to be sure to finish the compression. The FCGI mux on
its part must be sure to reserve the space for the empty STDIN record on the
last DATA block while this record was inserted on the EOM block.

The H2 multiplexer is probably the part that benefits the most from this
change. Indeed, it is now fairly easier to known when to set the ES flag.

The HTX documentaion has been updated accordingly.

4 years agoMINOR: htx: Add a function to know if a block is the only one in a message
Christopher Faulet [Wed, 2 Dec 2020 16:40:54 +0000 (17:40 +0100)] 
MINOR: htx: Add a function to know if a block is the only one in a message

The htx_is_unique_blk() function may now be used to know if a block is the
only one in an HTX message, excluding all unused blocks. Note the purpose of
this function is not to know if a block is the last one of an HTTP message.
This means no more data part from the message are expected, except tunneled
data. It only says if a block is alone in an HTX message.

4 years agoREGTESTS: Don't run http_msg_full_on_eom script on the 2.4 anymore
Christopher Faulet [Tue, 15 Dec 2020 13:53:03 +0000 (14:53 +0100)] 
REGTESTS: Don't run http_msg_full_on_eom script on the 2.4 anymore

The EOM block will be removed on the 2.4, thus this script will be broken on
this version. Now it is skipped for this version. It remains valid for 2.3
and 2.2.

4 years agoMINOR: htx: Rename HTX_FL_EOI flag into HTX_FL_EOM
Christopher Faulet [Fri, 20 Nov 2020 16:43:16 +0000 (17:43 +0100)] 
MINOR: htx: Rename HTX_FL_EOI flag into HTX_FL_EOM

The HTX_FL_EOI flag is not well named. For now, it is not very used. But
that will change. It will replace the EOM block. Thus, it is renamed.

4 years agoBUG/MAJOR: mux-h1/mux-h2/htx: Fix HTTP tunnel management at the mux level
Christopher Faulet [Fri, 22 Jan 2021 14:28:03 +0000 (15:28 +0100)] 
BUG/MAJOR: mux-h1/mux-h2/htx: Fix HTTP tunnel management at the mux level

Tunnel management between the H1 and H2 multiplexers is a bit blurred. And
the HTX is not enough well defined on this point to make things clear. In
fact, Establishing a tunnel between an H2 client and an H1 server, or the
opposite is buggy because the both multiplexers don't handle the EOM block
the same way when a tunnel is established. In fact, the H2 multiplexer is
pretty strict and add an END_STREAM flag when an EOM block is found, while
the H1 multiplexer is more flexible.

The purpose of this patch is to make the EOM block usage pretty clear and to
fix the HTTP multiplexers to really handle HTTP tunnels in the right
way. Now, an EOM block is used to mark the end of an HTTP message,
semantically speaking. That means it may be followed by tunneled data. Thus,
CONNECT requests are now finished by an EOM block, just after the EOH block.

On the H1 multiplexer side, a tunnel is now only established on the response
path. So a CONNECT request remains in a DONE state waiting for the 2xx
response. On the H2 multiplexer side, a flag is used to know an HTTP tunnel
is requested, to not immediately add the END_STREAM flag on the EOM block.

All these changes are sensitives and not backportable because of recent
changes. The same problem exists on earlier versions and should be
addressed. But it will only be possible with a specific patchset.

This patch relies on the following ones :

  * MEDIUM: mux-h1: Properly handle tunnel establishments and aborts
  * MEDIUM: mux-h2: Close streams when processing data for an aborted tunnel
  * MEDIUM: mux-h2: Block client data on server side waiting tunnel establishment
  * MINOR: mux-h2: Add 2 flags to help to properly handle tunnel mode
  * MINOR: mux-h1: Split H1C_F_WAIT_OPPOSITE flag to separate input/output sides
  * MINOR: mux-h1/mux-fcgi: Don't set TUNNEL mode if payload length is unknown

4 years agoMEDIUM: mux-h1: Properly handle tunnel establishments and aborts
Christopher Faulet [Fri, 22 Jan 2021 14:12:30 +0000 (15:12 +0100)] 
MEDIUM: mux-h1: Properly handle tunnel establishments and aborts

In the same way than the H2 mux, we now bloc data sending on the server side
if a tunnel is not fully established. In addition, if some data are still
pending for a aborted tunnel, an error is triggered and the server
connection is closed.

To do so, we rely on the H1C_F_WAIT_INPUT flag to bloc the output
processing. This patch contributes to fix the tunnel mode between the H1 and
the H2 muxes.

4 years agoMEDIUM: mux-h2: Close streams when processing data for an aborted tunnel
Christopher Faulet [Fri, 22 Jan 2021 11:13:15 +0000 (12:13 +0100)] 
MEDIUM: mux-h2: Close streams when processing data for an aborted tunnel

In the previous patch ("MEDIUM: mux-h2: Block client data on server side
waiting tunnel establishment"), we added a way to block client data for not
fully established tunnel on the server side. This one closes the stream with
an ERR_CANCEL erorr if there are some pending tunneled data while the tunnel
was aborted. This may happen on the client side if a non-empty DATA frame or
an empty DATA frame without the ES flag is received. This may also happen on
the server side if there is a DATA htx block. However in this last case, we
first wait the response is fully forwarded.

This patch contributes to fix the tunnel mode between the H1 and the H2
muxes.

4 years agoMEDIUM: mux-h2: Block client data on server side waiting tunnel establishment
Christopher Faulet [Fri, 22 Jan 2021 10:59:07 +0000 (11:59 +0100)] 
MEDIUM: mux-h2: Block client data on server side waiting tunnel establishment

On the server side, when a tunnel is not fully established, we must block
tunneled data, waiting for the server response. It is mandatory because the
server may refuse the tunnel. This happens when a DATA htx block is
processed in tunnel mode (H2_SF_BODY_TUNNEL flag set) but before the
response HEADERS frame is received (H2_SF_HEADERS_RCVD flag no set). In this
case, the H2_SF_BLK_MBUSY flag is set to mark the stream as busy. This flag
is removed when the tunnel is fully established or aborted.

This patch contributes to fix the tunnel mode between the H1 and the H2
muxes.

4 years agoMINOR: mux-h2: Add 2 flags to help to properly handle tunnel mode
Christopher Faulet [Fri, 22 Jan 2021 10:46:30 +0000 (11:46 +0100)] 
MINOR: mux-h2: Add 2 flags to help to properly handle tunnel mode

H2_SF_BODY_TUNNEL and H2_SF_TUNNEL_ABRT flags are added to properly handle
the tunnel mode in the H2 mux. The first one is used to detect tunnel
establishment or fully established tunnel. The second one is used to abort a
tunnel attempt. It is the first commit having as a goal to fix tunnel
establishment between H1 and H2 muxes.

There is a subtlety in h2_rcv_buf(). CS_FL_EOS flag is added on the
conn-stream when ES is received on a tunneled stream. It really reflects the
conn-stream state and is mandatory for next commits.

4 years agoMINOR: mux-h1: Split H1C_F_WAIT_OPPOSITE flag to separate input/output sides
Christopher Faulet [Wed, 13 Jan 2021 17:47:57 +0000 (18:47 +0100)] 
MINOR: mux-h1: Split H1C_F_WAIT_OPPOSITE flag to separate input/output sides

The H1C_F_WAIT_OPPOSITE flag is now splitted in 2 flags, H1C_F_WAIT_INPUT
and H1C_F_WAIT_OUTPUT, depending on the side is waiting. The change is a
prerequisite to fix the tunnel mode management in HTTP muxes.

H1C_F_WAIT_INPUT must be used to bloc the output side and to wait for an
event from the input side. H1C_F_WAIT_OUTPUT does the opposite. It bloc the
input side and wait for an event from the output side.

4 years agoMINOR: mux-h1/mux-fcgi: Don't set TUNNEL mode if payload length is unknown
Christopher Faulet [Tue, 8 Dec 2020 09:38:22 +0000 (10:38 +0100)] 
MINOR: mux-h1/mux-fcgi: Don't set TUNNEL mode if payload length is unknown

Responses with no C-L and T-E headers are no longer switched in TUNNEL mode
and remains in DATA mode instead. The H1 and FCGI muxes are updated
accordingly. This change reflects the real message state. It is not a true
tunnel. Data received are still part of the message.

It is not a bug. However, this message may be backported after some
observation period (at least as far as 2.2).

4 years agoBUG/MINOR: h2/mux-h2: Reject 101 responses with a PROTOCOL_ERROR h2s error
Christopher Faulet [Mon, 7 Dec 2020 17:24:43 +0000 (18:24 +0100)] 
BUG/MINOR: h2/mux-h2: Reject 101 responses with a PROTOCOL_ERROR h2s error

As stated in the RFC7540, section 8.1.1, the HTTP/2 removes support for the
101 informational status code. Thus a PROTOCOL_ERROR is now returned to the
server if a 101-switching-protocols response is received. Thus, the server
connection is aborted.

This patch may be backported as far as 2.0.

4 years agoMEDIUM: http-ana: Refuse invalid 101-switching-protocols responses
Christopher Faulet [Fri, 8 Jan 2021 15:02:05 +0000 (16:02 +0100)] 
MEDIUM: http-ana: Refuse invalid 101-switching-protocols responses

A 101-switching-protocols response must contain a Connection header with the
Upgrade option. And this response must only be received from a server if the
client explicitly requested a protocol upgrade. Thus, the request must also
contain a Connection header with the Upgrade option. If not, a
502-bad-gateway response is returned to the client. This way, a tunnel is
only established if both sides are agree.

It is closer to what the RFC says, but it remains a bit flexible because
there is no check on the Upgrade header itself. However, that's probably
enough to ensure a tunnel is not established when not requested.

This one is not tagged as a bug. But it may be backported, at least to
2.3. It relies on :

  * MINOR: htx/http-ana: Save info about Upgrade option in the Connection header

4 years agoMINOR: htx/http-ana: Save info about Upgrade option in the Connection header
Christopher Faulet [Fri, 8 Jan 2021 14:53:01 +0000 (15:53 +0100)] 
MINOR: htx/http-ana: Save info about Upgrade option in the Connection header

Add an HTX start-line flag and its counterpart into the HTTP message to
track the presence of the Upgrade option into the Connection header. This
way, without parsing the Connection header again, it will be easy to know if
a client asks for a protocol upgrade and if the server agrees to do so. It
will also be easy to perform some conformance checks when a
101-switching-protocols is received.

4 years agoBUG/MAJOR: mux-h1: Properly handle TCP to H1 upgrades
Christopher Faulet [Thu, 21 Jan 2021 16:50:19 +0000 (17:50 +0100)] 
BUG/MAJOR: mux-h1: Properly handle TCP to H1 upgrades

It is the second part and the most important of the fix.

Since the mux-h1 refactoring, and more specifically since the commit
c4bfa59f1 ("MAJOR: mux-h1: Create the client stream as later as possible"),
the upgrade from a TCP client connection to H1 is broken. Indeed, now the H1
mux is responsible to create the frontend conn-stream once the request
headers are fully received. But, to properly support TCP to H1 upgrades, we
must inherit from the existing conn-stream. To do so, if the conn-stream
already exists when the client H1 connection is created, we create a H1
stream in ST_ATTACHED state, but not ST_READY, and the conn-stream is
attached to it. Because the ST_READY state is not set, no data are xferred
to the data layer when h1_rcv_buf() is called and shutdowns are inhibited
except on client aborts. This way, the request is parsed the same way than
for a classical H1 connection. Once the request headers are fully received
and parsed, the data stream is upgraded and the ST_READY state is set.

A tricky case appears when an H2 upgrade is performed because the H2 preface
is matched. In this case, the conn-stream must be detached and destroyed
before switching to the H2 mux and releasing the current H1 mux. We must
also take care to detach and destroy the conn-stream when a timeout
occurres.

This patch relies on the following series of patches :

* BUG/MEDIUM: stream: Don't immediatly ack the TCP to H1 upgrades
* MEDIUM: http-ana: Do nothing in wait-for-request analyzer if not htx
* MINOR: stream: Add a function to validate TCP to H1 upgrades
* MEDIUM: mux-h1: Add ST_READY state for the H1 connections
* MINOR: mux-h1: Wake up instead of subscribe for reads after H1C creation
* MINOR: mux-h1: Try to wake up data layer first before calling its wake callback
* MINOR: stream-int: Take care of EOS in the SI wake callback function
* BUG/MINOR: stream: Don't update counters when TCP to H2 upgrades are performed

This fix is specific for 2.4. No backport needed.

4 years agoBUG/MEDIUM: stream: Don't immediatly ack the TCP to H1 upgrades
Christopher Faulet [Thu, 21 Jan 2021 16:31:04 +0000 (17:31 +0100)] 
BUG/MEDIUM: stream: Don't immediatly ack the TCP to H1 upgrades

Instead of switching the stream to HTX mode, the request channel is only
reset (the request buffer is xferred to the mux) and the SF_IGNORE flag is
set on the stream. This flag prevent any processing in case of abort. Once
the upgrade confirmed, the flag is removed, in stream_upgrade_from_cs().

It is only the first part of the fix. The next one ("BUG/MAJOR: mux-h1:
Properly handle TCP to H1 upgrades") is also required. Both rely on the
following series of patches :

* MEDIUM: http-ana: Do nothing in wait-for-request analyzer if not htx
* MINOR: stream: Add a function to validate TCP to H1 upgrades
* MEDIUM: mux-h1: Add ST_READY state for the H1 connections
* MINOR: mux-h1: Wake up instead of subscribe for reads after H1C creation
* MINOR: mux-h1: Try to wake up data layer first before calling its wake callback
* MINOR: stream-int: Take care of EOS in the SI wake callback function
* BUG/MINOR: stream: Don't update counters when TCP to H2 upgrades are performed

This fix is specific for 2.4. No backport needed.

4 years agoMEDIUM: http-ana: Do nothing in wait-for-request analyzer if not htx
Christopher Faulet [Thu, 21 Jan 2021 16:32:58 +0000 (17:32 +0100)] 
MEDIUM: http-ana: Do nothing in wait-for-request analyzer if not htx

If http_wait_for_request() analyzer is called with a non-htx stream, nothing
is performed and we return immediatly. For now, it is totally unexpected.
But it will be true during TCP to H1 upgrades, once fixed. Indeed, there
will be a transition period during these upgrades. First the mux will be
upgraded and the not the stream, and finally the stream will be upgraded by
the mux once ready. In the meantime, the stream will still be in raw
mode. Nothing will be performed in wait-for-request analyzer because it will
be the mux responsibility to handle errors.

This patch is required to fix the TCP to H1 upgrades.

4 years agoMINOR: stream: Add a function to validate TCP to H1 upgrades
Christopher Faulet [Thu, 21 Jan 2021 16:36:12 +0000 (17:36 +0100)] 
MINOR: stream: Add a function to validate TCP to H1 upgrades

TCP to H1 upgrades are buggy for now. When such upgrade is performed, a
crash is experienced. The bug is the result of the recent H1 mux
refactoring, and more specifically because of the commit c4bfa59f1 ("MAJOR:
mux-h1: Create the client stream as later as possible"). Indeed, now the H1
mux is responsible to create the frontend conn-stream once the request
headers are fully received. Thus the TCP to H1 upgrade is a problem because
the frontend conn-stream already exists.

To fix the bug, we must keep this conn-stream and the associate stream and
use it in the H1 mux. To do so, the upgrade will be performed in two
steps. First, the mux is upgraded from mux-pt to mux-h1. Then, the mux-h1
performs the stream upgrade, once the request headers are fully received and
parsed. To do so, stream_upgrade_from_cs() must be used. This function set
the SF_HTX flags to switch the stream to HTX mode, it removes the SF_IGNORE
flags and eventually it fills the request channel with some input data.

This patch is required to fix the TCP to H1 upgrades and is intimately
linked with the next commits.

4 years agoMEDIUM: mux-h1: Add ST_READY state for the H1 connections
Christopher Faulet [Thu, 21 Jan 2021 16:44:35 +0000 (17:44 +0100)] 
MEDIUM: mux-h1: Add ST_READY state for the H1 connections

An alive H1 connection may be in one of these 3 states :

  * ST_IDLE : not active and is waiting to be reused (no h1s and no cs)
  * ST_EMBRYONIC : active with a h1s but without any cs
  * ST_ATTACHED : active with a h1s and a cs

ST_IDLE and ST_ATTACHED are possible for frontend and backend
connection. ST_EMBRYONIC is only possible on the client side, when we are
waiting for the request headers. The last one is the expected state for an
active connection processing data. These states are mutually exclusives.

Now, there is a new state, ST_READY. It may only be set if ST_ATTACHED is
also set and when the CS is considered as fully active. For now, ST_READY is
set in the same time of ST_ATTACHED. But it will be used to fix TCP to H1
upgrades. Idea is to have an H1 connection in ST_ATTACHED state but not
ST_READY yet and have more or less the same behavior than an H1 connection
in ST_EMBRYONIC state. And when the upgrade is fully achieved, the ST_READY
state may be set and the data layer may be notified accordingly.

So for now, this patch should not change anything. TCP to H1 upgrades are
still buggy. But it is mandatory to make it work properly.

4 years agoMINOR: mux-h1: Wake up H1C after its creation if input buffer is not empty
Christopher Faulet [Thu, 21 Jan 2021 16:45:45 +0000 (17:45 +0100)] 
MINOR: mux-h1: Wake up H1C after its creation if input buffer is not empty

When a H1 connection is created, we now wakeup the H1C tasklet if there are
some data in the input buffer. If not we only subscribe for reads.

This patch is required to fix the TCP to H1 upgrades.

4 years agoMINOR: mux-h1: Try to wake up data layer first before calling its wake callback
Christopher Faulet [Thu, 21 Jan 2021 16:49:01 +0000 (17:49 +0100)] 
MINOR: mux-h1: Try to wake up data layer first before calling its wake callback

Instead of calling the data layer wake callback function, we now first try
to wake it up. If the data layer is subscribed for receives or for sends,
its tasklet is woken up. The wake callback function is only called as the
last chance to notify the data layer.

4 years agoMEDIUM: stream-int: Take care of EOS if the SI wake callback function
Christopher Faulet [Thu, 21 Jan 2021 15:22:01 +0000 (16:22 +0100)] 
MEDIUM: stream-int: Take care of EOS if the SI wake callback function

Because si_cs_process() is also the SI wake callback function, it may be
called from the mux layer. Thus, in such cases, it is performed outside any
I/O event and si_cs_recv() is not called. If a read0 is reported by the mux,
via the CS_FL_EOS flag, the event is not handled, because only si_cs_recv()
take care of this flag for now.

It is not a bug, because this does not happens for now. All muxes set this
flag when the data layer retrieve data (via mux->rcv_buf()). But it is safer
to be prepared to handle it from the wake callback. And in fact, it will be
useful to fix the HTTP upgrades of TCP connections (especially TCP>H1>H2
upgrades).

To be sure to not handle the same event twice, it is only handled if the
shutr is not already set on the input channel.

4 years agoREGTESTS: set_ssl_server_cert.vtc: check the sha1 from the server
William Lallemand [Thu, 28 Jan 2021 15:00:22 +0000 (16:00 +0100)] 
REGTESTS: set_ssl_server_cert.vtc: check the sha1 from the server

Check the sha1 from the server side with the sample ssl_c_sha1 sample
fetch in order to evict a possible problem with "show/set ssl cert".

4 years agoREGTESTS: set_ssl_server_cert.vtc: check the Sha1 Fingerprint
William Lallemand [Thu, 28 Jan 2021 13:59:19 +0000 (14:59 +0100)] 
REGTESTS: set_ssl_server_cert.vtc: check the Sha1 Fingerprint

Check the sha1 fingerprint once the certificate was changed with "show
ssl cert". This way the test is more reliable.

4 years agoREGTESTS: set_ssl_server_cert.vtc: remove the abort command
William Lallemand [Thu, 28 Jan 2021 13:56:31 +0000 (14:56 +0100)] 
REGTESTS: set_ssl_server_cert.vtc: remove the abort command

Temporarily remove the abort command as it seems to cause problems when
trying to do a "show ssl cert" after it.

4 years agoBUG/MEDIUM: backend: never reuse a connection for tcp mode
Amaury Denoyelle [Tue, 26 Jan 2021 16:35:46 +0000 (17:35 +0100)] 
BUG/MEDIUM: backend: never reuse a connection for tcp mode

The reuse of idle connections should only happen for a proxy with the
http mode. In case of a backend with the tcp mode, the reuse selection
and insertion in session list are skipped.

This behavior is present since commit :
MEDIUM: connection: Add private connections synchronously in session server list
It could also be further exagerated by :
MEDIUM: backend: add reused conn to sess if mux marked as HOL blocking

It can be backported up to 2.3.

4 years agoBUG/MEDIUM: session: only retrieve ready idle conn from session
Amaury Denoyelle [Tue, 26 Jan 2021 13:14:37 +0000 (14:14 +0100)] 
BUG/MEDIUM: session: only retrieve ready idle conn from session

A bug was introduced by the early insertion of idle connections at the
end of connect_server. It is possible to reuse a connection not yet
ready waiting for an handshake (for example with proxy protocol or ssl).
A wrong duplicate xprt_handshake_io_cb tasklet is thus registered as a
side-effect.

This triggers the BUG_ON statement of xprt_handshake_subscribe :
    BUG_ON(ctx->subs && ctx->subs != es);

To counter this, a check is now present in session_get_conn to only
return a connection without the flag CO_FL_WAIT_XPRT. This might cause
sometimes the creation of dedicated server connections when in theory
reuse could have been used, but probably only occurs rarely in real
condition.

This behavior is present since commit :
    MEDIUM: connection: Add private connections synchronously in session server list
It could also be further exagerated by :
    MEDIUM: backend: add reused conn to sess if mux marked as HOL blocking

It can be backported up to 2.3.

NOTE : This bug seems to be only reproducible with mode tcp, for an
unknown reason. However, reuse should never happen when not in http
mode. This improper behavior will be the subject of a dedicated patch.

This bug can easily be reproducible with the following config (a
webserver is required to accept proxy protocol on port 31080) :

    global

    defaults
      mode tcp
      timeout connect 1s
      timeout server 1s
      timeout client 1s

    listen li
      bind 0.0.0.0:4444
      server bla1 127.0.0.1:31080 check send-proxy-v2

with the inject client :
    $ inject -u 10000 -d 10 -G 127.0.0.1:4444

This should fix the github issue #1058.

4 years agoBUG/MINOR: ssl: init tmp chunk correctly in ssl_sock_load_sctl_from_file()
William Lallemand [Wed, 27 Jan 2021 13:58:51 +0000 (14:58 +0100)] 
BUG/MINOR: ssl: init tmp chunk correctly in ssl_sock_load_sctl_from_file()

Use chunk_inistr() for a chunk initialisation in
ssl_sock_load_sctl_from_file() instead of a manual initialisation which
was not initialising head.

Fix issue #1073.

Must be backported as far as 2.2

4 years agoCLEANUP: ssl: remove dead code in ckch_inst_new_load_srv_store()
William Lallemand [Wed, 27 Jan 2021 13:42:40 +0000 (14:42 +0100)] 
CLEANUP: ssl: remove dead code in ckch_inst_new_load_srv_store()

The new ckch_inst_new_load_srv_store() function which mimics the
ckch_inst_new_load_store() function includes some dead code which was
used only in the former function.

Fix issue #1081.

4 years agoBUG/MINOR: stats: Add a break after filling ST_F_MODE field for servers
Christopher Faulet [Wed, 27 Jan 2021 12:32:25 +0000 (13:32 +0100)] 
BUG/MINOR: stats: Add a break after filling ST_F_MODE field for servers

The previous patch was pushed too quickly (399bf72f6 "BUG/MINOR: stats:
Remove a break preventing ST_F_QCUR to be set for servers"). It was not an
extra break but a misplaced break statement. Thus, now a break statement
must be added after filling the ST_F_MODE field in stats_fill_sv_stats().

No backport needed except if the above commit is backported.

4 years agoBUG/MINOR: stats: Remove a break preventing ST_F_QCUR to be set for servers
Christopher Faulet [Wed, 27 Jan 2021 11:48:32 +0000 (12:48 +0100)] 
BUG/MINOR: stats: Remove a break preventing ST_F_QCUR to be set for servers

There is an extra break statement wrongly placed in stats_fill_sv_stats()
function, just before filling the ST_F_QCUR field. It prevents this field to
be set to the right value for servers.

No backport needed except if commit 3a9a4992 ("MEDIUM: stats: allow to
select one field in `stats_fill_sv_stats`") is backported.

4 years agoCI: Fix DEBUG_STRICT definition for Coverity
Tim Duesterhus [Tue, 26 Jan 2021 18:24:25 +0000 (19:24 +0100)] 
CI: Fix DEBUG_STRICT definition for Coverity

The DEBUG_STRICT define needs to be passed as part of `DEBUG`, not as a bare
parameter.

4 years agoBUILD: Include stdlib.h in compiler.h if DEBUG_USE_ABORT is set
Tim Duesterhus [Tue, 26 Jan 2021 18:24:24 +0000 (19:24 +0100)] 
BUILD: Include stdlib.h in compiler.h if DEBUG_USE_ABORT is set

Building with `"DEBUG=-DDEBUG_STRICT=1 -DDEBUG_USE_ABORT=1"` previously emitted the warning:

    In file included from include/haproxy/api.h:35:0,
                     from src/mux_pt.c:13:
    include/haproxy/buf.h: In function ‘br_init’:
    include/haproxy/bug.h:42:90: warning: implicit declaration of function ‘abort’ [-Wimplicit-function-declaration]
     #define ABORT_NOW() do { extern void ha_backtrace_to_stderr(); ha_backtrace_to_stderr(); abort(); } while (0)
                                                                                              ^
    include/haproxy/bug.h:56:21: note: in expansion of macro ‘ABORT_NOW’
     #define CRASH_NOW() ABORT_NOW()
                         ^
    include/haproxy/bug.h:68:4: note: in expansion of macro ‘CRASH_NOW’
        CRASH_NOW();                                           \
        ^
    include/haproxy/bug.h:62:35: note: in expansion of macro ‘__BUG_ON’
     #define _BUG_ON(cond, file, line) __BUG_ON(cond, file, line)
                                       ^
    include/haproxy/bug.h:61:22: note: in expansion of macro ‘_BUG_ON’
     #define BUG_ON(cond) _BUG_ON(cond, __FILE__, __LINE__)
                          ^
    include/haproxy/buf.h:875:2: note: in expansion of macro ‘BUG_ON’
      BUG_ON(size < 2);
      ^

This patch fixes that issue. The `DEBUG_USE_ABORT` option exists for use with
static analysis tools. No backport needed.

4 years agoCLEANUP: ssl: make load_srv_{ckchs,cert} match their bind counterpart
William Lallemand [Tue, 26 Jan 2021 11:01:46 +0000 (12:01 +0100)] 
CLEANUP: ssl: make load_srv_{ckchs,cert} match their bind counterpart

This patch makes things more consistent between the bind_conf functions
and the server ones:

- ssl_sock_load_srv_ckchs() loads the SSL_CTX in the server
  (ssl_sock_load_ckchs() load the SNIs in the bind_conf)

- add the server parameter to ssl_sock_load_srv_ckchs()

- changes made to the ckch_inst are done in
  ckch_inst_new_load_srv_store()

4 years agoCLEANUP: ssl: remove SSL_CTX function parameter
William Lallemand [Tue, 26 Jan 2021 10:27:42 +0000 (11:27 +0100)] 
CLEANUP: ssl: remove SSL_CTX function parameter

Since the server SSL_CTX is now stored in the ckch_inst, it is not
needed anymore to pass an SSL_CTX to ckch_inst_new_load_srv_store() and
ssl_sock_load_srv_ckchs().

4 years agoCLEANUP: ssl/cli: rework free in cli_io_handler_commit_cert()
William Lallemand [Tue, 26 Jan 2021 09:18:57 +0000 (10:18 +0100)] 
CLEANUP: ssl/cli: rework free in cli_io_handler_commit_cert()

The new feature allowing the change of server side certificates
introduced duplicated free code. Rework the code in
cli_io_handler_commit_cert() to be more consistent.

4 years agoMINOR: ssl: Remove client_crt member of the server's ssl context
Remi Tricot-Le Breton [Mon, 25 Jan 2021 16:19:45 +0000 (17:19 +0100)] 
MINOR: ssl: Remove client_crt member of the server's ssl context

The client_crt member is not used anymore since the server's ssl context
initialization now behaves the same way as the bind lines one (using
ckch stores and instances).

4 years agoMEDIUM: ssl: Enable backend certificate hot update
Remi Tricot-Le Breton [Mon, 25 Jan 2021 16:19:44 +0000 (17:19 +0100)] 
MEDIUM: ssl: Enable backend certificate hot update

When trying to update a backend certificate, we should find a
server-side ckch instance thanks to which we can rebuild a new ssl
context and a new ckch instance that replace the previous ones in the
server structure. This way any new ssl session will be built out of the
new ssl context and the newly updated certificate.

This resolves a subpart of GitHub issue #427 (the certificate part)

4 years agoMEDIUM: ssl: Load client certificates in a ckch for backend servers
Remi Tricot-Le Breton [Mon, 25 Jan 2021 16:19:43 +0000 (17:19 +0100)] 
MEDIUM: ssl: Load client certificates in a ckch for backend servers

In order for the backend server's certificate to be hot-updatable, it
needs to fit into the implementation used for the "bind" certificates.
This patch follows the architecture implemented for the frontend
implementation and reuses its structures and general function calls
(adapted for the server side).
The ckch store logic is kept and a dedicated ckch instance is used (one
per server). The whole sni_ctx logic was not kept though because it is
not needed.
All the new functions added in this patch are basically server-side
copies of functions that already exist on the frontend side with all the
sni and bind_cond references removed.
The ckch_inst structure has a new 'is_server_instance' flag which is
used to distinguish regular instances from the server-side ones, and a
new pointer to the server's structure in case of backend instance.
Since the new server ckch instances are linked to a standard ckch_store,
a lookup in the ckch store table will succeed so the cli code used to
update bind certificates needs to be covered to manage those new server
side ckch instances.

4 years agoMINOR: ssl: Certificate chain loading refactorization
Remi Tricot-Le Breton [Mon, 25 Jan 2021 16:19:42 +0000 (17:19 +0100)] 
MINOR: ssl: Certificate chain loading refactorization

Move the certificate chain loading code into a dedicated function that
will then be useable elsewhere.

4 years agoMINOR: ssl: Server ssl context prepare function refactoring
Remi Tricot-Le Breton [Mon, 25 Jan 2021 16:19:41 +0000 (17:19 +0100)] 
MINOR: ssl: Server ssl context prepare function refactoring

Split the server's ssl context initialization into the general ssl
related initializations and the actual initialization of a single
SSL_CTX structure. This way the context's initialization will be
usable by itself from elsewhere.

4 years agoREORG: backend: simplify conn_backend_get
Amaury Denoyelle [Tue, 26 Jan 2021 13:35:26 +0000 (14:35 +0100)] 
REORG: backend: simplify conn_backend_get

Reorganize the conditions for the reuse of idle/safe connections :
- reduce code by using variable to store reuse mode and idle/safe conns
  counts
- consider that idle/safe/avail lists are properly allocated if
  max_idle_conns not null. An allocation failure prevents haproxy
  startup.

4 years agoCLEANUP: backend: remove an obsolete comment on conn_backend_get
Amaury Denoyelle [Tue, 26 Jan 2021 13:35:25 +0000 (14:35 +0100)] 
CLEANUP: backend: remove an obsolete comment on conn_backend_get

This comment was valid for haproxy 1.8 but now it is obsolete.

4 years agoCLEANUP: srv: fix comment for pool-max-conn
Amaury Denoyelle [Tue, 26 Jan 2021 13:35:24 +0000 (14:35 +0100)] 
CLEANUP: srv: fix comment for pool-max-conn

Adjust comment for the unlimited value of pool-max-conn which is -1.

4 years agoMINOR: reg-tests: add http-reuse test
Amaury Denoyelle [Tue, 26 Jan 2021 13:35:23 +0000 (14:35 +0100)] 
MINOR: reg-tests: add http-reuse test

Add a serie of 4 tests for the various http-reuse modes : never, safe,
aggressive and always.

4 years agoBUG/MINOR: config: fix leak on proxy.conn_src.bind_hdr_name
Amaury Denoyelle [Tue, 26 Jan 2021 13:35:22 +0000 (14:35 +0100)] 
BUG/MINOR: config: fix leak on proxy.conn_src.bind_hdr_name

Leak for parsing of option usesrc of the source keyword.

This can be backported to 1.8.

4 years agoBUG/MEDIUM: filters/htx: Fix data forwarding when payload length is unknown
Christopher Faulet [Mon, 25 Jan 2021 11:02:00 +0000 (12:02 +0100)] 
BUG/MEDIUM: filters/htx: Fix data forwarding when payload length is unknown

It is only a problem on the response path because the request payload length
it always known. But when a filter is registered to analyze the response
payload, the filtering may hang if the server closes just after the headers.

The root cause of the bug comes from an attempt to allow the filters to not
immediately forward the headers if necessary. A filter may choose to hold
the headers by not forwarding any bytes of the payload. For a message with
no payload but a known payload length, there is always a EOM block to
forward. Thus holding the EOM block for bodyless messages is a good way to
also hold the headers. However, messages with an unknown payload length,
there is no EOM block finishing the message, but only a SHUTR flag on the
channel to mark the end of the stream. If there is no payload when it
happens, there is no payload at all to forward. In the filters API, it is
wrongly detected as a condition to not forward the headers.

Because it is not the most used feature and not the obvious one, this patch
introduces another way to hold the message headers at the begining of the
forwarding. A filter flag is added to explicitly says the headers should be
hold. A filter may choose to set the STRM_FLT_FL_HOLD_HTTP_HDRS flag and not
forwad anything to hold the headers. This flag is removed at each call, thus
it must always be explicitly set by filters. This flag is only evaluated if
no byte has ever been forwarded because the headers are forwarded with the
first byte of the payload.

reg-tests/filters/random-forwarding.vtc reg-test is updated to also test
responses with unknown payload length (with and without payload).

This patch must be backported as far as 2.0.