Commit Graph

1859 Commits

Author SHA1 Message Date
Christopher Faulet
83662b5431 MINOR: tcpcheck: Add support of L7OKC on expect rules error-status argument
L7OKC may now be used as an error status for an HTTP/TCP expect rule. Thus
it is for instance possible to write:

    option httpchk GET /isalive
    http-check expect status 200,404
    http-check expect status 200 error-status L7OKC

It is more or less the same than the disable-on-404 option except that if a
DOWN is up again but still replying a 404 will be set to NOLB state. While
it will stay in DOWN state with the disable-on-404 option.
2020-11-27 10:30:23 +01:00
Christopher Faulet
bb9fb8b7f8 MINOR: config: Deprecate and ignore tune.chksize global option
This option is now ignored because I/O check buffers are now allocated using the
buffer pool. Thus, it is marked as deprecated in the documentation and ignored
during the configuration parsing. The field is also removed from the global
structure.

Because this option is ignored since a recent fix, backported as fare as 2.2,
this patch should be backported too. Especially because it updates the
documentation.
2020-11-27 10:30:23 +01:00
Maciej Zdeb
21acc33266 DOC: Clarify %HP description in log-format
%HP is used to report HTTP request URI in logs, which might be relative
or absolute. Description in documentation should not suggest that it
behaves exactly the same as "path" sample fetch.

This is even more important after 30ee1efe67
because right now, when HTTP2 is a standard, %HP usually returns absolute
URI.

This might be backported as far as 2.1
2020-11-26 19:07:21 +01:00
Willy Tarreau
6f1129d14d DOC: better document the config file format and escaping/quoting rules
It's always a pain to figure how to proceed when special characters need
to be embedded inside arguments of an expression. Let's document the
configuration file format and how unquoting/unescaping works at each
level (top level and argument level) so that everyone hopefully finds
suitable reminders or examples for complex cases.

This is related to github issue #200 and addresses issues #712 and #966.
2020-11-26 18:50:12 +01:00
Remi Tricot-Le Breton
4f7308335e DOC: cache: Add information about Vary support
We do not skip all responses containing a Vary in the cachign mechanism
anymore. Under certain conditions such responses might be cached.
2020-11-26 18:01:43 +01:00
Remi Tricot-Le Breton
d493bc863d DOC: cache: Add new caching limitation information
Responses that do not have an explicit expiration time or a validator
will not be cached anymore.

Must be backported if cc9bf2e ("MEDIUM: cache: Change caching
conditions") is backported.
2020-11-26 17:58:01 +01:00
Remi Tricot-Le Breton
754b2428d3 MINOR: cache: Add a process-vary option that can enable/disable Vary processing
The cache section's process-vary option takes a 0 or 1 value to disable
or enable the vary processing.
When disabled, a response containing such a header will never be cached.
When enabled, we will calculate a preliminary hash for a subset of request
headers on all the incoming requests (which might come with a cpu cost) which
will be used to build a secondary key for a given request (see RFC 7234#4.1).
The default value is 0 (disabled).
2020-11-24 16:52:57 +01:00
Joao Morais
aa8fcc4692 DOC: better describes how to configure a fallback crt
A default certificate is always the first one declared in the bind line,
either from `crt` or from `crt-line` option. This commit updates the
description of how to configure a fallback certificate, clarifying that
it needs to be the first one of the bind line.

Should be merged as far as the first SNI filter implementation.
2020-11-24 13:23:06 +01:00
Julien Pivotto
2de240a676 MINOR: stream: Add level 7 retries on http error 401, 403
Level-7 retries are only possible with a restricted number of HTTP
return codes. While it is usually not safe to retry on 401 and 403, I
came up with an authentication backend which was not synchronizing
authentication of users. While not perfect, being allowed to also retry
on those return codes is really helpful and acts as a hotfix until we
can fix the backend.

Signed-off-by: Julien Pivotto <roidelapluie@inuits.eu>
2020-11-23 09:33:14 +01:00
Willy Tarreau
1a38ffcb0f [RELEASE] Released version 2.4-dev1
Released version 2.4-dev1 with the following main changes :
    - MINOR: ist: Add istend() function to return a pointer to the end of the string
    - MINOR: sample: Add converters to parse FIX messages
    - REGTEST: converter: Add a regtest for fix converters
    - MINOR: sample: Add converts to parses MQTT messages
    - REGTEST: converter: Add a regtest for MQTT converters
    - MINOR: compat: automatically include malloc.h on glibc
    - MEDIUM: pools: call malloc_trim() from pool_gc()
    - MEDIUM: pattern: call malloc_trim() on pat_ref_reload()
    - MINOR: pattern: move the update revision to the pat_ref, not the expression
    - CLEANUP: pattern: delete the back refs at once during pat_ref_reload()
    - MINOR: pattern: new sflag PAT_SF_REGFREE indicates regex_free() is needed
    - MINOR: pattern: make the delete and prune functions more generic
    - MEDIUM: pattern: link all final elements from the reference
    - MEDIUM: pattern: change the pat_del_* functions to delete from the references
    - MINOR: pattern: remerge the list and tree deletion functions
    - MINOR: pattern: perform a single call to pat_delete_gen() under the expression
    - CLEANUP: acl: don't reference the generic pattern deletion function anymore
    - CLEANUP: pattern: remove pat_delete_fcts[] and pattern_head->delete()
    - MINOR: pattern: introduce pat_ref_delete_by_ptr() to delete a valid reference
    - MINOR: pattern: store a generation number in the reference patterns
    - MEDIUM: pattern: only match patterns that match the current generation
    - MINOR: pattern: add pat_ref_commit() to commit a previously inserted element
    - MINOR: pattern: implement pat_ref_load() to load a pattern at a given generation
    - MINOR: pattern: add pat_ref_purge_older() to purge old entries
    - MEDIUM: pattern: make pat_ref_prune() rely on pat_ref_purge_older()
    - MINOR: pattern: during reload, delete elements frem the ref, not the expression
    - MINOR: pattern: prepare removal of a pattern from the list head
    - MEDIUM: pattern: turn the pattern chaining to single-linked list
    - CLEANUP: cfgparse: remove duplicate registration for transparent build options
    - BUG/MINOR: ssl: don't report 1024 bits DH param load error when it's higher
    - MINOR: http-htx: Add understandable errors for the errorfiles parsing
    - MINOR: ssl: instantiate stats module
    - MINOR: ssl: count client hello for stats
    - MINOR: ssl: add counters for ssl sessions
    - DOC: config: Fix a typo on ssl_c_chain_der
    - MINOR: server: remove idle lock in srv_cleanup_connections
    - BUILD: ssl: silence build warning on uninitialised counters
    - BUILD: http-htx: fix build warning regarding long type in printf
    - REGTEST: ssl: test wildcard and multi-type + exclusions
    - BUG/MEDIUM: ssl/crt-list: correctly insert crt-list line if crt already loaded
    - CI: Expand use of GitHub Actions for CI
    - REGTEST: ssl: mark reg-tests/ssl/ssl_crt-list_filters.vtc as broken
    - BUG/MINOR: pattern: a sample marked as const could be written
    - BUG/MINOR: lua: set buffer size during map lookups
    - MEDIUM: cache: Change caching conditions
    - BUG/MINOR: stats: free dynamically stats fields/lines on shutdown
    - BUG/MEDIUM: stats: prevent crash if counters not alloc with dummy one
    - MINOR: peers: Add traces to peer_treat_updatemsg().
    - BUG/MINOR: peers: Do not ignore a protocol error for dictionary entries.
    - BUG/MINOR: peers: Missing TX cache entries reset.
    - BUG/MEDIUM: peers: fix decoding of multi-byte length in stick-table messages
    - BUG/MINOR: http-fetch: Extract cookie value even when no cookie name
    - BUG/MINOR: http-fetch: Fix calls w/o parentheses of the cookie sample fetches
    - BUG/MEDIUM: check: reuse srv proto only if using same mode
    - MINOR: check: report error on incompatible proto
    - MINOR: check: report error on incompatible connect proto
    - BUG/MINOR: http-htx: Handle warnings when parsing http-error and http-errors
    - BUG/MAJOR: spoe: Be sure to remove all references on a released spoe applet
    - MINOR: spoe: Don't close connection in sync mode on processing timeout
    - BUG/MINOR: tcpcheck: Don't warn on unused rules if check option is after
    - MINOR: init: Fix the prototype for per-thread free callbacks
    - MINOR: config/mux-h2: Return ERR_ flags from init_h2() instead of a status
    - CLEANUP: config: Return ERR_NONE from config callbacks instead of 0
    - MINOR: cfgparse: tighten the scope of newnameserver variable, free it on error.
    - REGTEST: make ssl_client_samples and ssl_server_samples require to 2.2
    - REGTESTS: Add sample_fetches/cook.vtc
    - BUG/MEDIUM: filters: Forward all filtered data at the end of http filtering
    - BUG/MINOR: http-ana: Don't wait for the body of CONNECT requests
    - CLEANUP: flt-trace: Remove unused random-parsing option
    - MINOR: flt-trace: Add an option to inhibits trace messages
    - MINOR: flt-trace: Use a bitfield for the trace options
    - REGTESTS: Add a script to test the random forwarding with several filters
    - REGTESTS: mark the abns test as broken again
    - REGTESTS: converter: add url_dec test
    - CI: Stop hijacking the hosts file
    - CI: Make the h2spec workflow more consistent with the VTest workflow
    - CI: travis-ci: remove amd64, osx builds
    - CI: travis-ci: arm64 are not allowed to fail anymore
    - DOC: add missing 3.10 in the summary
    - MINOR: ssl: remove client hello counters
    - MEDIUM: stats: add counters for failed handshake
    - MINOR: ssl: create common ssl_ctx init
    - MEDIUM: cli/ssl: configure ssl on server at runtime
    - REGTEST: server/cli_set_ssl.vtc requires OpenSSL
    - DOC: coding-style: update a few rules about pointers
    - BUG/MINOR: ssl: segv on startup when AKID but no keyid
    - BUILD: ssl: use SSL_MODE_ASYNC macro instead of OPENSSL_VERSION
    - BUG/MEDIUM: http-ana: Don't eval http-after-response ruleset on empty messages
    - BUG/MEDIUM: ssl/crt-list: bundle support broken in crt-list
    - BUG/MEDIUM: ssl: error when no certificate are found
    - BUG/MINOR: ssl/crt-list: load bundle in crt-list only if activated
    - BUG/MEDIUM: ssl/crt-list: fix error when no file found
    - CI: Github Actions: enable prometheus exporter
    - CI: Github Actions: remove LibreSSL-3.0.2 builds
    - CI: Github Actions: enable BoringSSL builds
    - CI: travis-ci: remove builds migrated to GH actions
    - BUILD: makefile: enable crypt(3) for OpenBSD
    - CI: Github Action: run "apt-get update" before packages restore
    - BUILD: SSL: guard TLS13 ciphersuites with HAVE_SSL_CTX_SET_CIPHERSUITES
    - CI: Pass the github.event_name to matrix.py
    - CI: Clean up Windows CI
    - DOC: clarify how to create a fallback crt
    - CLEANUP: connection: do not use conn->owner when the session is known
    - BUG/MAJOR: connection: reset conn->owner when detaching from session list
    - REGTESTS: mark proxy_protocol_random_fail as broken
    - BUG/MINOR: http_htx: Fix searching headers by substring
    - MINOR: http_act: Add -m flag for del-header name matching method
2020-11-21 16:00:40 +01:00
Maciej Zdeb
ebdd4c55da MINOR: http_act: Add -m flag for del-header name matching method
This patch adds -m flag which allows to specify header name
matching method when deleting headers from http request/response.
Currently beg, end, sub, str and reg are supported.

This is related to GitHub issue #909
2020-11-21 15:54:30 +01:00
Joao Morais
e51fab0a4a DOC: clarify how to create a fallback crt
HAProxy uses CN and SAN of the certificates to match incoming SNI, and
use the matching certificate in the TLS handshake. `crt-list` goes
further and allows to configure SNI filters to explicitly define the
FQDNs that should match a certificate.

The first declared certificate of the `crt-list` option follows the same
rules, and it's also used as a fallback - the certificate that should be
used if SNI isn't provided or the provided one cannot match any
certificate or SNI filter. If a provided SNI matches the CN or SAN of
the first certificate, the first certificate would be used even if a
matching SNI filter is declared later.

This change clarifies this scenario and documents a filter that can be
used to convert the first declared certificate as a proper fallback.

Should be merged as far as the first SNI filter implementation.
2020-11-21 15:29:22 +01:00
Willy Tarreau
02ec3fe669 DOC: coding-style: update a few rules about pointers
It's really annoying to see that in 2020 we're still facing bugs caused
by dangling pointers in the code that result from poorly written rules
about how these pointers are supposed to be handled, set and reset. Let's
add a few supposedly obvious (but apparently not) rules about how pointers
have to be used through out the code in hope to make such bad practices
disappear (or at least have something to point the authors to after
reviewing their code).
2020-11-18 19:59:38 +01:00
William Dauchy
f63704488e MEDIUM: cli/ssl: configure ssl on server at runtime
in the context of a progressive backend migration, we want to be able to
activate SSL on outgoing connections to the server at runtime without
reloading.
This patch adds a `set server ssl` command; in order to allow that:

- add `srv_use_ssl` to `show servers state` command for compatibility,
  also update associated parsing
- when using default-server ssl setting, and `no-ssl` on server line,
  init SSL ctx without activating it
- when triggering ssl API, de/activate SSL connections as requested
- clean ongoing connections as it is done for addr/port changes, without
  checking prior server state

example config:

backend be_foo
  default-server ssl
  server srv0 127.0.0.1:6011 weight 1 no-ssl

show servers state:

  5 be_foo 1 srv0 127.0.0.1 2 0 1 1 15 1 0 4 0 0 0 0 - 6011 - -1

where srv0 can switch to ssl later during the runtime:

  set server be_foo/srv0 ssl on

  5 be_foo 1 srv0 127.0.0.1 2 0 1 1 15 1 0 4 0 0 0 0 - 6011 - 1

Also update existing tests and create a new one.

Signed-off-by: William Dauchy <wdauchy@gmail.com>
2020-11-18 17:22:28 +01:00
William Lallemand
0217b7b24b DOC: add missing 3.10 in the summary
3.10. Log forwarding was missing in the summary.
2020-11-18 10:43:36 +01:00
Christopher Faulet
96a577acae MINOR: flt-trace: Add an option to inhibits trace messages
The 'quiet' option may be set to inibits the trace messages. The trace filter is
a bit verbose. This option may be used to not display the messages.
2020-11-17 11:34:36 +01:00
Christopher Faulet
c41d8bd65a CLEANUP: flt-trace: Remove unused random-parsing option
This option was only used by the legacy HTTP mode. In HTX, it is not used. So it
can be removed.
2020-11-17 11:34:30 +01:00
Christopher Faulet
70d10d1fb6 DOC: config: Fix a typo on ssl_c_chain_der
There is a typo on the ssl_c_chain_der sample fetch
(s/ssl_c_der_chain/ssl_c_chain_der/). This implies a move of the fetch to keep
it at the right place.

This should be backported as far as 2.2 or anywhere the commit a598b500b
("MINOR: ssl: add ssl_{c,s}_chain_der fetch methods") is.
2020-11-06 12:20:04 +01:00
Baptiste Assmann
e279ca6bbe MINOR: sample: Add converts to parses MQTT messages
This patch implements a couple of converters to validate and extract data from a
MQTT (Message Queuing Telemetry Transport) message. The validation consists of a
few checks as well as "packet size" validation. The extraction can get any field
from the variable header and the payload.

This is limited to CONNECT and CONNACK packet types only. All other messages are
considered as invalid. It is not a problem for now because only the first packet
on each side can be parsed (CONNECT for the client and CONNACK for the server).

MQTT 3.1.1 and 5.0 are supported.

Reviewed and Fixed by Christopher Faulet <cfaulet@haproxy.com>
2020-11-05 19:27:03 +01:00
Baptiste Assmann
e138dda1e0 MINOR: sample: Add converters to parse FIX messages
This patch implements a couple of converters to validate and extract tag value
from a FIX (Financial Information eXchange) message. The validation consists in
a few checks such as mandatory fields and checksum computation. The extraction
can get any tag value based on a tag string or tag id.

This patch requires the istend() function. Thus it depends on "MINOR: ist: Add
istend() function to return a pointer to the end of the string".

Reviewed and Fixed by Christopher Faulet <cfaulet@haproxy.com>
2020-11-05 19:26:30 +01:00
Willy Tarreau
1db5579bf8 [RELEASE] Released version 2.4-dev0
Released version 2.4-dev0 with the following main changes :
    - MINOR: version: it's development again.
    - DOC: mention in INSTALL that it's development again
2020-11-05 17:20:35 +01:00
Willy Tarreau
1c0a722a83 [RELEASE] Released version 2.3.0
Released version 2.3.0 with the following main changes :
    - CLEANUP: pattern: remove unused entry "tree" in pattern.val
    - BUILD: ssl: use SSL_CTRL_GET_RAW_CIPHERLIST instead of OpenSSL versions
    - BUG/MEDIUM: filters: Don't try to init filters for disabled proxies
    - BUG/MINOR: proxy/server: Skip per-proxy/server post-check for disabled proxies
    - BUG/MINOR: checks: Report a socket error before any connection attempt
    - BUG/MINOR: server: Set server without addr but with dns in RMAINT on startup
    - MINOR: server: Copy configuration file and line for server templates
    - BUG/MEDIUM: mux-pt: Release the tasklet during an HTTP upgrade
    - BUILD: ssl: use HAVE_OPENSSL_KEYLOG instead of OpenSSL versions
    - MINOR: debug: don't count free(NULL) in memstats
    - BUG/MINOR: filters: Skip disabled proxies during startup only
    - MINOR: mux_h2: capitalize frame type in stats
    - MINOR: mux_h2: add stat for total count of connections/streams
    - MINOR: stats: do not display empty stat module title on html
    - BUG/MEDIUM: stick-table: limit the time spent purging old entries
    - BUG/MEDIUM: listener: only enable a listening listener if needed
    - BUG/MEDIUM: listener: never suspend inherited sockets
    - BUG/MEDIUM: listener: make the master also keep workers' inherited FDs
    - MINOR: fd: add fd_want_recv_safe()
    - MEDIUM: listeners: make use of fd_want_recv_safe() to enable early receivers
    - REGTESTS: mark abns_socket as working now
    - CLEANUP: mux-h2: Remove the h1 parser state from the h2 stream
    - MINOR: sock: add a check against cross worker<->master socket activities
    - CI: github actions: limit OpenSSL no-deprecated builds to "default,bug,devel" reg-tests
    - BUG/MEDIUM: server: make it possible to kill last idle connections
    - MINOR: mworker/cli: the master CLI use its own applet
    - MINOR: ssl: define SSL_CTX_set1_curves_list to itself on BoringSSL
    - BUILD: ssl: use feature macros for detecting ec curves manipulation support
    - DOC: Add dns as an available domain to show stat
    - BUILD: makefile: usual reorder of objects for faster builds
    - DOC: update INSTALL to mention that TCC is supported
    - DOC: mention in INSTALL that haproxy 2.3 is a stable version
    - MINOR: version: mention that it's stable now
2020-11-05 17:04:53 +01:00
Daniel Corbett
c40edacbda DOC: Add dns as an available domain to show stat
Within management.txt, proxy was listed as the only available option. "dns"
is now supported so let's add that. This change also updates the command to list
the available options <dns|proxy> for "domain" as previously it only specified
<domain>, which could be confusing as a user may think this field accepts
dynamic options when it actually requires a specific keyword.
2020-11-05 16:46:24 +01:00
Willy Tarreau
bd703e5650 [RELEASE] Released version 2.3-dev9
Released version 2.3-dev9 with the following main changes :
    - CLEANUP: http_ana: remove unused assignation of `att_beg`
    - BUG/MEDIUM: ssl: OCSP must work with BoringSSL
    - BUG/MINOR: log: fix memory leak on logsrv parse error
    - BUG/MINOR: log: fix risk of null deref on error path
    - BUILD: ssl: more elegant OpenSSL early data support check
    - CI: github actions: update h2spec to 2.6.0
    - BUG/MINOR: cache: Check the return value of http_replace_res_status
    - MINOR: cache: Store the "Last-Modified" date in the cache_entry
    - MINOR: cache: Process the If-Modified-Since header in conditional requests
    - MINOR: cache: Create res.cache_hit and res.cache_name sample fetches
    - MINOR: mux-h2: register a stats module
    - MINOR: mux-h2: add counters instance to h2c
    - MINOR: mux-h2: add stats for received frame types
    - MINOR: mux-h2: report detected error on stats
    - MINOR: mux-h2: count open connections/streams on stats
    - BUG/MINOR: server: fix srv downtime calcul on starting
    - BUG/MINOR: server: fix down_time report for stats
    - BUG/MINOR: lua: initialize sample before using it
    - MINOR: cache: Add Expires header value parsing
    - MINOR: ist: Add a case insensitive istmatch function
    - BUG/MINOR: cache: Manage multiple values in cache-control header value
    - BUG/MINOR: cache: Inverted variables in http_calc_maxage function
    - MINOR: pattern: make pat_ref_append() return the newly added element
    - MINOR: pattern: make pat_ref_add() rely on pat_ref_append()
    - MINOR: pattern: export pat_ref_push()
    - CLEANUP: pattern: use calloc() rather than malloc for structures
    - CLEANUP: pattern: fix spelling/grammatical/copy-paste in comments
2020-10-31 13:17:06 +01:00
Remi Tricot-Le Breton
bf97121f1c MINOR: cache: Create res.cache_hit and res.cache_name sample fetches
Res.cache_hit sample fetch returns a boolean which is true when the HTTP
response was built out of a cache. The cache's name is returned by the
res.cache_name sample_fetch.

This resolves GitHub issue #900.
2020-10-27 18:25:43 +01:00
Willy Tarreau
fb1b9e3dec [RELEASE] Released version 2.3-dev8
Released version 2.3-dev8 with the following main changes :
    - MINOR: backend: replace the lbprm lock with an rwlock
    - MINOR: lb/map: use seek lock and read locks where appropriate
    - MINOR: lb/leastconn: only take a read lock in fwlc_get_next_server()
    - MINOR: lb/first: use a read lock in fas_get_next_server()
    - MINOR: lb/chash: use a read lock in chash_get_server_hash()
    - BUG/MINOR: disable dynamic OCSP load with BoringSSL
    - BUILD: ssl: make BoringSSL use its own version numbers
    - CLEANUP: threads: don't register an initcall when not debugging
    - MINOR: threads: change lock_t to an unsigned int
    - CLEANUP: tree-wide: reorder a few structures to plug some holes around locks
    - CLEANUP: task: remove the unused and mishandled global_rqueue_size
    - BUG/MEDIUM: connection: Never cleanup server lists when freeing private conns
    - MEDIUM: config: report that "nbproc" is deprecated
    - BUG/MINOR: listener: close before free in `listener_accept`
    - MINOR: ssl: 'ssl-load-extra-del-ext' removes the certificate extension
    - BUG/MINOR: queue: properly report redistributed connections
    - CONTRIB: tcploop: remove unused local variables in tcp_pause()
    - BUILD: makefile: add entries to build common debugging tools
    - BUG/MEDIUM: server: support changing the slowstart value from state-file
    - MINOR: http: Add `enum etag_type http_get_etag_type(const struct ist)`
    - MINOR: http: Add etag comparison function
    - MEDIUM: cache: Store the ETag information in the cache_entry
    - MEDIUM: cache: Add support for 'If-None-Match' request header
    - REGTEST: cache: Add if-none-match test case
    - CLEANUP: compression: Make use of http_get_etag_type()
    - BUG/MINOR: http-ana: Don't send payload for internal responses to HEAD requests
    - BUG/MAJOR: mux-h2: Don't try to send data if we know it is no longer possible
    - MINOR: threads/debug: only report used lock stats
    - MINOR: threads/debug: only report lock stats for used operations
    - MINOR: proxy; replace the spinlock with an rwlock
    - MINOR: server: read-lock the cookie during srv_set_dyncookie()
    - MINOR: proxy/cli: only take a read lock in "show errors"
    - OPTIM: queue: don't call pendconn_unlink() when the pendconn is not queued
    - MINOR: queue: split __pendconn_unlink() in per-srv and per-prx
    - MINOR: queue: reduce the locked area in pendconn_add()
    - OPTIM: queue: make the nbpend counters atomic
    - OPTIM: queue: decrement the nbpend and totpend counters outside of the lock
    - MINOR: leastconn: take the queue length into account when queuing servers
    - MEDIUM: fwlc: re-enable per-server queuing up to maxqueue
    - Revert "OPTIM: queue: don't call pendconn_unlink() when the pendconn is not queued"
    - MINOR: stats: support the "up" output modifier for "show stat"
    - MINOR: stats: also support a "no-maint" show stat modifier
    - MINOR: stats: indicate the number of servers in a backend's status
    - MEDIUM: ssl: ssl-load-extra-del-ext work only with .crt
    - REGTEST: ssl: test "set ssl cert" with separate key / crt
    - DOC: management: apply the "show stat" modifiers to "show stat", not "show info"
    - MINOR: stats: report server's user-configured weight next to effective weight
    - CI: travis-ci: switch to Ubuntu 20.04
    - CONTRIB: release-estimator: Add release estimating tool
    - BUG/MEDIUM: queue: fix unsafe proxy pointer when counting nbpend
    - BUG/MINOR: extcheck: add missing checks on extchk_setenv()
2020-10-24 13:14:31 +02:00
Willy Tarreau
bd71510024 MINOR: stats: report server's user-configured weight next to effective weight
The "weight" column on the stats page is somewhat confusing when using
slowstart becaue it reports the effective weight, without being really
explicit about it. In some situations the user-configured weight is more
relevant (especially with long slowstarts where it's important to know
if the configured weight is correct).

This adds a new uweight stat which reports a server's user-configured
weight, and in a backend it receives the sum of all servers' uweights.
In addition it adds the mention of "effective" in a few descriptions
for the "weight" column (help and doc).

As a result, the list of servers in a backend is now always scanned
when dumping the stats. But this is not a problem given that these
servers are already scanned anyway and for way heavier processing.
2020-10-23 22:47:30 +02:00
Willy Tarreau
698097b54c DOC: management: apply the "show stat" modifiers to "show stat", not "show info"
By mistake I added the "up" then "maint" output modifiers to the "show info"
block instead of the "show stat" one in the two previous commits 65141ffc4
("MINOR: stats: support the "up" output modifier for "show stat"") and
3e3203670 ("MINOR: stats: also support a "no-maint" show stat modifier").

No backport is needed.
2020-10-23 20:22:33 +02:00
William Lallemand
089c13850f MEDIUM: ssl: ssl-load-extra-del-ext work only with .crt
In order to be compatible with the "set ssl cert" command of the CLI,
this patch restrict the ssl-load-extra-del-ext to files with a ".crt"
extension in the configuration.

Related to issue #785.

Should be backported where 8e8581e ("MINOR: ssl: 'ssl-load-extra-del-ext'
removes the certificate extension") was backported.
2020-10-23 18:41:08 +02:00
Willy Tarreau
3e32036701 MINOR: stats: also support a "no-maint" show stat modifier
"no-maint" is a bit similar to "up" except that it will only hide
servers that are in maintenance (or disabled in the configuration), and
not those that are enabled but failed a check. One benefit here is to
significantly reduce the output of the "show stat" command when using
large server-templates containing entries that are not yet provisioned.

Note that the prometheus exporter also has such an option which does
the exact same.
2020-10-23 18:11:24 +02:00
Willy Tarreau
65141ffc4f MINOR: stats: support the "up" output modifier for "show stat"
We already had it on the HTTP interface but it was not accessible on the
CLI. It can be very convenient to hide servers which are down, do not
resolve, or are in maintenance.
2020-10-23 18:11:24 +02:00
Willy Tarreau
8ae8c48eb0 MEDIUM: fwlc: re-enable per-server queuing up to maxqueue
Leastconn has the nice propery of being able to sort servers by their
current usage. It's really a shame to force all requests into the backend
queue when the algo would be able to also consider their current queue.

In order not to change existing behavior but extend it, this patch allows
leastconn to elect servers which are already full if they have an explicitly
configured maxqueue setting above zero and their queue hasn't reached that
threshold. This will significantly reduce the pressure in the backend queue
when queuing a lot with lots of servers.

A test on 8 threads with 100 servers configured with maxconn 1 jumped
from 165krps to 330krps with maxqueue 15 with this patch.

This partially undoes commit 82cd5c13a ("OPTIM: backend: skip LB when we
know the backend is full") but allows to scale much better even by setting
a single-digit maxqueue value. Some better heuristics could be used to
maintain the behavior of the bypass in the patch above, consisting in
keeping it if it's known that there is no server with a configured
maxqueue in the farm (or in the backend).
2020-10-22 18:30:25 +02:00
Willy Tarreau
8c855f6cff MINOR: leastconn: take the queue length into account when queuing servers
When servers are queued into the leastconn tree, it's important to also
consider their queue length. There could be some servers with lots of
queued requests that we don't want to hammer with extra connections. In
order not to add extra stress to the LB algorithm, we don't update the
value when adding to the queue, only when updating the connection count
(i.e. picking from the queue or releasing a connection). This will be
sufficient to significantly improve the fairness in such situations.
2020-10-22 18:30:18 +02:00
William Lallemand
8e8581e242 MINOR: ssl: 'ssl-load-extra-del-ext' removes the certificate extension
In issue #785, users are reporting that it's not convenient to load a
".crt.key" when the configuration contains a ".crt".

This option allows to remove the extension of the certificate before
trying to load any extra SSL file (.key, .ocsp, .sctl, .issuer etc.)

The patch changes a little bit the way ssl_sock_load_files_into_ckch()
looks for the file.
2020-10-20 18:25:46 +02:00
Willy Tarreau
f42d794d96 MEDIUM: config: report that "nbproc" is deprecated
As previously discussed, nbproc usage is bad, deprecated, and scheduled
for removal in 2.5.

If "nbproc" is found with more than one process while nbthread is not
set, a warning will be emitted encouraging to remove it or to migrate
to nbthread instead. This makes sure the user has an opportunity to
both see the message and silence it.
2020-10-20 11:54:49 +02:00
Willy Tarreau
9d58c9b251 [RELEASE] Released version 2.3-dev7
Released version 2.3-dev7 with the following main changes :
    - CI: travis-ci: replace not defined SSL_LIB, SSL_INC for BotringSSL builds
    - BUG/MINOR: init: only keep rlim_fd_cur if max is unlimited
    - BUG/MINOR: mux-h2: do not stop outgoing connections on stopping
    - MINOR: fd: report an error message when failing initial allocations
    - MINOR: proto-tcp: make use of connect(AF_UNSPEC) for the pause
    - MINOR: sock: add sock_accept_conn() to test a listening socket
    - MINOR: protocol: make proto_tcp & proto_uxst report listening sockets
    - MINOR: sockpair: implement the .rx_listening function
    - CLEANUP: tcp: make use of sock_accept_conn() where relevant
    - CLEANUP: unix: make use of sock_accept_conn() where relevant
    - BUG/MINOR: listener: detect and handle shared sockets stopped in other processes
    - CONTRIB: tcploop: implement a disconnect operation 'D'
    - CLEANUP: protocol: intitialize all of the sockaddr when disconnecting
    - BUG/MEDIUM: deinit: check fdtab before fdtab[fd].owner
    - BUG/MINOR: connection: fix loop iter on connection takeover
    - BUG/MEDIUM: connection: fix srv idle count on conn takeover
    - MINOR: connection: improve list api usage
    - MINOR: mux/connection: add a new mux flag for HOL risk
    - MINOR: connection: don't check priv flag on free
    - MEDIUM: backend: add new conn to session if mux marked as HOL blocking
    - MEDIUM: backend: add reused conn to sess if mux marked as HOL blocking
    - MEDIUM: h2: remove conn from session on detach
    - MEDIUM: fcgi: remove conn from session on detach
    - DOC: Describe reuse safe for HOL handling
    - MEDIUM: proxy: remove obsolete "mode health"
    - MEDIUM: proxy: remove obsolete "monitor-net"
    - CLEANUP: protocol: remove the ->drain() function
    - CLEANUP: fd: finally get rid of fd_done_recv()
    - MINOR: connection: make sockaddr_alloc() take the address to be copied
    - MEDIUM: listener: allocate the connection before queuing a new connection
    - MINOR: session: simplify error path in session_accept_fd()
    - MINOR: connection: add new error codes for accept_conn()
    - MINOR: sock: rename sock_accept_conn() to sock_accepting_conn()
    - MINOR: protocol: add a new function accept_conn()
    - MINOR: sock: implement sock_accept_conn() to accept a connection
    - MINOR: sockpair: implement sockpair_accept_conn() to accept a connection
    - MEDIUM: listener: use protocol->accept_conn() to accept a connection
    - MEDIUM: listener: remove the second pass of fd manipulation at the end
    - MINOR: protocol: add a default I/O callback and put it into the receiver
    - MINOR: log: set the UDP receiver's I/O handler in the receiver
    - MINOR: protocol: register the receiver's I/O handler and not the protocol's
    - CLEANUP: protocol: remove the now unused <handler> field of proto_fam->bind()
    - DOC: improve the documentation for "option nolinger"
    - BUG/MEDIUM: proxy: properly stop backends
    - BUG/MEDIUM: task: bound the number of tasks picked from the wait queue at once
    - MINOR: threads: augment rwlock debugging stats to report seek lock stats
    - MINOR: threads: add the transitions to/from the seek state
    - MEDIUM: task: use an upgradable seek lock when scanning the wait queue
    - BUILD: listener: avoir a build warning when threads are disabled
    - BUG/MINOR: peers: Possible unexpected peer seesion reset after collisions.
    - MINOR: ssl: add volatile flags to ssl samples
    - MEDIUM: backend: reuse connection if using a static sni
    - BUG/MEDIUM: spoe: Unset variable instead of set it if no data provided
    - BUG/MEDIUM: mux-h1: Get the session from the H1S when capturing bad messages
    - BUG/MEDIUM: lb: Always lock the server when calling server_{take,drop}_conn
    - DOC: fix typo in MAX_SESS_STKCTR
2020-10-17 10:31:50 +02:00
Matteo Contrini
1857b8cf4d DOC: fix typo in MAX_SESS_STKCTR
MAX_SESS_STKCTR is spelled wrongly a couple of times
in the configuration docs (K and C are swapped). This patch
fixes the typos.
2020-10-17 09:37:25 +02:00
Amaury Denoyelle
7239c24986 MEDIUM: backend: reuse connection if using a static sni
Detect if the sni used a constant value and if so, allow to reuse this
connection for later sessions. Use a combination of SMP_USE_INTRN +
!SMP_F_VOLATILE to consider a sample as a constant value.

This features has been requested on github issue #371.
2020-10-16 17:48:01 +02:00
Willy Tarreau
4a32103a48 DOC: improve the documentation for "option nolinger"
This reminds the different issues caused by option nolinger, as discussed
in issue #896.
2020-10-16 04:55:19 +02:00
Willy Tarreau
0138f51f93 CLEANUP: fd: finally get rid of fd_done_recv()
fd_done_recv() used to be useful with the FD cache because it used to
allow to keep a file descriptor active in the poller without being
marked as ready in the cache, saving it from ringing immediately,
without incurring any system call. It was a way to make it yield
to wait for new events leaving a bit of time for others. The only
user left was the connection accepter (listen_accept()). We used
to suspect that with the FD cache removal it had become totally
useless since changing its readiness or not wouldn't change its
status regarding the poller itself, which would be the only one
deciding to report it again.

Careful tests showed that it indeed has exactly zero effect nowadays,
the syscall numbers are exactly the same with and without, including
when enabling edge-triggered polling.

Given that there's no more API available to manipulate it and that it
was directly called as an optimization from listener_accept(), it's
about time to remove it.
2020-10-15 21:47:56 +02:00
Willy Tarreau
9e9919dd8b MEDIUM: proxy: remove obsolete "monitor-net"
As discussed here during 2.1-dev, "monitor-net" is totally obsolete:

   https://www.mail-archive.com/haproxy@formilux.org/msg35204.html

It's fundamentally incompatible with usage of SSL, and imposes the
presence of file descriptors with hard-coded syscalls directly in the
generic accept path.

It's very unlikely that anyone has used it in the last 10 years for
anything beyond testing. In the worst case if anyone would depend
on it, replacing it with "http-request return status 200 if ..." and
"mode http" would certainly do the trick.

The keyword is still detected as special by the config parser to help
users update their configurations appropriately.
2020-10-15 21:47:04 +02:00
Willy Tarreau
77e0daef9f MEDIUM: proxy: remove obsolete "mode health"
As discussed here during 2.1-dev, "mode health" is totally obsolete:

   https://www.mail-archive.com/haproxy@formilux.org/msg35204.html

It's fundamentally incompatible with usage of SSL, doesn't support
source filtering, and imposes the presence of file descriptors with
hard-coded syscalls directly in the generic accept path.

It's very unlikely that anyone has used it in the last 10 years for
anything beyond testing. In the worst case if anyone would depend
on it, replacing it with "http-request return status 200" and "mode
http" would certainly do the trick.

The keyword is still detected as special by the config parser to help
users update their configurations appropriately.
2020-10-15 21:47:04 +02:00
Amaury Denoyelle
2717965387 DOC: Describe reuse safe for HOL handling
Explain the special case of server connections using a protocol subject
to HOL on http-reuse safe mode.
2020-10-15 15:19:34 +02:00
Willy Tarreau
b7ffe1975a [RELEASE] Released version 2.3-dev6
Released version 2.3-dev6 with the following main changes :
    - REGTESTS: use "command" instead of "which" for better POSIX compatibility
    - BUILD: makefile: Update feature flags for OpenBSD
    - DOC: agent-check: fix typo in "fail" word expected reply
    - DOC: crt: advise to move away from cert bundle
    - BUG/MINOR: ssl/crt-list: exit on warning out of crtlist_parse_line()
    - REGTEST: fix host part in balance-uri-path-only.vtc
    - REGTEST: make ssl_client_samples and ssl_server_samples requiret to 2.3
    - REGTEST: the iif converter test requires 2.3
    - REGTEST: make agent-check.vtc require 1.8
    - REGTEST: make abns_socket.vtc require 1.8
    - REGTEST: make map_regm_with_backref require 1.7
    - BUILD: makefile: Update feature flags for FreeBSD
    - OPTIM: backend/random: never queue on the server, always on the backend
    - OPTIM: backend: skip LB when we know the backend is full
    - BUILD: makefile: Fix building with closefrom() support enabled
    - BUILD: makefile: add an EXTRAVERSION variable to ease local naming
    - MINOR: tools: support for word expansion of environment in parse_line
    - BUILD: tools: fix minor build issue on isspace()
    - BUILD: makefile: Enable closefrom() support on Solaris
    - CLEANUP: ssl: Use structured format for error line report during crt-list parsing
    - MINOR: ssl: Add error if a crt-list might be truncated
    - MINOR: ssl: remove uneeded check in crtlist_parse_file
    - BUG/MINOR: Fix several leaks of 'log_tag' in init().
    - DOC: tcp-rules: Refresh details about L7 matching for tcp-request content rules
    - MEDIUM: tcp-rules: Warn if a track-sc* content rule doesn't depend on content
    - BUG/MINOR: tcpcheck: Set socks4 and send-proxy flags before the connect call
    - DOC: ssl: new "cert bundle" behavior
    - BUG/MEDIUM: queue: make pendconn_cond_unlink() really thread-safe
    - CLEANUP: ssl: "bundle" is not an OpenSSL wording
    - MINOR: counters: fix a typo in comment
    - BUG/MINOR: stats: fix validity of the json schema
    - REORG: stats: export some functions
    - MINOR: stats: add stats size as a parameter for csv/json dump
    - MINOR: stats: hide px/sv/li fields in applet struct
    - REORG: stats: extract proxy json dump
    - REORG: stats: extract proxies dump loop in a function
    - MINOR: hlua: Display debug messages on stderr only in debug mode
    - MINOR: stats: define the concept of domain for statistics
    - MINOR: stats: define additional flag px cap on domain
    - MEDIUM: stats: add delimiter for static proxy stats on csv
    - MEDIUM: stats: define an API to register stat modules
    - MEDIUM: stats: add abstract type to store counters
    - MEDIUM: stats: integrate static proxies stats in new stats
    - MINOR: stats: support clear counters for dynamic stats
    - MINOR: stats: display extra proxy stats on the html page
    - MINOR: stats: add config "stats show modules"
    - MINOR: dns/stats: integrate dns counters in stats
    - MINOR: stats: remove for loop declaration
    - DOC: ssl: fix typo about ocsp files
    - BUG/MINOR: peers: Inconsistency when dumping peer status codes.
    - DOC: update INSTALL with supported OpenBSD / FreeBSD versions
    - BUG/MINOR: proto_tcp: Report warning messages when listeners are bound
    - CLEANUP: cache: Fix leak of cconf->c.name during config check
    - CLEANUP: ssl: Release cached SSL sessions on deinit
    - BUG/MINOR: mux-h1: Be sure to only set CO_RFL_READ_ONCE for the first read
    - BUG/MINOR: mux-h1: Always set the session on frontend h1 stream
    - MINOR: mux-h1: Don't wakeup the H1C when output buffer become available
    - CLEANUP: sock-unix: Remove an unreachable goto clause
    - BUG/MINOR: proxy: inc req counter on new syslog messages.
    - BUG/MEDIUM: log: old processes with log foward section don't die on soft stop.
    - MINOR: stats: inc req counter on listeners.
    - MINOR: channel: new getword and getchar functions on channel.
    - MEDIUM: log: syslog TCP support on log forward section.
    - BUG/MINOR: proxy/log: frontend/backend and log forward names must differ
    - DOC: re-work log forward bind statement documentation.
    - DOC: fix a confusing typo on a regsub example
    - BUILD: Add a DragonFlyBSD target
    - BUG/MINOR: makefile: fix a tiny typo in the target list
    - BUILD: makefile: Update feature flags for NetBSD
    - CI: travis-ci: help Coverity to detect BUG_ON() as a real stop
    - DOC: Add missing stats fields in the management doc
    - BUG/MEDIUM: mux-fcgi: Don't handle pending read0 too early on streams
    - BUG/MEDIUM: mux-h2: Don't handle pending read0 too early on streams
    - DOC: Fix typos in configuration.txt
    - BUG/MINOR: http: Fix content-length of the default 500 error
    - BUG/MINOR: http-htx: Expect no body for 204/304 internal HTTP responses
    - REGTESTS: mark abns_socket as broken
    - MEDIUM: fd: always wake up one thread when enabling a foreing FD
    - MEDIUM: listeners: don't bounce listeners management between queues
    - MEDIUM: init: stop disabled proxies after initializing fdtab
    - MEDIUM: listeners: make unbind_listener() converge if needed
    - MEDIUM: deinit: close all receivers/listeners before scanning proxies
    - MEDIUM: listeners: remove the now unused ZOMBIE state
    - MINOR: listeners: do not uselessly try to close zombie listeners in soft_stop()
    - CLEANUP: proxy: remove the first_to_listen hack in zombify_proxy()
    - MINOR: listeners: introduce listener_set_state()
    - MINOR: proxy: maintain per-state counters of listeners
    - MEDIUM: proxy: remove the unused PR_STFULL state
    - MEDIUM: proxy: remove the PR_STERROR state
    - MEDIUM: proxy: remove state PR_STPAUSED
    - MINOR: startup: don't rely on PR_STNEW to check for listeners
    - CLEANUP: peers: don't use the PR_ST* states to mark enabled/disabled
    - MEDIUM: proxy: replace proxy->state with proxy->disabled
    - MEDIUM: proxy: remove start_proxies()
    - MEDIUM: proxy: merge zombify_proxy() with stop_proxy()
    - MINOR: listeners: check the current listener state in pause_listener()
    - MINOR: listeners: check the current listener earlier state in resume_listener()
    - MEDIUM: listener/proxy: make the listeners notify about proxy pause/resume
    - MINOR: protocol: introduce protocol_{pause,resume}_all()
    - MAJOR: signals: use protocol_pause_all() and protocol_resume_all()
    - CLEANUP: proxy: remove the now unused pause_proxies() and resume_proxies()
    - MEDIUM: proto_tcp: make the pause() more robust in multi-process
    - BUG/MEDIUM: listeners: correctly report pause() errors
    - MINOR: listeners: move fd_stop_recv() to the receiver's socket code
    - CLEANUP: protocol: remove the ->disable_all method
    - CLEANUP: listeners: remove unused disable_listener and disable_all_listeners
    - MINOR: listeners: export enable_listener()
    - MINOR: protocol: directly call enable_listener() from protocol_enable_all()
    - CLEANUP: protocol: remove the ->enable_all method
    - CLEANUP: listeners: remove the now unused enable_all_listeners()
    - MINOR: protocol: rename the ->listeners field to ->receivers
    - MINOR: protocol: replace ->pause(listener) with ->rx_suspend(receiver)
    - MINOR: protocol: implement an ->rx_resume() method
    - MINOR: listener: use the protocol's ->rx_resume() method when available
    - MINOR: sock: provide a set of generic enable/disable functions
    - MINOR: protocol: add a new pair of rx_enable/rx_disable methods
    - MINOR: protocol: add a new pair of enable/disable methods for listeners
    - MEDIUM: listeners: now use the listener's ->enable/disable
    - MINOR: listeners: split delete_listener() in two versions
    - MINOR: listeners: count unstoppable jobs on creation, not deletion
    - MINOR: listeners: add a new stop_listener() function
    - MEDIUM: proxy: make stop_proxy() now use stop_listener()
    - MEDIUM: proxy: add mode PR_MODE_PEERS to flag peers frontends
    - MEDIUM: proxy: centralize proxy status update and reporting
    - MINOR: protocol: add protocol_stop_now() to instant-stop listeners
    - MEDIUM: proxy: make soft_stop() stop most listeners using protocol_stop_now()
    - MEDIUM: udp: implement udp_suspend() and udp_resume()
    - MINOR: listener: add a few BUG_ON() statements to detect inconsistencies
    - MEDIUM: listeners: always close master vs worker listeners
    - BROKEN/MEDIUM: listeners: rework the unbind logic to make it idempotent
    - MEDIUM: listener: let do_unbind_listener() decide whether to close or not
    - CLEANUP: listeners: remove the do_close argument to unbind_listener()
    - MINOR: listeners: move the LI_O_MWORKER flag to the receiver
    - MEDIUM: receivers: add an rx_unbind() method in the protocols
    - MINOR: listeners: split do_unbind_listener() in two
    - MEDIUM: listeners: implement protocol level ->suspend/resume() calls
    - MEDIUM: config: mark "grace" as deprecated
    - MEDIUM: config: remove the deprecated and dangerous global "debug" directive
    - BUG/MINOR: proxy: respect the proper format string in sig_pause/sig_listen
    - MINOR: peers: heartbeat, collisions and handshake information for "show peers" command.
    - BUILD: makefile: Enable getaddrinfo() on OS/X
2020-10-10 10:45:13 +02:00
Willy Tarreau
ccf429960b MEDIUM: config: remove the deprecated and dangerous global "debug" directive
This one was scheduled for removal in 2.3 since 2.2-dev3 by commit
1b85785bc ("MINOR: config: mark global.debug as deprecated"). Let's
remove it now. It remains totally possible to use -d on the command
line though.
2020-10-09 19:18:45 +02:00
Willy Tarreau
ab0a5192a8 MEDIUM: config: mark "grace" as deprecated
This was introduced 15 years ago or so to delay the stopping of some
services so that a monitoring device could detect its port being down
before services were stopped. Since then, clean reloads were implemented
and this doesn't cope well with reload at all, preventing the new process
from seamlessly binding, and forcing processes to coexist with half-baked
configurations.

Now it has become a real problem because there's a significant code
portion in the proxies that is solely dedicated to this obsolete feature,
and dealing with its special cases eases the introduction of bugs in
other places so it's about time that it goes.

We could tentatively schedule its removal for 2.4 with a hard deadline
for 2.5 in any case.
2020-10-09 19:07:01 +02:00
Willy Tarreau
c6dac6c7f5 MEDIUM: listeners: remove the now unused ZOMBIE state
The zombie state is not used anymore by the listeners, because in the
last two cases where it was tested it couldn't match as it was covered
by the test on the process mask. Instead now the FD is either in the
LISTEN state or the INIT state. This also avoids forcing the listener
to be single-dimensional because actually belonging to another process
isn't totally exclusive with the other states, which explains some of
the difficulties requiring to check the proc_mask and the fd sometimes.

So let's get rid of it now not to be tempted to reuse it.

The doc on the listeners state was updated.
2020-10-09 11:27:29 +02:00
Sébastien Gross
ab8771285c DOC: Fix typos in configuration.txt
This patch fixes small typos and grammar in configuration.txt for the
http-request return documentation.
2020-10-09 10:02:09 +02:00
Pierre Cheynier
08eb718494 DOC: Add missing stats fields in the management doc
Added latest fields: idle_conn_cur, safe_conn_cur, used_conn_cur, need_conn_est
2020-10-09 09:56:37 +02:00
Willy Tarreau
465dc7d63f DOC: fix a confusing typo on a regsub example
Sbastien reported a confusing example in the doc about regsub when used
with quotes. Nested quotes are already not trivial to grasp, but when
typos are there and result in something valid, it's even worse. The closing
quote ought to have been inside the brackets. However haproxy will not make
any difference because the single quotes delimit a word and the delimited
word remains the same. Let's just not add yet another level of confusion.
2020-10-08 18:05:56 +02:00