Skip to content

HTTP/2 post issue on latest curl version #7630

Closed
sthagen/curl-curl
#209
@webispy

Description

@webispy

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):

  1. HTTP/2 POST request start
  2. callback for CURLOPT_READFUNCTION invoked
  3. fill the buffer(the first part of the data to be sent) and return written bytes from callback
  4. HTTP/2 POST recv header from server
  5. callback for CURLOPT_READFUNCTION invoked
  6. fill the buffer(the second part of the data to be sent) and return written bytes from callback
  7. callback for CURLOPT_READFUNCTION invoked
  8. return 0 from callback (no more data to send)
  9. 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):

  1. HTTP/2 POST request start
  2. callback for CURLOPT_READFUNCTION invoked
  3. fill the buffer(the first part of the data to be sent) and return written bytes from callback
  4. HTTP/2 POST recv header from server
  5. ...waiting...
  6. HTTP/2 POST recv data from server (error response)
  7. callback for CURLOPT_READFUNCTION invoked
  8. 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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions