Commit Graph

10578 Commits

Author SHA1 Message Date
Olivier Houchard
cea46c0f2c TESTS: Add a stress-test for mt_lists.
Add test-list.c, a stress-test for mt_list, to ensure there's no concurrency
issue.
The number of threads is provided on the command line, and it randomly
add, removes, or parses the list until it made MAX_ACTION actions (currently
5000000).
2019-09-23 18:16:08 +02:00
Olivier Houchard
ff1e9f39b9 MEDIUM: tasklets: Make the tasklet list a struct mt_list.
Change the tasklet code so that the tasklet list is now a mt_list.
That means that tasklet now do have an associated tid, for the thread it
is expected to run on, and any thread can now call tasklet_wakeup() for
that tasklet.
One can change the associated tid with tasklet_set_tid().
2019-09-23 18:16:08 +02:00
Olivier Houchard
0cd6a976ff MINOR: mt_lists: Give MT_LIST_ADD, MT_LIST_ADDQ and MT_LIST_DEL a return value.
Make it so MT_LIST_ADD and MT_LIST_ADDQ return 1 if it managed to add the
item, 0 (because it was already in a list) otherwise.
Make it so MT_LIST_DEL returns 1 if it managed to remove the item from a
list, or 0 otherwise (because it was in no list).
2019-09-23 18:16:08 +02:00
Olivier Houchard
cb22ad4f71 MINOR: mt_lists: Do nothing in MT_LIST_ADD/MT_LIST_ADDQ if already in list.
Modify MT_LIST_ADD and MT_LIST_ADDQ to do nothing if the element is already
in a list.
2019-09-23 18:16:08 +02:00
Olivier Houchard
9570ecf662 MEDIUM: servers: Use LIST_DEL_INIT() instead of LIST_DEL().
In srv_add_to_idle_list(), use LIST_DEL_INIT instead of just LIST_DEL.
We're about to add the connection to a mt_list, and MT_LIST_ADD/MT_LIST_ADDQ
will be modified to make sure we're not adding the element if it's already
in a list.
2019-09-23 18:16:08 +02:00
Olivier Houchard
5e9b92cbff MINOR: mt_lists: Add new macroes.
Add a few new macroes to the mt_lists.
MT_LIST_LOCK_ELT()/MT_LIST_UNLOCK_ELT() helps locking/unlocking an element.
This should only be used if you know for sure nobody else will remove the
element from the list in the meanwhile.
mt_list_for_each_entry_safe() is an iterator, similar to
list_for_each_entry_safe().
It takes 5 arguments, item, list_head, member are similar to those of
the non-mt variant, tmpelt is a temporary pointer to a struct mt_list, while
tmpelt2 is a struct mt_list itself.
MT_LIST_DEL_SELF() can be used to delete an item while parsing the list with
mt_list_for_each_entry_safe(). It shouldn't be used outside, and you
shouldn't use MT_LIST_DEL() while using mt_list_for_each_entry_safe().
2019-09-23 18:16:08 +02:00
Olivier Houchard
859dc80f94 MEDIUM: list: Separate "locked" list from regular list.
Instead of using the same type for regular linked lists and "autolocked"
linked lists, use a separate type, "struct mt_list", for the autolocked one,
and introduce a set of macros, similar to the LIST_* macros, with the
MT_ prefix.
When we use the same entry for both regular list and autolocked list, as
is done for the "list" field in struct connection, we know have to explicitely
cast it to struct mt_list when using MT_ macros.
2019-09-23 18:16:08 +02:00
Willy Tarreau
6dd4ac890b BUG/MEDIUM: check/threads: make external checks run exclusively on thread 1
See GH issues #141 for all the context. In short, registered signal
handlers are not inherited by other threads during startup, which is
normally not a problem, except that we need that the same thread as
the one doing the fork() cleans up the old process using waitpid()
once its death is reported via SIGCHLD, as happens in external checks.

The only simple solution to this at the moment is to make sure that
external checks are exclusively run on the first thread, the one
which registered the signal handlers on startup. It will be far more
than enough anyway given that external checks must not require to be
load balanced on multiple threads! A more complex solution could be
designed over the long term to let each thread deal with all signals
but it sounds overkill.

This must be backported as far as 1.8.
2019-09-23 18:14:37 +02:00
Christopher Faulet
6884aa3eb0 BUG/MAJOR: mux-h2: Handle HEADERS frames received after a RST_STREAM frame
As stated in the RFC7540#5.1, an endpoint that receives any frame other than
PRIORITY after receiving a RST_STREAM MUST treat that as a stream error of type
STREAM_CLOSED. However, frames carrying compression state must still be
processed before being dropped to keep the HPACK decoder synchronized. This had
to be the purpose of the commit 8d9ac3ed8b ("BUG/MEDIUM: mux-h2: do not abort
HEADERS frame before decoding them"). But, the test on the frame type was
inverted.

This bug is major because desynchronizing the HPACK decoder leads to mixup
indexed headers in messages. From the time an HEADERS frame is received and
ignored for a closed stream, wrong headers may be sent to the following streams.

This patch may fix several bugs reported on github (#116, #290, #292). It must
be backported to 2.0 and 1.9.
2019-09-23 15:28:23 +02:00
Christopher Faulet
0ce57b05de BUG/MINOR: mux-fcgi: Don't compare the filter name in its parsing callback
The function parse_fcgi_flt() is called when the keyword "fcgi-app" is found on
a filter line. We don't need to compare it again in the function.

This patch fixes the issue #284. No backport needed.
2019-09-18 11:20:55 +02:00
Christopher Faulet
d432b3e5c8 CLEANUP: fcgi-app: Remove useless test on fcgi_conf pointer
fcgi_conf was already tested after allocation. No need to test it again.
This patch fixes the isssue #285.
2019-09-18 11:20:55 +02:00
Christopher Faulet
a99db937c5 BUG/MINOR: mux-fcgi: Be sure to have a connection to unsubcribe
When the mux is released, It must own the connection to unsubcribe.
This patch fixes the issue #283. No backport needed.
2019-09-18 11:20:55 +02:00
Christopher Faulet
21d849f52f BUG/MINOR: mux-h2: Be sure to have a connection to unsubcribe
When the mux is released, It must own the connection to unsubcribe.
This patch must be backported to 2.0.
2019-09-18 11:20:55 +02:00
Ilya Shipitsin
8abf026aff BUILD: CI: install golang-1.13 when building BoringSSL 2019-09-17 13:52:39 +02:00
Christopher Faulet
d66700a91c BUG/MINOR: build: Fix compilation of mux_fcgi.c when compiled without SSL
The function ssl_sock_is_ssl is only available when HAProxy is compile with the
SSL support.

This patch fixes the issue #279. No need to backport.
2019-09-17 13:50:20 +02:00
Christopher Faulet
b30b310f68 MINOR: doc: Add documentation about the FastCGI support 2019-09-17 10:38:35 +02:00
Christopher Faulet
99eff65f4f MEDIUM: mux-fcgi: Add the FCGI multiplexer
This multiplexer is only available on the backend side. It may handle
multiplexed connections if the FCGI application supports it. A FCGI application
must be configured on the backend to be used. If not redefined during the
request processing by the FCGI filter, this mux handles all mandatory
parameters.

There is a limitation on the way the requests are processed. The parameters must
be encoded into a uniq PARAMS record. It means, once encoded, all HTTP headers
and FCGI parameters must small enough to be store in a buffer. Otherwise, an
internal processing error is returned.
2019-09-17 10:18:54 +02:00
Christopher Faulet
78fbb9f991 MEDIUM: fcgi-app: Add FCGI application and filter
The FCGI application handles all the configuration parameters used to format
requests sent to an application. The configuration of an application is grouped
in a dedicated section (fcgi-app <name>) and referenced in a backend to be used
(use-fcgi-app <name>). To be valid, a FCGI application must at least define a
document root. But it is also possible to set the default index, a regex to
split the script name and the path-info from the request URI, parameters to set
or unset...  In addition, this patch also adds a FCGI filter, responsible for
all processing on a stream.
2019-09-17 10:18:54 +02:00
Christopher Faulet
63bbf284a1 MINOR: fcgi: Add code related to FCGI protocol
This code is independant and is only responsible to encode and decode part of
the FCGI protocol.
2019-09-17 10:18:54 +02:00
Christopher Faulet
86d144c74b MINOR: muxes/htx: Ignore pseudo header during message formatting
When an HTX message is formatted to an H1 or H2 message, pseudo-headers (with
header names starting by a colon (':')) are now ignored. In fact, for now, only
H2 messages have such headers, and the H2 mux already skips them when it creates
the HTX message. But in the futur, it may be useful to keep these headers in the
HTX message to help the message analysis or to do some processing during the
HTTP formatting. It would also be a good idea to have scopes for pseudo-headers
(:h1-, :h2-, :fcgi-...) to limit their usage to a specific mux.
2019-09-17 10:18:54 +02:00
Christopher Faulet
cc3124cf44 MINOR: h1-htx: Use the same function to copy message payload in all cases
This function will try to do a zero-copy transfer. Otherwise, it adds a data
block. The same is used for messages with a content-length, chunked messages and
messages with unknown body length.
2019-09-17 10:18:54 +02:00
Christopher Faulet
4f0f88a9d0 MEDIUM: mux-h1/h1-htx: move HTX convertion of H1 messages in dedicated file
To avoid code duplication in the futur mux FCGI, functions parsing H1 messages
and converting them into HTX have been moved in the file h1_htx.c. Some
specific parts remain in the mux H1. But most of the parsing is now generic.
2019-09-17 10:18:54 +02:00
Christopher Faulet
341fac1eb2 MINOR: http: Add function to parse value of the header Status
It will be used by the mux FCGI to get the status a response.
2019-09-17 10:18:54 +02:00
Christopher Faulet
5c6fefc8eb MINOR: log: Provide a function to emit a log for an application
Application is a generic term here. It is a modules which handle its own log
server list, with no dependency on a proxy. Such applications can now call the
function app_log() to log messages, passing a log server list and a tag as
parameters. Internally, the function __send_log() has been adapted accordingly.
2019-09-17 10:18:54 +02:00
Christopher Faulet
130cf21709 MINOR: istbuf: Add the function b_isteqi()
This function compares a part of a buffer to an indirect string (ist), ignoring
the case of the characters.
2019-09-17 10:18:54 +02:00
Christopher Faulet
a406356255 MINOR: http_fetch: Add sample fetches to get auth method/user/pass
Now, following sample fetches may be used to get information about
authentication:

 * http_auth_type : returns the auth method as supplied in Authorization header
 * http_auth_user : returns the auth user as supplied in Authorization header
 * http_auth_pass : returns the auth pass as supplied in Authorization header

Only Basic authentication is supported.
2019-09-17 10:18:54 +02:00
Christopher Faulet
c16929658f MINOR: config: Support per-proxy and per-server post-check functions callbacks
Most of times, when a keyword is added in proxy section or on the server line,
we need to have a post-parser callback to check the config validity for the
proxy or the server which uses this keyword.

It is possible to register a global post-parser callback. But all these
callbacks need to loop on the proxies and servers to do their job. It is neither
handy nor efficient. Instead, it is now possible to register per-proxy and
per-server post-check callbacks.
2019-09-17 10:18:54 +02:00
Christopher Faulet
3ea5cbe6a4 MINOR: config: Support per-proxy and per-server deinit functions callbacks
Most of times, when any allocation is done during configuration parsing because
of a new keyword in proxy section or on the server line, we must add a call in
the deinit() function to release allocated ressources. It is now possible to
register a post-deinit callback because, at this stage, the proxies and the
servers are already releases.

Now, it is possible to register deinit callbacks per-proxy or per-server. These
callbacks will be called for each proxy and server before releasing them.
2019-09-17 10:18:54 +02:00
Christopher Faulet
e3d2a877fb MINOR: http-ana: Remove err_state field from http_msg
This field is not used anymore. In addition, the state HTTP_MSG_ERROR is now
only used when an error occurred during the body forward.
2019-09-17 10:18:54 +02:00
Christopher Faulet
b9a92f308a MINOR: http-ana: Handle HTX errors first during message analysis
When an error occurred in a mux, most of time, an error is also reported on the
conn-stream, leading to an error (read and/or write) on the channel. When a
parsing or a processing error is reported for the HTX message, it is better to
handle it first.
2019-09-17 10:18:54 +02:00
Christopher Faulet
69b482180c MINOR: mux-h1: Report a processing error during output processing
During output processing, It is unexpected to have a malformed HTX
message. Instead of reporting a parsing error, we now report a processing error.
2019-09-17 10:18:54 +02:00
Christopher Faulet
505adfca51 MINOR: htx: Add a flag on HTX message to report processing errors
This new flag may be used to report unexpected error because of not well
formatted HTX messages (not related to a parsing error) or our incapactity to
handle the processing because we reach a limit (ressource exhaustion, too big
headers...). It should result to an error 500 returned to the client when
applicable.
2019-09-17 10:18:54 +02:00
Ilya Shipitsin
4a2ffe6ae9 BUILD: CI: temporarily disable ASAN
it turned out that ASAN breaks things. until this is resolved,
let us disable ASAN
2019-09-15 12:42:57 +02:00
Christopher Faulet
4e9a83349a BUG/MEDIUM: stick-table: Properly handle "show table" with a data type argument
Since the commit 1b8e68e8 ("MEDIUM: stick-table: Stop handling stick-tables as
proxies."), the target field into the table context of the CLI applet was not
anymore a pointer to a proxy. It was replaced by a pointer to a stktable. But,
some parts of the code was not updated accordingly. the function
table_prepare_data_request() still tries to cast it to a pointer to a proxy. The
result is totally undefined. With a bit of luck, when the "show table" command
is used with a data type, we failed to find a table and the error "Data type not
stored in this table" is returned. But crashes may also be experienced.

This patch fixes the issue #262. It must be backported to 2.0.
2019-09-13 15:46:46 +02:00
Adis Nezirovic
a46b142e88 BUG/MINOR: Missing stat_field_names (since f21d17bb)
Recently Lua code which uses Proxy class (get_stats method) stopped
working ("table index is nil from [C] method 'get_stats'")
It probably affects other codepaths too.

This should be backported do 2.0 and 1.9.
2019-09-13 12:40:50 +02:00
Christopher Faulet
1dbc4676c6 BUG/MINOR: backend: Fix a possible null pointer dereference
In the function connect_server(), when we are not able to reuse a connection and
too many FDs are opened, the variable srv must be defined to kill an idle
connection.

This patch fixes the issue #257. It must be backported to 2.0
2019-09-13 10:08:44 +02:00
Christopher Faulet
361935aa1e BUG/MINOR: acl: Fix memory leaks when an ACL expression is parsed
This only happens during the configuration parsing. First leak is the string
representing the last converter parsed, if any. The second one is on the error
path, when the allocation of the ACL expression failed. In this case, the sample
was not released.

This patch fixes the issue #256. It must be backported to all stable versions.
2019-09-13 10:08:44 +02:00
Christopher Faulet
3e395632bf CLEANUP: mux-h2: Remove unused flag H2_SF_DATA_CHNK
Since the legacy HTTP mode has been removed, this flag is not necessary
anymore. Removing this flag, a test on the HTX message at the end of the
function h2c_decode_headers() has also been removed fixing the github
issue #244.

No backport needed.
2019-09-13 10:08:28 +02:00
Luca Schimweg
8a694b859c MINOR: sample: Add UUID-fetch
Adds the fetch uuid(int). It returns a UUID following the format of
version 4 in the RFC4122 standard.

New feature, but could be backported.
2019-09-13 04:43:33 +02:00
Christopher Faulet
e058f7359f BUG/MINOR: filters: Properly set the HTTP status code on analysis error
When a filter returns an error during the HTTP analysis, an error must be
returned if the status code is not already set. On the request path, an error
400 is returned. On the response path, an error 502 is returned. The status is
considered as unset if its value is not strictly positive.

If needed, this patch may be backported to all versions having filters (as far
as 1.7). Because nobody have never report any bug, the backport to 2.0 is
probably enough.
2019-09-10 10:29:54 +02:00
Christopher Faulet
6338a08c34 MINOR: stats: Add JSON export from the stats page
It is now possible to export stats using the JSON format from the HTTP stats
page. Like for the CSV export, to export stats in JSON, you must add the option
";json" on the stats URL. It is also possible to dump the JSON schema with the
option ";json-schema". Corresponding Links have been added on the HTML page.

This patch fixes the issue #263.
2019-09-10 10:29:54 +02:00
Christopher Faulet
82004145d4 BUG/MINOR: ssl: always check for ssl connection before getting its XPRT context
In several SSL functions, the XPRT context is retrieved before any check on the
connection. In the function ssl_sock_is_ssl(), a test suggests the connection
may be null. So, it is safer to test the ssl connection before retrieving its
XPRT context. It removes any ambiguities and prevents possible null pointer
dereferences.

This patch fixes the issue #265. It must be backported to 2.0.
2019-09-10 10:29:54 +02:00
Christopher Faulet
ad6c2eac28 BUG/MINOR: listener: Fix a possible null pointer dereference
It seems to be possible to have no frontend for a listener. A test was missing
before dereferencing it at the end of the function listener_accept().

This patch fixes the issue #264. It must be backported to 2.0 and 1.9.
2019-09-10 10:29:54 +02:00
David Carlier
6c00eba63b BUILD/MINOR: auth: enabling for osx
macOS supports this but as part of libc.
Little typo fix while here.
2019-09-08 12:20:13 +02:00
Ilya Shipitsin
bd99f6d4bd BUILD: CI: skip reg-tests/connection/proxy_protocol_random_fail.vtc on CentOS 6
This test relies on ALPN which is not available in CentOS 6.
2019-09-08 12:10:32 +02:00
Willy Tarreau
f21d17bbe8 MINOR: stats: report the number of idle connections for each server
This adds two extra fields to the stats, one for the current number of idle
connections and one for the configured limit. A tooltip link now appears on
the HTML page to show these values in front of the active connection values.

This should be backported to 2.0 and 1.9 as it's the only way to monitor
the idle connections behaviour.
2019-09-08 09:30:50 +02:00
Willy Tarreau
4cae3bf631 BUG/MEDIUM: connection: don't keep more idle connections than ever needed
When using "http-reuse safe", which is the default, a new incoming connection
does not automatically reuse an existing connection for the first request, as
we don't want to risk to lose the contents if we know the client will not be
able to replay the request. A side effect to this is that when dealing with
mostly http-close traffic, the reuse rate is extremely low and we keep
accumulating server-side connections that may even never be reused. At some
point we're limited to a ratio of file descriptors, but when the system is
configured with very high FD limits, we can still reach the limit of outgoing
source ports and make the system significantly slow down trying to find an
available port for outgoing connections. A simple test on my laptop with
ulimit 100000 and with the following config results in the load immediately
dropping after a few seconds :

   listen l1
        bind :4445
        mode http
        server s1 127.0.0.1:8000

As can be seen, the load falls from 38k cps to 400 cps during the first 200ms
(in fact when the source port table is full and connect() takes ages to find
a spare port for a new connection):

   $ injectl464 -p 4 -o 1 -u 10 -G 127.0.0.1:4445/ -F -c -w 100
   hits ^hits hits/s  ^h/s     bytes  kB/s  last  errs  tout htime  sdht ptime
   2439  2439  39338 39338    356094  5743  5743     0     0 0.4 0.5 0.4
   7637  5198  38185 37666   1115002  5575  5499     0     0 0.7 0.5 0.7
   7719    82  25730   820   1127002  3756   120     0     0 21.8 18.8 21.8
   7797    78  19492   780   1138446  2846   114     0     0 61.4 2.5 61.4
   7877    80  15754   800   1150182  2300   117     0     0 58.6 0.5 58.6
   7920    43  13200   430   1156488  1927    63     0     0 58.9 0.3 58.9

At this point, lots of connections are indeed in use, for only 10 connections
on the frontend side:

   $ ss -ant state established | wc -l
   39022

This patch makes sure we never keep more idle connections than we've ever
had outstanding requests on a server. This way the total number of idle
connections will never exceed the sum of maximum connections. Thus highly
loaded servers will be able to get many connections and slightly loaded
servers will keep less. Ideally we should apply similar limits per process
and the per backend, but in practice this already addresses the issues
pretty well:

   $ injectl464 -p 4 -o 1 -u 10 -G 127.0.0.1:4445/ -F -c -w 100
   hits ^hits hits/s  ^h/s     bytes  kB/s  last  errs  tout htime  sdht ptime
   4423  4423  40209 40209    645758  5870  5870     0     0 0.2 0.4 0.2
   8020  3597  40100 39966   1170920  5854  5835     0     0 0.2 0.4 0.2
  12037  4017  40123 40170   1757402  5858  5864     0     0 0.2 0.4 0.2
  16069  4032  40172 40320   2346074  5865  5886     0     0 0.2 0.4 0.2
  20047  3978  40013 39386   2926862  5842  5750     0     0 0.3 0.4 0.3
  24005  3958  40008 39979   3504730  5841  5837     0     0 0.2 0.4 0.2

   $ ss -ant state established | wc -l
   234

This patch must be backported to 2.0. It could be useful in 1.9 as well
eventhough pools and reuse are not enabled by default there.
2019-09-08 09:30:50 +02:00
Willy Tarreau
6b3089856f MEDIUM: fd: do not use the FD_POLL_* flags in the pollers anymore
As mentioned in previous commit, these flags do not map well to
modern poller capabilities. Let's use the FD_EV_*_{R,W} flags instead.
This first patch only performs a 1-to-1 mapping making sure that the
previously reported flags are still reported identically while using
the closest possible semantics in the pollers.

It's worth noting that kqueue will now support improvements such as
returning distinctions between shut and errors on each direction,
though this is not exploited for now.
2019-09-06 19:09:56 +02:00
Willy Tarreau
77abb43ed1 MINOR: fd: add two flags ERR and SHUT to describe FD states
There's currently a big ambiguity on our use of POLLHUP because we
currently map POLLHUP and POLLRDHUP to FD_POLL_HUP. The first one
indicates a close in *both* directions while the second one indicates
a unidirectional close. Since we don't know from the resulting flag
we always have to read when reported. Furthermore kqueue only reports
unidirectional responses which are mapped to FD_POLL_HUP as well, and
their write closes are mapped to a general error.

We could add a new FD_POLL_RDHUP flag to improve the mapping, or
switch only to the POLL* flags, but that further complicates the
portability for operating systems like FreeBSD which do not have
POLLRDHUP but have its semantics.

Let's instead directly use the per-direction flag values we already
have, and it will be a first step in the direction of finer states.
Thus we introduce an ERR and a SHUT status for each direction, that
the pollers will be able to compute and pass to fd_update_events().

It's worth noting that FD_EV_STATUS already sees the two new flags,
but they are harmless since used only by fd_{recv,send}_state() which
are never called. Thus in its current state this patch must be totally
transparent.
2019-09-06 18:33:07 +02:00
Willy Tarreau
ccf3f6d1d6 MEDIUM: connection: enable reading only once the connection is confirmed
In order to address the absurd polling sequence described in issue #253,
let's make sure we disable receiving on a connection until it's established.
Previously with bottom-top I/Os, we were almost certain that a connection
was ready when the first I/O was confirmed. Now we can enter various
functions, including process_stream(), which will attempt to read
something, will fail, and will then subscribe. But we don't want them
to try to receive if we know the connection didn't complete. The first
prerequisite for this is to mark the connection as not ready for receiving
until it's validated. But we don't want to mark it as not ready for sending
because we know that attempting I/Os later is extremely likely to work
without polling.

Once the connection is confirmed we re-enable recv readiness. In order
for this event to be taken into account, the call to tcp_connect_probe()
was moved earlier, between the attempt to send() and the attempt to recv().
This way if tcp_connect_probe() enables reading, we have a chance to
immediately fall back to this and read the possibly pending data.

Now the trace looks like the following. It's far from being perfect
but we've already saved one recvfrom() and one epollctl():

 epoll_wait(3, [], 200, 0) = 0
 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 7
 fcntl(7, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
 setsockopt(7, SOL_TCP, TCP_NODELAY, [1], 4) = 0
 connect(7, {sa_family=AF_INET, sin_port=htons(8000), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress)
 epoll_ctl(3, EPOLL_CTL_ADD, 7, {EPOLLIN|EPOLLOUT|EPOLLRDHUP, {u32=7, u64=7}}) = 0
 epoll_wait(3, [{EPOLLOUT, {u32=7, u64=7}}], 200, 1000) = 1
 connect(7, {sa_family=AF_INET, sin_port=htons(8000), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
 getsockopt(7, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
 sendto(7, "OPTIONS / HTTP/1.0\r\n\r\n", 22, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 22
 epoll_ctl(3, EPOLL_CTL_MOD, 7, {EPOLLIN|EPOLLRDHUP, {u32=7, u64=7}}) = 0
 epoll_wait(3, [{EPOLLIN|EPOLLRDHUP, {u32=7, u64=7}}], 200, 1000) = 1
 getsockopt(7, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
 getsockopt(7, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
 recvfrom(7, "HTTP/1.0 200\r\nContent-length: 0\r\nX-req: size=22, time=0 ms\r\nX-rsp: id=dummy, code=200, cache=1, size=0, time=0 ms (0 real)\r\n\r\n", 16384, 0, NULL, NULL) = 126
 close(7)                = 0
2019-09-06 17:50:36 +02:00