Commit Graph

20005 Commits

Author SHA1 Message Date
Christopher Faulet
872b01c984 MINOR: mux-pt: Report end-of-input with the end-of-stream after a read
In the PT multiplexer, the end of stream is also the end of input. Thus
we must report EOI to the stream-endpoint descriptor when the EOS is
reported. For now, it is a bit useless but it will be important to
disginguish an shutdown to an error to an abort.

To be sure to not report an EOI on an error, the errors are now handled
first.
2023-04-05 08:57:05 +02:00
Christopher Faulet
84d3ef982c MINOR: stconn/channel: Move CF_EXPECT_MORE into the SC and rename it
The channel flag CF_EXPECT_MORE is renamed to SC_FL_SND_EXP_MORE and moved
into the stream-connector.
2023-04-05 08:57:05 +02:00
Christopher Faulet
68ef218a72 MINOR: stconn/channel: Move CF_NEVER_WAIT into the SC and rename it
The channel flag CF_NEVER_WAIT is renamed to SC_FL_SND_NEVERWAIT and moved
into the stream-connector.
2023-04-05 08:57:05 +02:00
Christopher Faulet
5c281d58ea MINOR: stconn/channel: Move CF_SEND_DONTWAIT into the SC and rename it
The channel flag CF_SEND_DONTWAIT is renamed to SC_FL_SND_ASAP and moved
into the stream-connector.
2023-04-05 08:57:05 +02:00
Christopher Faulet
9a790f63ed MINOR: stconn/channel: Move CF_READ_DONTWAIT into the SC and rename it
The channel flag CF_READ_DONTWAIT is renamed to SC_FL_RCV_ONCE and moved
into the stream-connector.
2023-04-05 08:57:05 +02:00
Christopher Faulet
9bce9724ec MINOR: stconn: Remove unecessary test on SE_FL_EOS before receiving data
In sc_conn_recv(), if the EOS is reported by the endpoint, it will always be
acknowledged by the SC and a read0 will be performed on the input
channel. Thus there is no reason to still test at the begining of the
function because there is already a test on CF_SHUTR.
2023-04-05 08:57:05 +02:00
Christopher Faulet
28975e1e10 BUG/MEDIUM: dns: Properly handle error when a response consumed
When a response is consumed, result for co_getblk() is never checked. It
seems ok because amount of output data is always checked first. But There is
an issue when we try to get the first 2 bytes to read the message length. If
there is only one byte followed by a shutdown, the applet ignore the
shutdown and loop till the timeout to get more data.

So to avoid any issue and improve shutdown detection, the co_getblk() return
value is always tested. In addition, if there is not enough data, the applet
explicitly ask for more data by calling applet_need_more_data().

This patch relies on the previous one:

   * BUG/MEDIUM: channel: Improve reports for shut in co_getblk()

Both should be backported as far as 2.4. On 2.5 and 2.4,
applet_need_more_data() must be replaced by si_rx_endp_more().
2023-04-05 08:57:05 +02:00
Christopher Faulet
5f5c94617e BUG/MEDIUM: channel: Improve reports for shut in co_getblk()
When co_getblk() is called with a length and an offset to 0, shutdown is
never reported. It may be an issue when the function is called to retrieve
all available output data, while there is no output data at all. And it
seems pretty annoying to handle this case in the caller.

Thus, now, in co_getblk(), -1 is returned when the channel is empty and a
shutdown was received.

There is no real reason to backport this patch alone. However, another fix
will rely on it.
2023-04-05 08:57:05 +02:00
Christopher Faulet
2726624ee7 CLEANUP: stconn: Remove remaining debug messages
It is now possible to enable traces for applets. Thus we can remove annoying
debug messages (DPRINTF) to track calls to applets.
2023-04-05 08:57:05 +02:00
Christopher Faulet
26e0935681 MEDIUM: applet/trace: Register a new trace source with its events
Traces are now supported for applets. The first argument is always the
appctx. This will help to debug applets.
2023-04-05 08:46:06 +02:00
Christopher Faulet
a5915eb1dd MINOR: applet: Uninline appctx_free()
This functin is uninlined and move in src/applet.c. It is mandatory to add
traces for applets.
2023-04-05 08:46:06 +02:00
Christopher Faulet
947b2e5922 BUG/MINOR: stream: Fix test on channels flags to set clientfin/serverfin touts
There is a bug in a way the channels flags are checked to set clientfin or
serverfin timeout. Indeed, to set the clientfin timeout, the request channel
must be shut for reads (CF_SHUTR) or the response channel must be shut for
writes (CF_SHUTW). As the opposite, the serverfin timeout must be set when
the request channel is shut for writes (CF_SHUTW) or the response channel is
shut for reads (CF_SHUTR).

It is a 2.8-dev specific issue. No backport needed.
2023-04-05 08:46:06 +02:00
Christopher Faulet
c665bb5637 BUG/MEDIUM: stconn: Add a missing return statement in sc_app_shutr()
In the commut b08c5259e ("MINOR: stconn: Always report READ/WRITE event on
shutr/shutw"), a return statement was erroneously removed from
sc_app_shutr(). As a consequence, CF_SHUTR flags was never set. Fortunately,
it is the default .shutr callback function. Thus when a connection or an
applet is attached to the SC, another callback is used to performe a
shutdown for reads.

It is a 28-dev specific issue. No backport needed.
2023-04-05 08:46:06 +02:00
Christopher Faulet
a664aa6a68 BUG/MINOR: tcpcheck: Be able to expect an empty response
It is not possible to successfully match an empty response. However using
regex, it should be possible to reject response with any content. For
instance:

   tcp-check expect !rstring ".+"

It may seem a be strange to do that, but it is possible, it is a valid
config. So it must work. Thanks to this patch, it is now really supported.

This patch may be backported as far as 2.2. But only if someone ask for it.
2023-04-05 08:46:06 +02:00
Frédéric Lécaille
0222cc6366 BUG/MINOR: quic: Possible wrong PTO computing
As timestamps based on now_ms values are used to compute the probing timeout,
they may wrap. So, use ticks API to compared them.

Must be backported to 2.7 and 2.6.
2023-04-04 18:24:28 +02:00
Frédéric Lécaille
fdb1494985 BUILD: quic: 32bits compilation issue in cli_io_handler_dump_quic()
Replaced a %zu printf format by %llu for an uint64_t.

Must be backported to 2.7.
2023-04-04 18:24:28 +02:00
Frédéric Lécaille
92f4a7c614 BUG/MINOR: quic: Wrong idle timer expiration (during 20s)
This this commit, this is ->idle_expire of quic_conn struct which must
be taken into an account to display the idel timer task expiration value:

     MEDIUM: quic: Ack delay implementation

Furthermore, this value was always zero until now_ms has wrapped (20 s after
the start time) due to this commit:
     MEDIUM: clock: force internal time to wrap early after boot

Do not rely on the value of now_ms compared to ->idle_expire to display the
difference but use ticks_remain() to compute it.

Must be backported to 2.7 where "show quic" has already been backported.
2023-04-04 18:24:28 +02:00
Frédéric Lécaille
12eca3a727 BUG/MINOR: quic: Unexpected connection closures upon idle timer task execution
This bug arrived with this commit:

      MEDIUM: quic: Ack delay implementation

It is possible that the idle timer task was already in the run queue when its
->expire field was updated calling qc_idle_timer_do_rearm(). To prevent this
task from running in this condition, one must check its ->expire field value
with this condition to run the task if its timer has really expired:

	!tick_is_expired(t->expire, now_ms)

Furthermore, as this task may be directly woken up with a call to task_wakeup()
all, for instance by qc_kill_conn() to kill the connection, one must check this
task has really been woken up when it was in the wait queue and not by a direct
call to task_wakeup() thanks to this test:

	(state & TASK_WOKEN_ANY) == TASK_WOKEN_TIMER

Again, when this condition is not fulfilled, the task must be run.

Must be backported where the commit mentionned above was backported.
2023-04-04 18:24:28 +02:00
Frédéric Lécaille
495968ed51 MINOR: quic: Add trace to debug idle timer task issues
Add TRACE_PROTO() call where this is relevant to debug issues about
qc_idle_timer_task() issues.

Must be backported to 2.6 and 2.7.
2023-04-04 18:24:28 +02:00
William Lallemand
5c099351d1 DOC: config: strict-sni allows to start without certificate
The strict-sni keyword allows to start without certificate on a bind
line.

Must be backported as far as 2.2.
2023-04-04 16:28:58 +02:00
Willy Tarreau
db12c0dd10 MINOR: http-act: emit a warning when a header field name contains forbidden chars
As found in issue #2089, it's easy to mistakenly paste a colon in a
header name, or other chars (e.g. spaces) when quotes are in use, and
this causes all sort of trouble in field because such chars are rejected
by the peer.

Better try to detect these upfront. That's what we're doing here during
the parsing of the add-header/set-header/early-hint actions, where a
warning is emitted if a non-token character is found in a header name.
A special case is made for the colon at the beginning so that it remains
possible to place any future pseudo-headers that may appear. E.g:

  [WARNING]  (14388) : config : parsing [badchar.cfg:23] : header name 'X-Content-Type-Options:' contains forbidden character ':'.

This should be backported to 2.7, and ideally it should be turned to an
error in future versions.
2023-04-04 05:38:01 +02:00
Frédéric Lécaille
c877bd4ea5 BUG/MINOR: quic: Remove useless BUG_ON() in newreno and cubic algo implementation
As now_ms may be zero, these BUG_ON() could be triggered when its value has wrapped.
These call to BUG_ON() may be removed because the values they was supposed to
check are safely used by the ticks API.

Must be backported to 2.6 and 2.7.
2023-04-03 13:15:56 +02:00
Remi Tricot-Le Breton
26e1432436 BUG/MINOR: ssl: Undefined reference when building with OPENSSL_NO_DEPRECATED
If OPENSSL_NO_DEPRECATED is set, we get a 'error: ‘RSA_PKCS1_PADDING’
undeclared' when building jwt.c. The symbol is not deprecated, we are
just missing an include.

This was raised in GitHub issue #2098.
It does not need to be backported.
2023-04-03 11:46:54 +02:00
Frédéric Lécaille
7d6270a845 BUG/MAJOR: quic: Congestion algorithms states shared between the connection
This very old bug is there since the first implementation of newreno congestion
algorithm implementation. This was a very bad idea to put a state variable
into quic_cc_algo struct which only defines the congestion control algorithm used
by a QUIC listener, typically its type and its callbacks.
This bug could lead to crashes since BUG_ON() calls have been added to each algorithm
implementation. This was revealed by interop test, but not very often as there was
not very often several connections run at the time during these tests.

Hopefully this was also reported by Tristan in GH #2095.

Move the congestion algorithm state to the correct structures which are private
to a connection (see cubic and nr structs).

Must be backported to 2.7 and 2.6.
2023-04-02 13:10:13 +02:00
Frédéric Lécaille
de2ba8640b MINOR: quic: Add missing traces in cubic algorithm implementation
May be useful to debug.

Must be backported to 2.7 and 2.6.
2023-04-02 13:10:08 +02:00
Frédéric Lécaille
db54847212 BUG/MINOR: quic: Cubic congestion control window may wrap
Add a check to prevent the cubic congestion control from wrapping (very low risk)
in slow start callback.

Must be backported to 2.6 and 2.7.
2023-04-02 13:10:07 +02:00
Frédéric Lécaille
23b8eef05b BUG/MINOR: quic: Remaining useless statements in cubic slow start callback
When entering a recovery period, the algo state is set by quic_enter_recovery().
And that's it!. These two lines should have been removed with this commit:

     BUG/MINOR: quic: Wrong use of now_ms timestamps (cubic algo)

Take the opportunity of this patch to add a missing TRACE_LEAVE() call in
quic_cc_cubic_ca_cb().

Must be backported to 2.7 and 2.6.
2023-04-02 13:10:04 +02:00
Ilya Shipitsin
d481ed3fa0 CI: exclude doc/{design-thoughts,internals} from spell check
as those directories do contain many documents written in French,
codespell is catching a lot of false positives scanning them.
2023-04-01 18:34:10 +02:00
Ilya Shipitsin
07be66d21b CLEANUP: assorted typo fixes in the code and comments
This is 35th iteration of typo fixes
2023-04-01 18:33:40 +02:00
Ilya Shipitsin
7e6e0388d6 CI: run smoke tests on config syntax to check memory related issues
config syntax check seems add a value on testing code path not
covered by VTest, also checks are very fast
2023-04-01 18:30:52 +02:00
Frédéric Lécaille
db4bc6b4f3 MINOR: quic: Add a fake congestion control algorithm named "nocc"
This algorithm does nothing except initializing the congestion control window
to a fixed value. Very smart!

Modify the QUIC congestion control configuration parser to support this new
algorithm. The congestion control algorithm must be set as follows:

     quic-cc-algo nocc-<cc window size(KB))

For instance if "nocc-15" is provided as quic-cc-algo keyword value, this
will set a fixed window of 15KB.
2023-03-31 17:09:03 +02:00
Willy Tarreau
1cb041a6ee MINOR: cli: support filtering on FD types in "show fd"
Depending on what we're debugging, some FDs can represent pollution in
the "show fd" output. Here we add a set of filters allowing to pick (or
exclude) any combination of listener, frontend conn, backend conn, pipes,
etc. "show fd l" will only list listening connections for example.
2023-03-31 16:35:53 +02:00
Frédéric Lécaille
5d5afe7900 BUG/MINOR: quic: Wrong rtt variance computing
In ->srtt quic_loss struct this is 8*srtt which is stored so that not to have to multiply/devide
it to compute the RTT variance (at least). This is where there was a bug in quic_loss_srtt_update():
each time ->srtt must be used, it must be devided by 8 or right shifted by 3.
This bug had a very bad impact for network with non negligeable packet loss.

Must be backported to 2.6 and 2.7.
2023-03-31 13:41:17 +02:00
Frédéric Lécaille
d721571d26 MEDIUM: quic: Ack delay implementation
Reuse the idle timeout task to delay the acknowledgments. The time of the
idle timer expiration is for now on stored in ->idle_expire. The one to
trigger the acknowledgements is stored in ->ack_expire.
Add QUIC_FL_CONN_ACK_TIMER_FIRED new connection flag to mark a connection
as having its acknowledgement timer been triggered.
Modify qc_may_build_pkt() to prevent the sending of "ack only" packets and
allows the connection to send packet when the ack timer has fired.
It is possible that acks are sent before the ack timer has triggered. In
this case it is cancelled only if ACK frames are really sent.
The idle timer expiration must be set again when the ack timer has been
triggered or when it is cancelled.

Must be backported to 2.7.
2023-03-31 13:41:17 +02:00
Frédéric Lécaille
8f991948f5 MINOR: quic: Traces adjustments at proto level.
Dump variables displayed by TRACE_ENTER() or TRACE_LEAVE() by calls to TRACE_PROTO().
No more variables are displayed by the two former macros. For now on, these information
are accessible from proto level.
Add new calls to TRACE_PROTO() at important locations in relation whith QUIC transport
protocol.
When relevant, try to prefix such traces with TX or RX keyword to identify the
concerned subpart (transmission or reception) of the protocol.

Must be backported to 2.7.
2023-03-31 09:54:59 +02:00
Frédéric Lécaille
acc9cfdf79 MINOR: quic: Adjustments for generic control congestion traces
Display the elapsed time since packets were sent in place of the timestamp which
do not bring easy to read information.

Must be backported to 2.7.
2023-03-31 09:54:59 +02:00
Frédéric Lécaille
01314b8b53 MINOR: quic: Implement cubic state trace callback
This callback was left as not implemented. It should at least display
the algorithm state, the control congestion window the slow start threshold
and the time of the current recovery period. Should be helpful to debug.

Must be backported to 2.7.
2023-03-31 09:54:59 +02:00
Frédéric Lécaille
deb978149a BUG/MINOR: quic: Missing max_idle_timeout initialization for the connection
This bug was revealed by handshakeloss interop tests (often with quiceh) where one
could see haproxy an Initial packet without TLS ClientHello message (only a padded
PING frame). In this case, as the ->max_idle_timeout was not initialized, the
connection was closed about three seconds later, and haproxy opened a new one with
a new source connection ID upon receipt of the next client Initial packet. As the
interop runner count the number of source connection ID used by the server to check
there were exactly 50 such IDs used by the server, it considered the test as failed.

So, the ->max_idle_timeout of the connection must be at least initialized
to the local "max_idle_timeout" transport parameter value to avoid such
a situation (closing connections too soon) until it is "negotiated" with the
client when receiving its TLS ClientHello message.

Must be backported to 2.7 and 2.6.
2023-03-31 09:54:59 +02:00
Frédéric Lécaille
8e6c6611e8 BUG/MINOR: quic: Wrong use of now_ms timestamps (newreno algo)
This patch is similar to the one for cubic algorithm:
    "BUG/MINOR: quic: Wrong use of timestamps with now_ms variable (cubic algo)"

As now_ms may wrap, one must use the ticks API to protect the cubic congestion
control algorithm implementation from side effects due to this.

Furthermore, to make the newreno congestion control algorithm more readable and easy
to maintain, add quic_cc_cubic_rp_cb() new callback for the "in recovery period"
state (QUIC_CC_ST_RP).

Must be backported to 2.7 and 2.6.
2023-03-31 09:54:59 +02:00
Frédéric Lécaille
a3772e1134 MINOR: quic: Add recovery related information to "show quic"
Add ->srtt, ->rtt_var, ->rtt_min and ->pto_count values from ->path->loss
struct to "show quic". Same thing for ->cwnd from ->path struct.

Also take the opportunity of this patch to dump the packet number
space information directly from ->pktns[] array in place of ->els[]
array. Indeed, ->els[QUIC_TLS_ENC_LEVEL_EARLY_DATA] and ->els[QUIC_TLS_ENC_LEVEL_APP]
have the same packet number space.

Must be backported to 2.7 where "show quic" implementation has alredy been
backported.
2023-03-31 09:54:59 +02:00
Frédéric Lécaille
d7243318c4 BUG/MINOR: quic: Wrong use of now_ms timestamps (cubic algo)
As now_ms may wrap, one must use the ticks API to protect the cubic congestion
control algorithm implementation from side effects due to this.

Furthermore to make the cubic congestion control algorithm more readable and easy
to maintain, adding a new state ("in recovery period" QUIC_CC_ST_RP new enum) helps
in reaching this goal. Implement quic_cc_cubic_rp_cb() which is the callback for
this new state.

Must be backported to 2.7 and 2.6.
2023-03-31 09:54:59 +02:00
Remi Tricot-Le Breton
6549f53fb6 BUG/MINOR: ssl: ssl-(min|max)-ver parameter not duplicated for bundles in crt-list
If a bundle is used in a crt-list, the ssl-min-ver and ssl-max-ver
options were not taken into account in entries other than the first one
because the corresponding fields in the ssl_bind_conf structure were not
copied in crtlist_dup_ssl_conf.

This should fix GitHub issue #2069.
This patch should be backported up to 2.4.
2023-03-31 09:11:51 +02:00
Remi Tricot-Le Breton
d32c8e3ccb BUG/MINOR: ssl: Fix potential leak in cli_parse_update_ocsp_response
In some extremely unlikely case (or even impossible for now), we might
exit cli_parse_update_ocsp_response without raising an error but with a
filled 'err' buffer. It was not properly free'd.

It does not need to be backported.
2023-03-31 09:10:36 +02:00
Remi Tricot-Le Breton
ae5187721f BUG/MINOR: ssl: Remove dead code in cli_parse_update_ocsp_response
This patch removes dead code from the cli_parse_update_ocsp_response
function. The 'end' label in only used in case of error so the check of
the 'errcode' variable and the errcode variable itself become useless.

This patch does not need to be backported.
It fixes GitHub issue #2077.
2023-03-31 09:08:28 +02:00
Aurelien DARRAGON
7e64d8720e BUG/MINOR: backend: make be_usable_srv() consistent when stopping
When a proxy enters the STOPPED state, it will no longer accept new
connections.

However, it doesn't mean that it's completely inactive yet: it will
still be able to handle already pending / keep-alive connections,
thus finishing ongoing work before effectively stopping.

be_usable_srv(), which is used by nbsrv converter and sample fetch,
will return 0 if the proxy is either stopped or disabled.

nbsrv behaves this way since it was originally implemented in b7e7c4720
("MINOR: Add nbsrv sample converter").

(Since then, multiple refactors were performed around this area, but
the current implementation still follows the same logic)

It was found that if nbsrv is used in a proxy section to perform routing
logic, unexpected decisions are being made when nbsrv is used on a proxy
with STOPPED state, since in-flight requests will suffer from nbsrv
returning 0 instead of the current number of usable servers which may
still process existing connections.
For instance, this can happen during process soft-stop, or even when
stopping the proxy from the cli / lua.

To fix this: we now make sure be_usable_srv() always returns the
current number of usable servers, unless the proxy is explicitly
disabled (from the config, not at runtime)

This could be backported up to 2.6.
For older versions, the need for a backport should be evaluated first.

--
Note for 2.4: proxy flags did not exist, it was implemented with fd10ab5e
("MINOR: proxy: Introduce proxy flags to replace disabled bitfield")

For 2.2: STOPPED and DISABLED states were not separated, so we have no
easy way to apply the fix anyway.
2023-03-31 07:45:08 +02:00
Aurelien DARRAGON
7f01f0a8ef BUG/MEDIUM: proxy/sktable: prevent watchdog trigger on soft-stop
During soft-stop, manage_proxy() (p->task) will try to purge
trashable (expired and not referenced) sticktable entries,
effectively releasing the process memory to leave some space
for new processes.

This is done by calling stktable_trash_oldest(), immediately
followed by a pool_gc() to give the memory back to the OS.

As already mentioned in dfe7925 ("BUG/MEDIUM: stick-table:
limit the time spent purging old entries"), calling
stktable_trash_oldest() with a huge batch can result in the function
spending too much time searching and purging entries, and ultimately
triggering the watchdog.

Lately, an internal issue was reported in which we could see
that the watchdog is being triggered in stktable_trash_oldest()
on soft-stop (thus initiated by manage_proxy())

According to the report, the crash seems to only occur since 5938021
("BUG/MEDIUM: stick-table: do not leave entries in end of window during purge")

This could be the result of stktable_trash_oldest() now working
as expected, and thus spending a large amount of time purging
entries when called with a large enough <to_batch>.

Instead of adding new checks in stktable_trash_oldest(), here we
chose to address the issue directly in manage_proxy().

Since the stktable_trash_oldest() function is called with
<to_batch> == <p->table->current>, it's pretty obvious that it could
cause some issues during soft-stop if a large table, assuming it is
full prior to the soft-stop, suddenly sees most of its entries
becoming trashable because of the soft-stop.

Moreover, we should note that the call to stktable_trash_oldest() is
immediately followed by a call to pool_gc():

We know for sure that pool_gc(), as it involves malloc_trim() on
glibc, is rather expensive, and the more memory to reclaim,
the longer the call.

We need to ensure that both stktable_trash_oldest() + consequent
pool_gc() call both theoretically fit in a single task execution window
to avoid contention, and thus prevent the watchdog from being triggered.

To do this, we now allocate a "budget" for each purging attempt.
budget is maxed out to 32K, it means that each sticktable cleanup
attempt will trash at most 32K entries.

32K value is quite arbitrary here, and might need to be adjusted or
even deducted from other parameters if this fails to properly address
the issue without introducing new side-effects.
The goal is to find a good balance between the max duration of each
cleanup batch and the frequency of (expensive) pool_gc() calls.

If most of the budget is actually spent trashing entries, then the task
will immediately be rescheduled to continue the purge.
This way, the purge is effectively batched over multiple task runs.

This may be slowly backported to all stable versions.
[Please note that this commit depends on 6e1fe25 ("MINOR: proxy/pool:
prevent unnecessary calls to pool_gc()")]
2023-03-31 07:05:08 +02:00
Martin DOLEZ
d3e58f8d69 REGTESTS : Add test support for case insentitive for url_param
Test using case insensitive is supported in /reg-tests/http-rules/h1or2_to_h1c.vtc
2023-03-30 15:32:14 +02:00
Martin DOLEZ
28c5f40ad6 MINOR: http_fetch: Add case-insensitive argument for url_param/urlp_val
This commit adds a new optional argument to smp_fetch_url_param
and smp_fetch_url_param_val that makes the parameter key comparison
case-insensitive.
Now users can retrieve URL parameters regardless of their case,
allowing to match parameters in case insensitive application.
Doc was updated.
2023-03-30 14:11:25 +02:00
Martin DOLEZ
110e4a8733 MINOR: http_fetch: add case insensitive support for smp_fetch_url_param
This commit adds a new argument to smp_fetch_url_param
that makes the parameter key comparison case-insensitive.
Several levels of callers were modified to pass this info.
2023-03-30 14:11:10 +02:00
Martin DOLEZ
1a9a994c11 MINOR: http_fetch: Add support for empty delim in url_param
In prevision of adding a third parameter to the url_param
sample-fetch function we need to make the second parameter optional.
User can now pass a empty 2nd argument to keep the default delimiter.
2023-03-30 14:10:59 +02:00