I did this
The issue is observed after upgrading curl from 8.5.0 to 8.6.0.
Specifically, the behavior change is seen from d7b6ce6.
When issuing queries, we might not get the state change from PERFORMING to DONE.
The currently seen behavior on failure is*:
- HTTPS/2 request is sent through
curl_multi_add_handle(...).
- The request is completed and
drain_steam(...) (https://github.com/curl/curl/blob/master/lib/http2.c#L212) is called.
data->state.select_bits is set to CURL_CSELECT_IN.
Curl_expire(data, 0, EXPIRE_RUN_NOW); is called.
- Client's
epoll returns the socket to be writable but not readable.
curl_multi_socket_action(..., CURL_CSELECT_OUT, ...) is called by the client.
data->state.select_bits is set to CURL_CSELECT_OUT (overriding libcurl operation on step 2).
CURLMOPT_TIMERFUNCTION is called as a result of step 2.
readwrite_data(...) is not called because data->state.select_bits == CURL_CSELECT_OUT and k->keepon == KEEP_RECV.
The currently seen behavior on success is*:
- HTTPS/2 request is sent through
curl_multi_add_handle(...).
- The request is completed and
drain_steam(...) (https://github.com/curl/curl/blob/master/lib/http2.c#L212) is called.
data->state.select_bits is set to CURL_CSELECT_IN.
Curl_expire(data, 0, EXPIRE_RUN_NOW); is called.
CURLMOPT_TIMERFUNCTION is called as a result of step 2.
readwrite_data(...) is called because data->state.select_bits == CURL_CSELECT_IN and k->keepon == KEEP_RECV.
- Curl gets
EndOfSteam (EOS) / nread == 0 from readwrite_data(...).
- Curl updated the state from PERFORMING to DONE.
*The difference is whether curl_multi_socket_action(..., CURL_CSELECT_OUT, ...) or CURLMOPT_TIMERFUNCTION is called first.
The previous behavior is (< 8.6.0):
- HTTPS/2 request is sent through
curl_multi_add_handle(...).
- The request is completed and
drain_steam(...) (https://github.com/curl/curl/blob/master/lib/http2.c#L212) is called.
data->state.select_bits is set to CURL_CSELECT_IN.
Curl_expire(data, 0, EXPIRE_RUN_NOW); is called.
- Curl updated the state from PERFORMING to DONE within the same
multi_socket(...) calls as step 2.
- As such, it is not possible for the client to call
curl_multi_socket_action(..., CURL_CSELECT_OUT, ...).
From my understanding, the behavior change is the result of 2944e46.
I expected the following
Curl to always finish the request even if curl_multi_socket_action(..., CURL_CSELECT_OUT, ...) is called.
curl/libcurl version
WARNING: this libcurl is Debug-enabled, do not use in production
curl 8.6.0-DEV (x86_64-cros-linux-gnu) libcurl/8.6.0-DEV OpenSSL/3.2.0 zlib/1.2.13 c-ares/1.19.1 libpsl/0.21.1 nghttp2/1.57.0
Release-Date: [unreleased]
Protocols: dict file http https ipfs ipns mqtt
Features: alt-svc AsynchDNS Debug GSS-API HSTS HTTP2 HTTPS-proxy IPv6 Kerberos Largefile libz NTLM PSL SPNEGO SSL threadsafe TLS-SRP TrackMemory UnixSockets
operating system
ChromeOS
$ uname -a
Linux localhost 5.15.147-21486-g7e7afc4ef5b4 #1 SMP PREEMPT Tue, 16 Jan 2024 22:08:30 +0000 x86_64 Intel(R) Core(TM) i3-10110U CPU @ 2.10GHz GenuineIntel GNU/Linux
I did this
The issue is observed after upgrading curl from 8.5.0 to 8.6.0.
Specifically, the behavior change is seen from d7b6ce6.
When issuing queries, we might not get the state change from PERFORMING to DONE.
The currently seen behavior on failure is*:
curl_multi_add_handle(...).drain_steam(...)(https://github.com/curl/curl/blob/master/lib/http2.c#L212) is called.data->state.select_bitsis set toCURL_CSELECT_IN.Curl_expire(data, 0, EXPIRE_RUN_NOW);is called.epollreturns the socket to be writable but not readable.curl_multi_socket_action(..., CURL_CSELECT_OUT, ...)is called by the client.data->state.select_bitsis set toCURL_CSELECT_OUT(overriding libcurl operation on step 2).CURLMOPT_TIMERFUNCTIONis called as a result of step 2.readwrite_data(...)is not called becausedata->state.select_bits == CURL_CSELECT_OUTandk->keepon == KEEP_RECV.The currently seen behavior on success is*:
curl_multi_add_handle(...).drain_steam(...)(https://github.com/curl/curl/blob/master/lib/http2.c#L212) is called.data->state.select_bitsis set toCURL_CSELECT_IN.Curl_expire(data, 0, EXPIRE_RUN_NOW);is called.CURLMOPT_TIMERFUNCTIONis called as a result of step 2.readwrite_data(...)is called becausedata->state.select_bits == CURL_CSELECT_INandk->keepon == KEEP_RECV.EndOfSteam(EOS) /nread == 0fromreadwrite_data(...).*The difference is whether
curl_multi_socket_action(..., CURL_CSELECT_OUT, ...)orCURLMOPT_TIMERFUNCTIONis called first.The previous behavior is (< 8.6.0):
curl_multi_add_handle(...).drain_steam(...)(https://github.com/curl/curl/blob/master/lib/http2.c#L212) is called.data->state.select_bitsis set toCURL_CSELECT_IN.Curl_expire(data, 0, EXPIRE_RUN_NOW);is called.multi_socket(...)calls as step 2.curl_multi_socket_action(..., CURL_CSELECT_OUT, ...).From my understanding, the behavior change is the result of 2944e46.
I expected the following
Curl to always finish the request even if
curl_multi_socket_action(..., CURL_CSELECT_OUT, ...)is called.curl/libcurl version
WARNING: this libcurl is Debug-enabled, do not use in production
curl 8.6.0-DEV (x86_64-cros-linux-gnu) libcurl/8.6.0-DEV OpenSSL/3.2.0 zlib/1.2.13 c-ares/1.19.1 libpsl/0.21.1 nghttp2/1.57.0
Release-Date: [unreleased]
Protocols: dict file http https ipfs ipns mqtt
Features: alt-svc AsynchDNS Debug GSS-API HSTS HTTP2 HTTPS-proxy IPv6 Kerberos Largefile libz NTLM PSL SPNEGO SSL threadsafe TLS-SRP TrackMemory UnixSockets
operating system
ChromeOS
$ uname -a
Linux localhost 5.15.147-21486-g7e7afc4ef5b4 #1 SMP PREEMPT Tue, 16 Jan 2024 22:08:30 +0000 x86_64 Intel(R) Core(TM) i3-10110U CPU @ 2.10GHz GenuineIntel GNU/Linux