(This deprecates the :transport_options option)
This should be given an array of peer addresses to connect to. It can be
used when the destination IPs are known and you want to avoid resolving
them, and when the destination is a unix socket (and the destination is
a FS path)
connections which either already contain addresses, or were given an
open IO object, should be marked as resolved, and should not go through
the resolver.
session
In order not to leak these into other sessions, one keeps a registry
around as a session option. This will cascade into the request and
response encoding routines.
this is achieved by a rework of the upgrade plugin, and the addition of
an h2 upgrade plugin. The idea is the following: if a response carries
an Upgrade header, and there's a handler for it, we should go for it.
The difference is:
* when the response is 101, this means that the negotiation must take
place before the actual response comes in;
* when the response is 200, upgrading means reconnecting to the channel,
and assume the new protocol for subsequent requests only.
connection
After the connection has been upgraded and session is kept open,
subsequent requests were still trying to upgrade it. This fixes it by
marking the connection as upgraded, and falling back to normal
behaviour when it is.
By setting the h2c protocol handler, the rest became much simpler.
Formatting the upgrade request is a matter for the sub-plugin.
Therefore, the specific h2c request upgrade headers are built-in there.
It was observed that, during a request done via a DoH resolve, the
resolver connection is left in the selector, despite already having
resolved the name, until the whole transfer is done. This is
inefficient, as we're not expected to use it again.
Fixed by improvinng the interest calculation of an HTTP/2 connection; if
the connection doesn't have anything to write. and there aren't any
inflight streams nor pings, connection won't be listened on.
Some debugging surfaced that the resolving step of doh contains 2
registered connections in the selector, instead of just one. That's
because both the resolver and its inherent connection are registered.
Fixed it by marking the resolver as closed, in the same way we do for
the system resolver, which also nnever gets registered in the selector.
created a test server which removes the content-length. Taken extra
condition into account, that the close might manifest itself while
selecting on the socket; at that point we're out of the consumption
loop, so better not to deal with throwing :called
The Errno::INPROGRESS error signals that the TCP handshake has been
signaled to the peer already, by which locally we just have wait for it
to be writable.
For simple plaintext requests, this was working correctly, because the
interest was always writable no matter what. However, when wrapped in
the SSL conn, and with the OS tcp stack under more stress, the interest
could be switched to readable, and by reuse, never reset; if, by
subsequent reconnection, EINPROGRESS would be emitted, the socket would
wait for readable instead, resulting in a loop and subsequent
connectionnn timeout.
although a connection might correctly emit an error response, the
returned responses are still defined by the fetch_response loop in the
session. When the pool is actually empty, this had the side-effect of
leaving error responses behind and exiting with just the first one.
This fixes it popping all available responses in such cases.
in some cases where the client is sending a request with a lot of bytes
(i.e. file uploads), and the server can't consume it (because
authorization, or wrong endpoint), the server stops processing the
request altogether and sends an error response immediately, in which
case the client should pivot and read the error response. Not doing this
was causing the Errno::EPIPE error. The mitigation is therefore to
rescue the error, and mark the consumption loop to read the response
immediately.
if a response does not advertise its body length, then the server closes
the connection when there's no more data to read. Therefore, the
HTTP/1.1 parser should interpret these conditions accordingly, and
emit the response.
Closes#114