<feed xmlns='http://www.w3.org/2005/Atom'>
<title>delta/haproxy.git, branch 20210122-fix-tcp-to-h1-upgrade-1</title>
<subtitle>github.com: haproxy/haproxy.git
</subtitle>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/haproxy.git/'/>
<entry>
<title>BUG/MAJOR: mux-h1: Properly handle TCP to H1 upgrades</title>
<updated>2021-01-26T14:00:18+00:00</updated>
<author>
<name>Christopher Faulet</name>
<email>cfaulet@haproxy.com</email>
</author>
<published>2021-01-21T16:50:19+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/haproxy.git/commit/?id=0bf8f6ea030a9ef7abaf90924be7d4e3852e0261'/>
<id>0bf8f6ea030a9ef7abaf90924be7d4e3852e0261</id>
<content type='text'>
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.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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.
</pre>
</div>
</content>
</entry>
<entry>
<title>BUG/MEDIUM: stream: Don't immediatly ack the TCP to H1 upgrades</title>
<updated>2021-01-26T14:00:18+00:00</updated>
<author>
<name>Christopher Faulet</name>
<email>cfaulet@haproxy.com</email>
</author>
<published>2021-01-21T16:31:04+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/haproxy.git/commit/?id=5d47ef87e56d7e88f976ccd9d97e4b6ebd72df08'/>
<id>5d47ef87e56d7e88f976ccd9d97e4b6ebd72df08</id>
<content type='text'>
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.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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.
</pre>
</div>
</content>
</entry>
<entry>
<title>MEDIUM: http-ana: Do nothing in wait-for-request analyzer if not htx</title>
<updated>2021-01-26T14:00:18+00:00</updated>
<author>
<name>Christopher Faulet</name>
<email>cfaulet@haproxy.com</email>
</author>
<published>2021-01-21T16:32:58+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/haproxy.git/commit/?id=ff4dc825fe7528ae0387509626eb0e7b414badb4'/>
<id>ff4dc825fe7528ae0387509626eb0e7b414badb4</id>
<content type='text'>
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.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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.
</pre>
</div>
</content>
</entry>
<entry>
<title>MINOR: stream: Add a function to validate TCP to H1 upgrades</title>
<updated>2021-01-26T14:00:18+00:00</updated>
<author>
<name>Christopher Faulet</name>
<email>cfaulet@haproxy.com</email>
</author>
<published>2021-01-21T16:36:12+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/haproxy.git/commit/?id=37269e9a00e1fb5417e2148c7a39e06c3f61d4e7'/>
<id>37269e9a00e1fb5417e2148c7a39e06c3f61d4e7</id>
<content type='text'>
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.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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.
</pre>
</div>
</content>
</entry>
<entry>
<title>MEDIUM: mux-h1: Add ST_READY state for the H1 connections</title>
<updated>2021-01-26T14:00:18+00:00</updated>
<author>
<name>Christopher Faulet</name>
<email>cfaulet@haproxy.com</email>
</author>
<published>2021-01-21T16:44:35+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/haproxy.git/commit/?id=20938af387d016cf6ca81dd74ef6613865500626'/>
<id>20938af387d016cf6ca81dd74ef6613865500626</id>
<content type='text'>
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.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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.
</pre>
</div>
</content>
</entry>
<entry>
<title>MINOR: mux-h1: Wake up instead of subscribe for reads after H1C creation</title>
<updated>2021-01-26T14:00:18+00:00</updated>
<author>
<name>Christopher Faulet</name>
<email>cfaulet@haproxy.com</email>
</author>
<published>2021-01-21T16:45:45+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/haproxy.git/commit/?id=23d0b3b9cb92f21927231bc43f6c90e6654c456d'/>
<id>23d0b3b9cb92f21927231bc43f6c90e6654c456d</id>
<content type='text'>
When a H1 connection is created, we now wakeup the H1C tasklet instead of
subscribing for reads. In addtion, it is now also performed if there are
some data in the input buffer.

This patch is required to fix the TCP to H1 upgrades.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
When a H1 connection is created, we now wakeup the H1C tasklet instead of
subscribing for reads. In addtion, it is now also performed if there are
some data in the input buffer.

This patch is required to fix the TCP to H1 upgrades.
</pre>
</div>
</content>
</entry>
<entry>
<title>MINOR: mux-h1: Try to wake up data layer first before calling its wake callback</title>
<updated>2021-01-26T14:00:18+00:00</updated>
<author>
<name>Christopher Faulet</name>
<email>cfaulet@haproxy.com</email>
</author>
<published>2021-01-21T16:49:01+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/haproxy.git/commit/?id=7d00d526035688e4fe2e6f2bd65c9df4caca6ee0'/>
<id>7d00d526035688e4fe2e6f2bd65c9df4caca6ee0</id>
<content type='text'>
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.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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.
</pre>
</div>
</content>
</entry>
<entry>
<title>MINOR: stream-int: Take care of EOS in the SI wake callback function</title>
<updated>2021-01-26T14:00:18+00:00</updated>
<author>
<name>Christopher Faulet</name>
<email>cfaulet@haproxy.com</email>
</author>
<published>2021-01-21T15:22:01+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/haproxy.git/commit/?id=d7cd4a08d1f3f84bd67a2a6cc68650bdd56c929f'/>
<id>d7cd4a08d1f3f84bd67a2a6cc68650bdd56c929f</id>
<content type='text'>
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-&gt;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&gt;H1&gt;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.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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-&gt;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&gt;H1&gt;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.
</pre>
</div>
</content>
</entry>
<entry>
<title>REORG: backend: simplify conn_backend_get</title>
<updated>2021-01-26T13:48:39+00:00</updated>
<author>
<name>Amaury Denoyelle</name>
<email>adenoyelle@haproxy.com</email>
</author>
<published>2021-01-26T13:35:26+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/haproxy.git/commit/?id=7f68d815af356fbe1b2e1080a88b9935581c91d2'/>
<id>7f68d815af356fbe1b2e1080a88b9935581c91d2</id>
<content type='text'>
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.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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.
</pre>
</div>
</content>
</entry>
<entry>
<title>CLEANUP: backend: remove an obsolete comment on conn_backend_get</title>
<updated>2021-01-26T13:48:39+00:00</updated>
<author>
<name>Amaury Denoyelle</name>
<email>adenoyelle@haproxy.com</email>
</author>
<published>2021-01-26T13:35:25+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/haproxy.git/commit/?id=37e25bcd1e2cf9beb6d976f52b79a4721ecd679f'/>
<id>37e25bcd1e2cf9beb6d976f52b79a4721ecd679f</id>
<content type='text'>
This comment was valid for haproxy 1.8 but now it is obsolete.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This comment was valid for haproxy 1.8 but now it is obsolete.
</pre>
</div>
</content>
</entry>
</feed>
