Description
I did this
Currently, I am developing an application that communicates with the server over HTTP/2 using curl + nghttp2 (1.44.0).
So far, I've been using curl library version 7.69.1, and it worked fine.
However, when testing with the latest curl version, a problem occurred, and the test results for each version are as follows.
- v7.69.1 - works
- v7.70.0 - works
- v7.71.0 ~ v7.79.0 (or latest master) - not works
I tested each commit between 7.70.0 and 7.71.0 one by one to find the commit that made it stop working, and found that the following commit was causing the problem.
I expected the following
Sequence (normal operation case):
- HTTP/2 POST request start
- callback for
CURLOPT_READFUNCTION
invoked - fill the buffer(the first part of the data to be sent) and return written bytes from callback
- HTTP/2 POST recv header from server
- callback for
CURLOPT_READFUNCTION
invoked - fill the buffer(the second part of the data to be sent) and return written bytes from callback
- callback for
CURLOPT_READFUNCTION
invoked - return
0
from callback (no more data to send) - HTTP/2 POST recv data from server
But, after the c4e6968
commit, the step 5 of the above sequence does not proceed.
Sequence (abnormal operation case):
- HTTP/2 POST request start
- callback for
CURLOPT_READFUNCTION
invoked - fill the buffer(the first part of the data to be sent) and return written bytes from callback
- HTTP/2 POST recv header from server
- ...waiting...
- HTTP/2 POST recv data from server (error response)
- callback for
CURLOPT_READFUNCTION
invoked - fill the buffer(the second part of the data to be sent) and return written bytes from callback
I analyzed the curl log for debugging, and the difference between the normal operation case and the abnormal operation case is as follows.
File: lib/http2.c
static ssize_t http2_recv(struct connectdata *conn, int sockindex,
char *mem, size_t len, CURLcode *err)
{
...
if(stream->bodystarted &&
stream->nread_header_recvbuf < Curl_dyn_len(&stream->header_recvbuf)) {
...abnormal case return... (build with c4e6968 commit)
}
...normal case... (build with 842f73d commit)
}
Logs for normal case(build with 842f73d
commit):
data_source_read_callback: returns 5136 bytes stream 7
http2_send returns 5136 for stream 7
Store 151 bytes headers from stream 7 at 0x1072470
http2_recv: easy 0x1071470 (stream 7) win 33533076/33554432
http2_recv: DRAIN 151 bytes stream 7!! (0x1072470 => 0x1072470)
http2_recv: returns 151 for stream 7
Logs for abnormal case(build with c4e6968
commit):
data_source_read_callback: returns 5138 bytes stream 9
http2_send returns 5138 for stream 9
Store 0 bytes headers from stream 9 at (nil)
Curl_readwrite: forcibly told to drain data (1)
http2_recv: Got 151 bytes from header_recvbuf
Curl_readwrite: forcibly told to drain data (1)
Curl_readwrite: forcibly told to drain data (1)
...
IMHO, it seems that the drained_transfer()
function is not called in the above abnormal case log(the state.drain
value is still remains). So in the Curl_readwrite()
function, the select_res
value is still set to CURL_CSELECT_IN
, and the readwrite_upload()
function is not called.
curl/libcurl version
curl 7.71.0-DEV
operating system
Linux (armhf)