Willy Tarreau [Fri, 14 Dec 2018 10:35:36 +0000 (11:35 +0100)]
MINOR: backend: count the number of connect and reuse per server and per backend
Sadly we didn't have the cumulated number of connections established to
servers till now, so let's now update it per backend and per-server and
report it in the stats. On the stats page it appears in the tooltip
when hovering over the total sessions count field.
Willy Tarreau [Fri, 14 Dec 2018 09:59:15 +0000 (10:59 +0100)]
MINOR: mux_h1/h2: simplify the zero-copy Rx alignment
The transpory layer now respects buffer alignment, so we don't need to
cheat anymore pretending we have some data at the head, adjusting the
buffer's head is enough.
Willy Tarreau [Fri, 14 Dec 2018 09:51:23 +0000 (10:51 +0100)]
MINOR: connection: realign empty buffers in muxes, not transport layers
For a long time we've been realigning empty buffers in the transport
layers, where the I/Os were performed based on callbacks. Doing so is
optimal for higher data throughput but makes it trickier to optimize
unaligned data, where mux_h1/h2 have to claim some data are present
in the buffer to force unaligned accesses to skip the frame's header
or the chunk header.
We don't need to do this anymore since the I/O calls are now always
performed from top to bottom, so it's only the mux's responsibility
to realign an empty buffer if it wants to.
In practice it doesn't change anything, it's just a convention, and
it will allow the code to be simplified in a next patch.
Willy Tarreau [Fri, 14 Dec 2018 09:19:28 +0000 (10:19 +0100)]
BUG/MEDIUM: cache: fix random crash on filter parser's error path
The cconf variable was not initialized before the two first possible
error exits before being freed, resulting in random crashes instead
of displaying an error message if the cache ID was missing from the
filter declaration.
Willy Tarreau [Fri, 14 Dec 2018 08:51:48 +0000 (09:51 +0100)]
REGTEST: http-messaging: add "option http-buffer-request" for H2 tests
These tests upload contents and randomly make the server start to
respond before the client finishes to upload data, making the test
occasionally fail. Waiting for a body in the server doesn't always
work, depending on the method or how the data are advertised. Thus,
let's ask haproxy to wait for the request using the aforementioned
option, it guarantees that the DATA frame is sent before the response
HEADERS frame is delivered.
Willy Tarreau [Fri, 14 Dec 2018 07:33:28 +0000 (08:33 +0100)]
MINOR: lb: make the leastconn algorithm more accurate
The leastconn algorithm queues available servers based on their weighted
current load. But this results in an inaccurate load balancing when weights
differ and the load is very low, because what matters is not the load before
picking the server but the load resulting from picking the server. At the
very least, it must be granted that servers with the highest weight are
always picked first when no server has any connection.
This patch addresses this by simply adding one to the current connections
count when queuing the server, since this is the load the server will have
once picked. This finally allows to bridge the gap that existed between
the "leastconn" and the "first" algorithms.
Willy Tarreau [Thu, 13 Dec 2018 18:35:29 +0000 (19:35 +0100)]
REGTEST: add a few HTTP messaging tests
These tests send GET/HEAD/POST requests in H1 and H2, with and without
HTX, with and without a body, and verify that the behaviour is the expected
one. For now HEAD requests have been commented out because in H1 they are
not really testable as varnishtest expects to read a body, and in H2 the
behaviour depends on HTX/legacy, indicating a bug in haproxy (it looks
like we can deliver some data in response to HEAD in legacy mode).
Add a new target to the Makefile named "reg-tests-help" to have an idea
about how to run the reg tests from haproxy Makefile.
Handle list of levels and lists of level range passed to make with LEVEL variable.
New supported syntax:
LEVEL=1,4 make reg-tests
LEVEL=1-2,5-6 make reg-tests
Add two new levels 5 and 6. 5 is for broken script, 6 for experimental scripts.
Olivier Houchard [Thu, 13 Dec 2018 17:46:22 +0000 (18:46 +0100)]
MEDIUM: htx: Try to take a connection over if it has no owner.
In the mux detach function, when using HTX, take the connection over if
it no longer has an owner (ie because the session that was the owner left).
It is done for legacy code in proto_http.c, but not for HTX.
Also when using HTX, in H2, try to add the connection back to idle_conns if
it was not already (ie we used to use all the available streams, and we're
freeing one). That too was done in proto_http.c.
Olivier Houchard [Thu, 13 Dec 2018 17:01:00 +0000 (18:01 +0100)]
BUG/MEDIUM: connections: Don't attempt to reuse an unusable connection.
Before trying to add a connection to the idle list, make sure it doesn't
have the error, the shutr or the shutw flag. If any of them is present,
don't bother trying to recycle the connection, it's going to be destroyed
anyway.
BUG/MEDIUM: mux-h1: Fix loop if server closes its connection with unparsed data
A first patch was pushed to fix this bug if it happens during the headers
parsing. But it is also possible to hit the bug during the parsing of
chunks. For instance, if the server sends only part of the trailers, some data
remains unparsed. So it the server closes its connection without sending the end
of the response, we fall back again into an infinite loop.
The fix contains in 2 parts. First, we block the receive if a read0 or an error
is detected on the connection, independently if the input buffer is empty or
not. Then, the flags CS_FL_RCV_MORE and CL_FL_WANT_ROOM are always reset when
input data are processed. We set them again only when necessary.
Olivier Houchard [Tue, 11 Dec 2018 15:47:14 +0000 (16:47 +0100)]
MEDIUM: mux: Add an optional "reset" method.
Add a new method to mux, "reset", that is used to let the mux know the
connection attempt failed, and we're about to retry, so it just have to
reinit itself. Currently only the H1 mux needs it.
Olivier Houchard [Thu, 13 Dec 2018 14:40:16 +0000 (15:40 +0100)]
BUG/MEDIUM: connection: Just make sure we closed the fd on connection failure.
When the connection failed, we don't really want to close the conn_stream,
as we're probably about to retry, so just make sure the file descriptor is
closed.
Olivier Houchard [Thu, 13 Dec 2018 14:38:16 +0000 (15:38 +0100)]
BUG/MEDIUM: stream_interface: Don't report read0 if we were not connected.
In si_cs_recv(), report that arrive at the end of stream only if we were
indeed connected, we don't want that if the connection failed and we're about
to retry.
Olivier Houchard [Thu, 13 Dec 2018 14:37:25 +0000 (15:37 +0100)]
BUG/MEDIUM: connections: Remove CS_FL_EOS | CS_FL_REOS on retry.
CS_FL_EOS | CS_FL_REOS can be set by the mux if the connection failed, so make
sure we remove them before retrying to connect, or it may lead to a premature
close of the connection.
Willy Tarreau [Thu, 13 Dec 2018 16:29:20 +0000 (17:29 +0100)]
REGTESTS: adjust the http-rules regtest to support window updates
Varnishtest is not happy to see the window update come before the
settings ACK, as by default it expects exactly tx/rx/txack/rxack.
One workaround could consist in making haproxy send the WU after
the settings ACK but this would be a real hack as the preface is
already finished when sending this ack. Instead, let's make the
initial sequence explicit in the tests.
BUG/MEDIUM: cli: handle correctly prefix and payload
In the master CLI, the commands and the prefix were still parsed and
trimmed after the pattern payload. Don't parse anything but the end of a
line till we are in payload mode.
Put the search of the pattern after the trim so we can use correctly a
payload with a command which is prefixed by @.
Handle the CLI level in the master CLI. In order to do this, the master
CLI stores the level in the stream. Each command are prefixed by a
"user" or "operator" command before they are forwarded to the target
CLI.
The level can be configured in the haproxy program arguments with the
level keyword: -S /tmp/sock,level,admin -S /tmp/sock2,level,user.
Remi Gacogne [Wed, 5 Dec 2018 16:59:56 +0000 (17:59 +0100)]
BUG: dns: Fix off-by-one write in dns_validate_dns_response()
The maximum number of bytes in a DNS name is indeed 255, but we
need to allocate one more byte for the NULL-terminating byte.
Otherwise dns_read_name() might return 255 for a very long name,
causing dns_validate_dns_response() to write a NULL value one
byte after the end of the buffer:
dns_answer_record->name[len] = 0;
The next fields in the struct being filled from the content of the
query, it might have been possible to fill them with non-0 values,
causing for example a strlen() of the name to read past the end of
the struct and access unintended parts of the memory, possibly
leading to a crash.
Remi Gacogne [Wed, 5 Dec 2018 16:57:49 +0000 (17:57 +0100)]
BUG: dns: Fix out-of-bounds read via signedness error in dns_validate_dns_response()
Since the data_len field of the dns_answer_item struct was an int16_t,
record length values larger than 2^15-1 were causing an integer
overflow and thus may have been interpreted as negative, making us
read well before the beginning of the buffer.
This might have led to information disclosure or a crash.
Remi Gacogne [Wed, 5 Dec 2018 16:56:29 +0000 (17:56 +0100)]
BUG: dns: Prevent out-of-bounds read in dns_validate_dns_response()
We need to make sure that the record length is not making us read
past the end of the data we received.
Before this patch we could for example read the 16 bytes
corresponding to an AAAA record from the non-initialized part of
the buffer, possibly accessing anything that was left on the stack,
or even past the end of the 8193-byte buffer, depending on the
value of accepted_payload_size.
Remi Gacogne [Wed, 5 Dec 2018 16:55:10 +0000 (17:55 +0100)]
BUG: dns: Prevent out-of-bounds read in dns_read_name()
Some callers of dns_read_name() do not make sure that we can read
the first byte, holding the length of the next label, without going
past our buffer, so we need to make sure of that.
In addition, if the label is a compressed one we need to make sure
that we can read the following byte to compute the target offset.
Remi Gacogne [Wed, 5 Dec 2018 16:52:54 +0000 (17:52 +0100)]
BUG: dns: Prevent stack-exhaustion via recursion loop in dns_read_name
When a compressed pointer is encountered, dns_read_name() will call
itself with the pointed-to offset in the packet.
With a specially crafted packet, it was possible to trigger an
infinite-loop recursion by making the pointer points to itself.
While it would be possible to handle that particular case differently
by making sure that the target is different from the current offset,
it would still be possible to craft a packet with a very long chain
of valid pointers, always pointing backwards. To prevent a stack
exhaustion in that case, this patch restricts the number of recursive
calls to 100, which should be more than enough.
BUG/MEDIUM: mux-h1: Fix the zero-copy on output for chunked messages
The commit 3815b227f ("MEDIUM: mux-h1: implement true zero-copy of DATA blocks")
broke the output of chunked messages. When the zero-copy was performed on such
messages, no chunk size was emitted nor ending CRLF.
Now, the chunked envelope is added when necessary. We have at least the size of
the struct htx to emit it. So 40 bytes for now. It should be enough.
MINOR: cli: change 'show proc' output of old processes
Change the output of the relative pid for the old processes, displays
"[was: X]" instead of just "X" which was confusing if you want to
connect to the CLI of an old PID.
Willy Tarreau [Wed, 12 Dec 2018 07:23:47 +0000 (08:23 +0100)]
MINOR: mux-h2: force reads to be HTX-aligned in HTX mode
H2 has a 9-byte frame header, and HTX has a 40-byte frame header.
By artificially advancing the Rx header and limiting the amount of
bytes read to protect the end of the buffer, we can make the data
payload perfectly aligned with HTX blocks and optimize the copy.
Willy Tarreau [Wed, 12 Dec 2018 06:03:00 +0000 (07:03 +0100)]
MEDIUM: mux-h2: implement true zero-copy send of large HTX DATA blocks
This is similar to what was done for the H1 mux : when the mux's buffer
is empty and the htx area contains exactly one data block of the same
size as the requested count, and all window and frame size conditions are
satisfied, then it's possible to simply swap the caller's buffer with the
mux's output buffer and adjust offsets and length to match the entire
DATA HTX block in the middle. An H2 frame header has to be prepended
before the block but this always fits in an HTX frame header.
In this case we perform a true zero-copy operation from end-to-end. This
is the situation that happens all the time with large files. When using
HTX over H2 over TLS, this brings a 3% extra performance gain. TLS remains
a limiting factor here but the copy definitely has a cost. Also since
haproxy can now use H2 in clear, the savings can be higher.
Willy Tarreau [Wed, 12 Dec 2018 08:17:21 +0000 (09:17 +0100)]
MINOR: mux-h2: avoid copying large blocks into full buffers
Due to blocking factor being different on H1 and H2, we regularly end
up with tails of data blocks that leave room in the mux buffer, making
it tempting to copy the pending frame into the remaining room left, and
possibly realigning the output buffer.
Here we check if the output buffer contains data, and prefer to wait
if either the current frame doesn't fit or if it's larger than 1/4 of
the buffer. This way upon next call, either a zero copy, or a larger
and aligned copy will be performed, taking the whole chunk at once.
Doing so increases the H2 bandwidth by slightly more than 1% on large
objects.
Willy Tarreau [Wed, 12 Dec 2018 07:08:05 +0000 (08:08 +0100)]
BUG/MINOR: mux-h2: advertise a larger connection window size
By default H2 uses a 65535 bytes window for the connection, and changing
it requires sending a WINDOW_UPDATE message. We only used to update the
window when receiving data, thus never increasing it further.
As reported by user klzgrad on the mailing list, this seriously limits
the upload bitrate, and will have an even higher impact on the backend
H2 connections to origin servers.
There is no technical reason for keeping this window so low, so let's
increase it to the maximum possible value (2G-1). We do this by
pretending we've already received that many data minus the maximum
data the client might already send (65535), so that an early
WINDOW_UPDATE message is sent right after the SETTINGS frame.
This should be backported to 1.8. This patch depends on previous
patch "BUG/MINOR: mux-h2: refrain from muxing during the preface".
Willy Tarreau [Wed, 12 Dec 2018 07:03:58 +0000 (08:03 +0100)]
BUG/MINOR: mux-h2: refrain from muxing during the preface
The condition to refrain from processing the mux was insufficient as it
would only handle the outgoing connections. In essence it is not that much
of a problem since we don't have streams yet on an incoming connetion. But
it prevents waiting for the end of the preface before sending an early
WINDOW_UPDATE message, thus causing the connections to fail in this case.
This must be backported to 1.8 with a few minor adaptations.
Willy Tarreau [Wed, 12 Dec 2018 05:19:42 +0000 (06:19 +0100)]
MINOR: config: round up global.tune.bufsize to the next multiple of 2 void*
Since HTX casts the buffer to a struct and stores relative pointers at the
end, it is mandatory that its end is properly aligned. This patch enforces
a buffer size rounding up to the next multiple of two void*, thus 8 on
32-bit and 16 on 64-bit, to match what malloc() already does on the beginning
of the buffer. In pratice it will never be really noticeable since default
sizes already are such multiples.
Willy Tarreau [Tue, 11 Dec 2018 18:50:43 +0000 (19:50 +0100)]
MEDIUM: mux-h1: implement true zero-copy of DATA blocks
When the mux's buffer is empty and the htx area contains exactly one
data block of the same size as the requested count, then it's possible
to simply swap the caller's buffer with the mux's output buffer and
adjust offsets and length to match the entire DATA HTX block in the
middle. In this case we perform a true zero-copy operation from
end-to-end. This is the situation that happens all the time with large
files. With this change, the HTX bit rate performance catches up again
with the legacy mode (measured at 97%).
These flags haven't been used for a while. SF_TUNNEL was reintroduced
by commit d62b98c6e ("MINOR: stream: don't set backend's nor response
analysers on SF_TUNNEL") to handle the two-level streams needed to
deal with the first model for H2, and was not removed after this model
was abandonned. SF_INITIALIZED was only set. SF_CONN_TAR was never
referenced at all.
Willy Tarreau [Tue, 11 Dec 2018 09:59:20 +0000 (10:59 +0100)]
REORG: h1: move legacy http functions to http_msg.c
Now that h1 and legacy HTTP are two distinct things, there's no need
to keep the legacy HTTP parsers in h1.c since they're only used by
the legacy code in proto_http.c, and h1.h doesn't need to include
hdr_idx anymore. This concerns the following functions :
Willy Tarreau [Tue, 11 Dec 2018 10:42:27 +0000 (11:42 +0100)]
REORG: http: create http_msg.c to place there some legacy HTTP parts
Lots of HTTP code still uses struct http_msg. Not only this code is
still huge, but it's part of the legacy interface. Let's move most
of these functions to a separate file http_msg.c to make it more
visible which file relies on what. It's mostly symmetrical with
what is present in http_htx.c.
The function http_transform_header_str() which used to rely on two
function pointers to look up a header was simplified to rely on
two variants http_legacy_replace_{,full_}header(), making both
sides of the function much simpler.
Willy Tarreau [Tue, 11 Dec 2018 09:22:41 +0000 (10:22 +0100)]
REORG: htx: merge types+proto into common/htx.h
All the HTX definition is self-contained and doesn't really depend on
anything external since it's a mostly protocol. In addition, some
external similar files (like h2) also placed in common used to rely
on it, making it a bit awkward.
This patch moves the two htx.h files into a single self-contained one.
The historical dependency on sample.h could be also removed since it
used to be there only for http_meth_t which is now in http.h.
MEDIUM: cache: Require an explicit filter declaration if other filters are used
As for the compression filter, the cache filter must be explicitly declared
(using the filter keyword) if other filters than cache are used. It is mandatory
to explicitly define the filters order.
MEDIUM: cache/compression: Add a way to safely combined compression and cache
This is only true for HTX proxies. On legacy HTTP proxy, if the compression and
the cache are both enabled, an error during HAProxy startup is triggered.
With the HTX, now you can use both in any order. If the compression is defined
before the cache, then the responses will be stored compressed. If the
compression is defined after the cache, then the responses will be stored
uncompressed. So in the last case, when a response is served from the cache, it
will compressed too like any response.
MINOR: cache: Improve and simplify the cache configuration check
To do so, a dedicated configuration has been added on cache filters. Before the
cache filter configuration pointed directly to the cache it used. Now, it is the
dedicated structure cache_flt_conf. Store and use rules also point to this
structure. It is linked to the cache the filter must used. It also contains a
flags field. This will allow us to define the behavior of a cache filter when a
response is stored in the cache or delivered from it.
And now, Store and use rules uses a common parsing function. So if it does not
already exists, a filter is always created for both kind of rules. The cache
filters configuration is checked using their check callback. In the postparser
function, we only check the caches configuration. This removes the loop on all
proxies in the postparser function.
MEDIUM: cache/htx: Add the HTX support into the cache
The cache is now able to store and resend HTX messages. When an HTX message is
stored in the cache, the headers are prefixed with their block's info (an
uint32_t), containing its type and its length. Data, on their side, are stored
without any prefix. Only the value is copied in the cache. 2 fields have been
added in the structure cache_entry, hdrs_len and data_len, to known the size, in
the cache, of the headers part and the data part. If the message is chunked, the
trailers are also copied, the same way as data. When the HTX message is
recreated in the cache applet, the trailers size is known removing the headers
length and the data lenght from the total object length.
MINOR: cache: Register the cache as a data filter only if response is cacheable
Instead of calling register_data_filter() when the stream analyze starts, we now
call it when we are sure the response is cacheable. It is done in the
http_headers callback, just before the body analyzis, and only if the headers
was already been cached. And during the body analyzis, if an error occurred or
if the response is too big, we unregistered the cache immediatly.
This patch may be backported in 1.8. It is not a bug but a significant
improvement.
MINOR: cache/htx: Don't use the same cache on HTX and legacy HTTP proxies
It is not possible to mix the format of messages stored in a cache. So we reject
the configurations with a cache used by an HTX proxy and a legacy HTTP proxy in
same time.
The CLI proxy was not handling payload. To do that, we needed to keep a
connection active on a server and to transfer each new line over that
connection until we receive a empty line.
The CLI proxy handles the payload in the same way that the CLI do it.
BUG/MINOR: cli: wait for payload data even without prompt
During a payload transfer, we need to wait for the data even when we are
not in interactive mode. Indeed, the data could be received line per
line progressively instead of in one recv.
Previously the CLI was doing a SHUTW just after the first line if it was
not in interactive mode. We now check if we are in payload mode to do
a SHUTW.
Willy Tarreau [Tue, 11 Dec 2018 15:37:42 +0000 (16:37 +0100)]
REORG: connection: centralize the conn_set_{tos,mark,quickack} functions
There were a number of ugly setsockopt() calls spread all over
proto_http.c, proto_htx.c and hlua.c just to manipulate the front
connection's TOS, mark or TCP quick-ack. These ones entirely relied
on the connection, its existence, its control layer's presence, and
its addresses. Worse, inet_set_tos() was placed in proto_http.c,
exported and used from the two other ones, surrounded in #ifdefs.
This patch moves this code to connection.h and makes the other ones
rely on it without ifdefs.
Willy Tarreau [Mon, 10 Dec 2018 18:26:51 +0000 (19:26 +0100)]
MINOR: hpack: provide a function to encode an HTTP path
The new function hpack_encode_path() supports encoding a path into
the ":path" header. It knows about "/" and "/index.html" which use
a single byte, and falls back to literal encoding for other ones,
with a fast path for short paths < 127 bytes.
Willy Tarreau [Mon, 10 Dec 2018 18:16:20 +0000 (19:16 +0100)]
MINOR: hpack: provide a function to encode an HTTP scheme
The new function hpack_encode_scheme() supports encoding a scheme
into the ":scheme" header. It knows about "https" and "http" which use
a single byte, and falls back to literal encoding for other ones.
Willy Tarreau [Mon, 10 Dec 2018 17:24:19 +0000 (18:24 +0100)]
MINOR: hpack: provide a function to encode an HTTP method
The new function hpack_encode_method() supports encoding a method.
It knows about GET and POST which use a single byte, and falls back
to literal encoding for other ones.
Willy Tarreau [Mon, 10 Dec 2018 17:06:40 +0000 (18:06 +0100)]
MEDIUM: mux-h2: make use of standard HPACK encoding functions for the status
This way we don't open-code the HPACK status codes anymore in the H2
code. Special care was taken not to cause any slowdown as this code is
very sensitive.
Willy Tarreau [Mon, 10 Dec 2018 17:04:42 +0000 (18:04 +0100)]
MINOR: hpack: provide new functions to encode the ":status" header
This header exists with 7 different values, it's worth taking them
into account for the encoding, hence these functions. One of them
makes use of an integer only and computes the 3 output bytes in case
of literal. The other one benefits from the knowledge of an existing
string, which for example exists in the case of H1 to H2 encoding.
Willy Tarreau [Tue, 11 Dec 2018 06:44:19 +0000 (07:44 +0100)]
MINOR: hpack: provide a function to encode a long indexed header
For long header values whose index is known, hpack_encodde_long_idx()
may now be used. This function emits the short index and follows with
the header's value.
Willy Tarreau [Tue, 11 Dec 2018 05:16:45 +0000 (06:16 +0100)]
MINOR: hpack: provide a function to encode a short indexed header
Most direct calls to HPACK functions are made to encode short header
fields like methods, schemes or statuses, whose lengths and indexes
are known. Let's have a small function to do this.
Willy Tarreau [Tue, 11 Dec 2018 06:44:00 +0000 (07:44 +0100)]
MINOR: hpack: move the length computation and encoding functions to .h
We'll need these functions from other inline functions, let's make them
accessible. len_to_bytes() was renamed to hpack_len_to_bytes() since it's
now exposed.
Willy Tarreau [Mon, 10 Dec 2018 14:19:14 +0000 (15:19 +0100)]
MEDIUM: hpack: make it possible to encode any static header name
We used to have a series of well-known header fields that were looked
up, but most of them were not. The current model couldn't scale with
the addition of the new headers or pseudo-headers required to process
requests, resulting in their encoding being hard-coded in the caller.
This patch implements a quick lookup which retrieves any header from
the static table. A binary stream is made of header names prefixed by
lengths and indexes. These header names are sorted by length, then by
frequency, then by direction (preference for response), then by name,
the the lowest index of each is stored only in case of multiple
entries. A parallel length index table provides the index of the first
header for a given string. This allows to focus on the first few values
matching the same length.
Everything was made to limit the cache footprint. Interestingly, the
lookup ends up being slightly faster than the previous one, while
covering the 54 distinct headers instead of only 10.
A test with a curl request and a basic response showed that the request
size has dropped from 85 to 56 bytes and that the response size has
dropped from 197 to 170 bytes, thus we can now shave roughly 25-30 bytes
per message.
Willy Tarreau [Mon, 10 Dec 2018 14:26:35 +0000 (15:26 +0100)]
CONTRIB: hpack: add a compressed stream generator for the encoder
This generates the tables and indexes which will be used by the HPACK
encoder. The headers are sorted by length, then by statistical frequency,
then by direction (preference for responses), then by name, then by index.
The purpose is to speed up their lookup.
Willy Tarreau [Tue, 11 Dec 2018 05:42:01 +0000 (06:42 +0100)]
MINOR: hpack: optimize header encoding for short names
For unknown fields, since we know that most of them are less than 127
characters, we don't need to go through the loop and can instead directly
emit the one-byte length encoding. This increases the request rate by
approximately 0.5%.
Willy Tarreau [Tue, 11 Dec 2018 05:27:06 +0000 (06:27 +0100)]
MINOR: hpack: use ist2bin() to copy header names in hpack_encode_header()
memcpy() tends to be overkill to copy short strings, better use ist's
naive functions for this. This shows a consistent 1.2% performance
gain with h2load.
Willy Tarreau [Mon, 10 Dec 2018 12:36:56 +0000 (13:36 +0100)]
MINOR: hpack: simplify the len to bytes conversion
The len-to-bytes conversion can be slightly simplified and optimized
by hardcoding a tree lookup. Just doing this increases by 1% the
request rate on H2. It could be made almost branch-free by using
fls() but it looks overkill for most situations since most headers
are very short.
Willy Tarreau [Tue, 11 Dec 2018 05:46:03 +0000 (06:46 +0100)]
BUG/MINOR: hpack: fix off-by-one in header name encoding length calculation
In hpack_encode_header() there is a length check to verify that a literal
header name fits in the buffer, but there it an off-by-one in this length
check, which forgets the byte required to mark the encoding type (literal
without indexing). It should be harmless though as it cannot be triggered
since response headers passing through haproxy are limited by the reserve,
which is not the case of the output buffer.
BUG/MEDIUM: htx: Always do a defrag if a block value is replace by a bigger one
Otherwise, after such replaces, the HTX message appears to wrap but the head
block address is not necessarily the first one. So adding new blocks will
override data of old ones.
BUG/MEDIUM: mux-h1: Don't loop on the headers parsing if the read0 was received
If a server sends part of headers and then close its connection, the mux H1
reamins blocked in an infinite loop trying to read more data to finish the
parsing of the message. The flag CS_FL_REOS is set on the conn_stream. But
because there are some data in the input buffer, CS_FL_EOS is never set.
To fix the bug, in h1_process_input, when CS_FL_REOS is set on the conn_stream,
we also set CS_FL_EOS if the input buffer is empty OR if the channel's buffer is
empty.
BUG/MEDIUM: mux-h1: Add a BUSY mode to not loop on pipelinned requests
When a request is fully processed, no more data are parsed until the response is
totally processed and a new transaction starts. But during this time, the mux is
trying to read more data and subscribes to read. If requests are pipelined, we
start to receive the next requests which will stay in the input buffer, leading
to a loop consuming all the CPU. This loop ends when the transaction ends. To
avoid this loop, the flag H1C_F_IN_BUSY has been added. It is set when the
request is fully parsed and unset when the transaction ends. Once set on H1C, it
blocks the reads. So the mux never tries to receive more data in this state.
BUG/MINOR: mux-h1: Fix conn_mode processing for headerless outgoing messages
Condition to process the connection mode on outgoing messages whithout
'Connection' header was wrong. It relied on the wrong H1M
state. H1_MSG_HDR_L2_LWS is only a possible state for messages with at least one
header. Now, to fix the bug, we just check the H1M state is not
H1_MSG_LAST_LF. So, we have the warranty the EOH was not processed yet.
Willy Tarreau [Mon, 10 Dec 2018 10:08:04 +0000 (11:08 +0100)]
BUG/MEDIUM: mux-h2: fix encoding of non-GET/POST methods
Jerome reported that outgoing H2 failed for methods different from GET
or POST. It turns out that the HPACK encoding is performed by hand in
the outgoing headers encoding function and that the data length was not
incremented to cover the literal method value, resulting in a corrupted
HEADERS frame.
Admittedly this code should move to the generic HPACK code.
PiBa-NL [Sat, 8 Dec 2018 18:48:37 +0000 (19:48 +0100)]
REGTEST/MINOR: remove double body specification for server txresp
fix http-rules/h00000.vtc / http-rules/h00000.vtc as both 'bodylen' and
'body' are specified, these settings conflict with each other as they
both generate/present the body to send.
BUG/MEDIUM: connection: Don't use the provided conn_stream if it was tried.
In connect_server(), don't attempt to reuse the conn_stream associated to
the stream_interface, if we already attempted a connection with it.
Using that conn_stream is only there for the cases where a connection and
a conn_stream was created ahead, mostly by http_proxy or by the LUA code.
If we already attempted to connect, that means we fail, and so we should
create a new connection.
Willy Tarreau [Sat, 8 Dec 2018 15:20:55 +0000 (16:20 +0100)]
[RELEASE] Released version 1.9-dev10
Released version 1.9-dev10 with the following main changes :
- MINOR: htx: Rename functions htx_*_to_str() to be H1 specific
- BUG/MINOR: htx: Force HTTP/1.1 on H1 formatting when version is 1.1 or above
- BUG/MINOR: fix ssl_fc_alpn and actually add ssl_bc_alpn
- BUG/MEDIUM: mworker: stop proxies which have no listener in the master
- BUG/MEDIUM: h1: Destroy a connection after detach if it has no owner.
- BUG/MEDIUM: h2: Don't forget to wake the tasklet after shutr/shutw.
- BUG/MINOR: flt_trace/compression: Use the right flag to add the HTX support
- BUG/MEDIUM: stream_interface: Make REALLY sure we read all the data.
- MEDIUM: mux-h1: Revamp the way subscriptions are handled.
- BUG/MEDIUM: mux-h1: Always set CS_FL_RCV_MORE when data are received in h1_recv()
- MINOR: mux-h1: Make sure to return 1 in h1_recv() when needed
- BUG/MEDIUM: mux-h1: Release the mux H1 in h1_process() if there is no h1s
- BUG/MINOR: proto_htx: Truncate the request when an error is detected
- BUG/MEDIUM: h2: When sending in HTX, make sure the caller knows we sent all.
- BUG/MEDIUM: mux-h2: properly update the window size in HTX mode
- BUG/MEDIUM: mux-h2: make sure to always report HTX EOM when consumed by headers
- BUG/MEDIUM: mux-h2: stop sending HTX once the mux is blocked
- BUG/MEDIUM: mux-h2: don't send more HTX data than requested
- MINOR: mux-h2: stop on non-DATA and non-EOM HTX blocks
- BUG/MEDIUM: h1: Correctly report used data with no len.
- MEDIUM: h1: Realign the ibuf before calling rcv_buf if needed.
- BUG/MEDIUM: mux_pt: Always set CS_FL_RCV_MORE.
- MINOR: htx: make htx_from_buf() adjust the size only on new buffers
- MINOR: htx: add buf_room_for_htx_data() to help optimize buffer transfers
- MEDIUM: mux-h1: make use of buf_room_for_htx_data() instead of b_room()
- MEDIUM: mux-h1: attempt to zero-copy Rx DATA transfers
- MEDIUM: mux-h1: avoid a double copy on the Tx path whenever possible
- BUG/MEDIUM: stream-int: don't mark as blocked an empty buffer on Rx
- BUG/MINOR: mux-h1: Check h1m flags to set the server conn_mode on request path
- MEDIUM: htx: Rework conversion from a buffer to an htx structure
- MEDIUM: channel/htx: Add functions for forward HTX data
- MINOR: mux-h1: Don't adjust anymore the amount of data sent in h1_snd_buf()
- CLEANUP: htx: Fix indentation here and there in HTX files
- MINOR: mux-h1: Allow partial data consumption during outgoing data processing
- BUG/MEDIUM: mux-h2: use the correct offset for the HTX start line
- BUG/MEDIUM: mux-h2: stop sending using HTX on errors
- MINOR: mux-h1: Drain obuf if the output is closed after sending data
- BUG/MEDIUM: mworker: stop every tasks in the master
- BUG/MEDIUM: htx: Set the right start-line offset after a defrag
- BUG/MEDIUM: stream: Don't dereference s->txn when it is not there yet.
- BUG/MEDIUM: connections: Reuse an already attached conn_stream.
- MINOR: stream-int: add a new blocking condition on the remote connection
- BUG/MEDIUM: stream-int: don't attempt to receive if the connection is not established
- BUG/MEDIUM: lua: block on remote connection establishment
- BUG/MEDIUM: mworker: fix several typos in mworker_cleantasks()
- SCRIPTS/REGTEST: merge grep+sed into sed in run-regtests
- BUG/MEDIUM: connections: Split CS_FL_RCV_MORE into 2 flags.
- BUG/MEDIUM: h1: Don't free the connection if it's an outgoing connection.
- BUG/MEDIUM: h1: Set CS_FL_REOS if we had a read0.
- BUG/MEDIUM: mux-h1: Be sure to have a conn_stream to set CS_FL_REOS in h1_recv
- REGTEST: Move LUA reg test 4 to level 1.
- MINOR: ist: add functions to copy/uppercase/lowercase into a buffer or string
- MEDIUM: ist: always turn header names to lower case
- MINOR: h2: don't turn HTX header names to lower case anymore
- MEDIUM: ist: use local conversion arrays to case conversion
- MINOR: htx: switch to case sensitive search of lower case header names
- MINOR: mux-h1: Set CS_FL_EOS when read0 is detected and no data are pending
- BUG/MINOR: stream-int: Process read0 even if no data was received in si_cs_recv
- REGTEST: fix the Lua test file name in test lua/h00002 :-)
- REGTEST: add a basic test for HTTP rules manipulating headers
- BUG/MEDIUM: sample: Don't treat SMP_T_METH as SMP_T_STR.
- MINOR: sample: add bc_http_major
- BUG/MEDIUM: htx: fix typo in htx_replace_stline() making it fail all the time
- REGTEST: make the HTTP rules test compatible with HTTP/2 as well
- BUG/MEDIUM: h2: Don't try to chunk data when using HTX.
- MINOR: compiler: add a new macro ALREADY_CHECKED()
- BUILD: h2: mark the start line already checked to avoid warnings
- BUG/MINOR: mux-h1: Remove the connection header when it is useless