Fix edge cases around handling of pending send frames and encoding
frames with size_t/curl_off_t possible flowy things.
Reported-by: Joshua Rogers
Closes#18965
After this patch, the codebase no longer overrides system printf
functions. Instead it explicitly calls either the curl printf functions
`curl_m*printf()` or the system ones using their original names.
Also:
- drop unused `curl_printf.h` includes.
- checksrc: ban system printf functions, allow where necessary.
Follow-up to db98daab05#18844
Follow-up to 4deea9396b#18814Closes#18866
- GHA/checkdocs: rename `spellcheck` job to `pyspelling` to say
the exact tool used.
- GHA/checkdocs: restore a comment.
- GHA/linux: add `-B .` to a cmake configure to avoid warning, and
future breakage.
- autotools: use correct casing for `Schannel`.
- doh: update RFC URL.
- drop redundant parenthesis.
- fix indentation, whitespace.
Closes#18756
Improvements around HTTP Upgrade: and multiplex hanndling:
* add `Curl_conn_set_multiplex()` to set connection's multiplex
bit and trigger "connchanged" events
* call `Curl_conn_set_multiplex()` in filters' `CF_CTRL_CONN_INFO_UPDATE`
implementation where other connection properties are updated.
This prevents connection updates before the final filter chain
is chosen.
* rename enum `UPGR101_INIT` to `UPGR101_NONE`
* rename connection bit `asks_multiplex` to `upgrade_in_progress`
* trigger "connchanged" when `upgrade_in_progress` clears
* rename `WebSockets` to `WebSocket` as it is the common term
used in documentation
Closes#18227
The auto PONG frames were inserted into the connection at the time
a PING had been decoded, irregardless if an upstream frame was just
in the middle of being assembled.
Add PONG frames only to the buffer if there is no frame currently
assemebled and, if it is, set the control frame aside. This control
frame is then added on the first opportunity of a "clean" send buffer.
There is only a single control frame set aside at a time. This means
a double PING will, when the PONG cannot be sent right away, only
send the last PONG.
I imagine this is fine. We want to prevent the endless buffering of
PONG frames on a connection where the server sends but does no receives.
Reported-by: Calvin Ruocco
Fixes#16706Closes#18479
Sending websocket data did not clear the "upload_done" flag of
the initial HTTP Upgrade request, leading to KEEP_SEND never be
cleared. This caused the socket to be polled for INOUT after all
the websocket data had been sent. A busy loop.
Closes#18476
Split out adding of individual request headers into a switch. Check
the connection http version only on fresh connections, use separate
methods.
Add TE: header directly without allocation. Add bit for indicating
Connection: header has been added and custom headers should not do
that again.
Closes#18444
Write out 9-length frames to client's WRITEFUNCTION
Read 0-length frames from READFUNCTION *if* the function
started a new frame via `curl_ws_start_frame()`.
Fixes#18286Closes#18332
Reported-by: Andriy Druk
Add support for CURLOPT_READFUNCTION with WebSocket urls when *not* in
connect-only mode, e.g. when using curl_multi_perform.
Install the callback function and set CURLOPT_UPLOAD. Return
CURL_READFUNC_PAUSE when having nothing more to send and unpause the
transfer when more data is ready.
This will send the read bytes in a WebSocket BINARY frame.
Add support for this mode in the pytest "ws_data" client and have all
tests run in 'curl_ws_send/recv' and 'peform' mode as well.
Add `curl_ws_start_frame()`. Document, cover in libcurl-ws.md and
explain the READFUNCTION mode for websockets.
Add example `websocket-updown` for this.
Closes#17683
`getsock()` calls operated on a global limit that could
not be configure beyond 16 sockets. This is no longer adequate
with the new happy eyeballing strategy.
Instead, do the following:
- make `struct easy_pollset` dynamic. Starting with
a minimal room for two sockets, the very common case,
allow it to grow on demand.
- replace all protocol handler getsock() calls with pollsets
and a CURLcode to return failures
- add CURLcode return for all connection filter `adjust_pollset()`
callbacks, since they too can now fail.
- use appropriately in multi.c and multi_ev.c
- fix unit2600 to trigger pollset growth
Closes#18164
Change the signature of `bufq` functions from
* `ssize_t Curl_bufq_*(..., CURLcode *err)` to
* `CURLcode Curl_bufq_*(..., size_t *pn)`
This allows us to write slightly less code and avoids the ssize_t/size_t
conversions in many cases. Also, it gets the function in line with all
the other send/recv signatures.
Added helper functions in `cfilters.h` for sending from/receving into
a bufq.
Fuzzer now fails to build due to these changes and its testing of
the bufq API.
Closes#17396
This started out as regression tests for the `curl_ws_recv()` and
`curl_ws_send()` implementation and ended up with a bugfix, additional
protocol validation and minor logging improvements.
- Fix reset of fragmented message decoder state when a PING/PONG is
received in between message fragments.
- Fix undefined behavior (applying zero offset to null pointer) in
curl_ws_send() when the given buffer is NULL.
- Detect invalid overlong PING/PONG/CLOSE frames.
- Detect invalid fragmented PING/PONG/CLOSE frames.
- Detect invalid sequences of fragmented frames.
- a) A continuation frame (0x80...) is received without any ongoing
fragmented message.
- b) A new fragmented message is started (0x81/0x01/0x82/0x02...)
before the ongoing fragmented message has terminated.
- Made logs for invalid opcodes easier to understand.
- Moved noisy logs to the `CURL_TRC_WS` log level.
- Unified the prefixes for WebSocket log messages: `[WS] ...`
- Add env var `CURL_WS_FORCE_ZERO_MASK` in debug builds.
- If set, it forces the bit mask applied to outgoing payloads to
0x00000000, which effectively means the payload is not masked at
all. This drastically simplifies defining the expected `<protocol>`
data in test cases.
- 2700: Frame types
- 2701: Invalid opcode 0x3
- 2702: Invalid opcode 0xB
- 2703: Invalid reserved bit RSV1 _(replaces 2310)_
- 2704: Invalid reserved bit RSV2
- 2705: Invalid reserved bit RSV3
- 2706: Invalid masked server message
- 2707: Peculiar frame sizes _(part. replaces 2311)_
- 2708: Automatic PONG
- 2709: No automatic PONG _(replaces 2312)_
- 2710: Unsolicited PONG
- 2711: Empty PING/PONG/CLOSE
- 2712: Max sized PING/PONG/CLOSE
- 2713: Invalid oversized PING _(replaces 2307)_
- 2714: Invalid oversized PONG
- 2715: Invalid oversized CLOSE
- 2716: Invalid fragmented PING
- 2717: Invalid fragmented PONG
- 2718: Invalid fragmented CLOSE
- 2719: Fragmented messages _(part. replaces 2311)_
- 2720: Fragmented messages with empty fragments
- 2721: Fragmented messages with interleaved pong
- 2722: Invalid fragmented message without initial frame
- 2723: Invalid fragmented message without final frame
- 2305: curl_ws_recv() loop reading three larger frames
- This test involuntarily sent an invalid sequence of opcodes (0x01...,0x01...,0x81...) , but neither libcurl nor the test caught this! The correct sequence was tested in 2311 (0x01...,0x00...,0x80...). See below for 2311.
- Validation of the opcode sequence was added to libcurl and is now tested in 2723.
- Superseded by 2719 (fragmented message) and 2707 (large frames).
- 2307: overlong PING payload
- The tested PING payload length check was actually missing, but the test didn't catch this since it involuntarily sent an invalid opcode (0x19... instead of 0x89...) so that the expected error occurred, but for the wrong reason.
- Superseded by 2713.
- 2310: unknown reserved bit set in frame header
- Superseded by 2703 and extended by 2704 and 2705.
- 2311: curl_ws_recv() read fragmented message
- Superseded by 2719 (fragmented message) and 2707 (large frames).
- 2312: WebSockets no auto ping
- Superseded by 2709.
- No tests for `CURLOPT_WRITEFUNCTION`.
- No tests for sending of invalid frames/fragments.
Closes#17136
Move curlx_ functions into its own subdir.
The idea is to use the curlx_ prefix proper on these functions, and use
these same function names both in tool, lib and test suite source code.
Stop the previous special #define setup for curlx_ names.
The printf defines are now done for the library alone. Tests no longer
use the printf defines. The tool code sets its own defines. The printf
functions are not curlx, they are publicly available.
The strcase defines are not curlx_ functions and should not be used by
tool or server code.
dynbuf, warnless, base64, strparse, timeval, timediff are now proper
curlx functions.
When libcurl is built statically, the functions from the library can be
used as-is. The key is then that the functions must work as-is, without
having to be recompiled for use in tool/tests. This avoids symbol
collisions - when libcurl is built statically, we use those functions
directly when building the tool/tests. When libcurl is shared, we
build/link them separately for the tool/tests.
Assisted-by: Jay Satiro
Closes#17253
Eliminates union member on struct connectdata. Sample of how
other procotols can handle their connection related data.
This avoids potention mix-ups of the `proto` union of a
connection with other protocol instances.
Removed ws "disconnect" callback as meta data is automatically
destroyed when a connection is destroyed.
Closes#17146
It passed in the wrong header length to the check function, which made
it do duplicated headers in cases where the user provides its own set.
Reported-by: sbernatsky on github
Fixes#17170Closes#17194Closes#16178
This adds another bitflag on CURLOPT_WS_OPTIONS (CURLWS_NOAUTOPONG) that
disables the default and automatic PONG reply in the WebSocket layer.
Assisted-by: Calvin Ruocco
Closes#16744
The issues found fell into these categories, with the applied fixes:
- const was accidentally stripped.
Adjust code to not cast or cast with const.
- const/volatile missing from arguments, local variables.
Constify arguments or variables, adjust/delete casts. Small code
changes in a few places.
- const must be stripped because an API dependency requires it.
Strip `const` with `CURL_UNCONST()` macro to silence the warning out
of our control. These happen at API boundaries. Sometimes they depend
on dependency version, which this patch handles as necessary. Also
enable const support for the zlib API, using `ZLIB_CONST`. Supported
by zlib 1.2.5.2 and newer.
- const must be stripped because a curl API requires it.
Strip `const` with `CURL_UNCONST()` macro to silence the warning out
of our immediate control. For example we promise to send a non-const
argument to a callback, though the data is const internally.
- other cases where we may avoid const stripping by code changes.
Also silenced with `CURL_UNCONST()`.
- there are 3 places where `CURL_UNCONST()` is cast again to const.
To silence this type of warning:
```
lib/vquic/curl_osslq.c:1015:29: error: to be safe all intermediate
pointers in cast from 'unsigned char **' to 'const unsigned char **'
must be 'const' qualified [-Werror=cast-qual]
lib/cf-socket.c:734:32: error: to be safe all intermediate pointers in
cast from 'char **' to 'const char **' must be 'const' qualified
[-Werror=cast-qual]
```
There may be a better solution, but I couldn't find it.
These cases are handled in separate subcommits, but without further
markup.
If you see a `-Wcast-qual` warning in curl, we appreciate your report
about it.
Closes#16142
Add a 'wanted' major HTTP version bitmask next to the 'allowed' bitmask
in HTTP version negotiation. This will try connections as specified in
'wanted', but enabled Alt-Svc and HTTPS-RR to redirect to other major
HTTP versions, if those are 'allowed'.
Changes libcurl internal default to `CURL_HTTP_VERSION_NONE` and removes
the code in curl that sets `CURL_HTTP_VERSION_2TLS` if the command line
does not say anything else.
Closes#16117
Translate the `data->set.httpwant` which is one of the consts from the
public API (CURL_HTTP_VERSION_*) into a major version mask plus
additional flags for internal handling.
`Curl_http_neg_init()` does the translation and flags setting in http.c,
using new internal consts CURL_HTTP_V1x, CURL_HTTP_V2x and CURL_HTTP_V3x
for the major versions. The flags are
- only_10: when the application explicity asked fro HTTP/1.0
- h2_upgrade: when the application asks for upgrading 1.1 to 2.
- h2_prior_knowledge: when directly talking h2 without ALPN
- accept_09: when a HTTP/0.9 response is acceptable.
The Alt-Svc and HTTPS RR redirections from one ALPN to another obey the
allowed major versions. If a transfer has only h3 enabled, Alt-Svc
redirection to h2 is ignored.
This is the current implementation. It can be debated if Alt-Svc should
be able to override the allowed major versions. Added test_12_06 to
verify the current restriction.
Closes#16100
- add hex and octal parsers to the Curl_str_* family
- make curlx_strtoofft use these parsers
- remove all use of strtol() and strtoul() in library code
- generally use Curl_str_* more than strtoofft, for stricter parsing
- supports 64-bit universally, instead of 'long' which differs in size
between platforms
Extended the unit test 1664 to verify hex and octal parsing.
Closes#16336
RFC 6455 Section 5.2 notes that for bits RSV1, RSV2, and RSV3 of the
framing header, a non-zero value that is not defined by a negotiated
extension MUST Fail the WebSocket connection.
Test 2310 verifies
Closes#16069
Adds a `follow()` callback to protocol handlers, so they may decide how
to act on a `newurl` after a request has been done. This is optional.
This moves the HTTP code for handling redirects from multi.c to http.c
where it should be. If we ever add a protocol with its own logic, it
would install its own follow function.
Closes#16075
- Fix a bug in EAGAIN handling when sending frames that led to a
corrupted last byte of the frame sent.
- Restore sanity to curl_ws_send() behaviour:
- Partial writes are reported as OK with the actual number of
payload bytes sent.
- CURLE_AGAIN is only returned when none of the payload bytes
(or for 0-length frames, not all of the frame header bytes)
could be sent.
- curl_ws_send() now behaves like a common send() call.
- Change 'ws-data' test client to allow concurrent send/recv
operations and vary frame sizes and repeat count.
- Add DEBUG env var CURL_WS_CHUNK_EAGAIN to simulate blocking
after a chunk of an encoded websocket frame has been sent.
- Add tests.
Prior to this change data corruption may occur when sending websocket
messages due to two bugs:
1) 3e64569a (precedes 8.10.0) caused a data corruption bug in the last
byte of frame of large messages.
2) curl_ws_send had non-traditional send behavior and could return
CURLE_AGAIN with bytes sent and expect the caller to adjust buffer
and buflen in a subsequent call. That behavior was not documented.
Reported-by: na-trium-144@users.noreply.github.com
Fixes https://github.com/curl/curl/issues/15865
Fixes https://github.com/curl/curl/issues/15865#issuecomment-2569870144
Closes https://github.com/curl/curl/pull/15901
lib : remove all hyper code
configure: stop detecting hyper
docs: no more mention of hyper
tests: mo more special-handling of hyper builds
CI: no jobs using hyper
Closes#15120
It makes the callbacks get different signnatures when used from within
libcurl vs outside of it by libcurl-using applications (such as the
libtests) and this triggers UndefinedBehaviorSanitizer errors.
Closes#15289
Change mingw-w64 printf format checks in public curl headers to use
`__MINGW_PRINTF_FORMAT` instead of `gnu_printf`. This syncs the format
checker with format string macros published via `curl/system.h`. (Also
disable format checks for mingw-w64 older than 3.0.0 (2013-09-20) and
classic-mingw, which do not support this macro.)
This fixes bogus format checker `-Wformat` warnings in 3rd party code
using curl format strings with the curl printf functions, when using
mingw-w64 7.0.0 (2019-11-10) and older (with GCC, MSVCRT).
It also allows to delete two workaounds for this within curl itself:
- setting `-D__USE_MINGW_ANSI_STDIO=1` for mingw-w64 via cmake and
configure for `docs/examples` and `tests/http/clients`.
Ref: c730c8549b#14640
The format check macro is incompatible (depending on mingw-w64 version
and configuration) with the C99 `%z` (`size_t`) format string used
internally by curl.
To work around this problem, override the format check style in curl
public headers to use `gnu_printf`. This is compatible with `%z` in all
mingw-w64 versions and allows keeping the C99 format strings internally.
Also:
- lib/ws.c: add missing space to an error message.
- docs/examples/ftpgetinfo.c: fix to use standard printf.
Ref: #14643 (take 1)
Follow-up to 3829759bd0#12489Closes#14703