Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTTP/2 upload too large request does not immediately end #15316

Closed
jkamp-aws opened this issue Oct 17, 2024 · 5 comments
Closed

HTTP/2 upload too large request does not immediately end #15316

jkamp-aws opened this issue Oct 17, 2024 · 5 comments
Assignees
Labels

Comments

@jkamp-aws
Copy link

I did this

Create a request where the server is going to reply HTTP/2 413. Using curl cli to make the request:

curl --http2 -X POST -d @./too-large-request -s -i $URL

I expected the following

curl to end quickly without an error code, but instead curl waits for the server as if it wants to upload the full data or another request. The server closes the connection (for me 5 minutes) and then curl ends with error 18.

< HTTP/2 413 
< date: Thu, 17 Oct 2024 07:19:20 GMT
< content-type: text/xml
< content-length: 635
< server: Server
* HTTP error before end of send, stop sending
* abort upload after having sent 212992 bytes
< 
* received GOAWAY, error=0, last_stream=1
* TLSv1.3 (IN), TLS alert, close notify (256):
* closing connection #0
curl: (18) Transferred a partial file

Same output but from curl 7.81.0 (reported 8.6.1 should have been good too)

< HTTP/2 413 
< date: Thu, 17 Oct 2024 08:12:15 GMT
< content-type: text/xml
< content-length: 635
< server: Server
* HTTP error before end of send, stop sending
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
< 
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Connection #0 to host hostname left intact

curl/libcurl version

curl 8.10.1 (x86_64-pc-linux-gnu) libcurl/8.10.1 OpenSSL/3.0.2 zlib/1.2.11 zstd/1.4.8 libpsl/0.21.0 nghttp2/1.43.0 OpenLDAP/2.5.18
Release-Date: 2024-09-18
Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns ldap ldaps mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS HSTS HTTP2 HTTPS-proxy IPv6 Largefile libz NTLM PSL SSL threadsafe TLS-SRP UnixSockets zstd

operating system

Linux ip-192-168-10-106 6.8.0-1015-aws #16~22.04.1-Ubuntu SMP Mon Aug 19 19:38:17 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux

@bagder bagder added the HTTP/2 label Oct 17, 2024
@icing
Copy link
Contributor

icing commented Oct 17, 2024

Thanks for the report. Could you generate a trace adding -v --trace-config http/2,read,write to your command line?

@icing icing self-assigned this Oct 17, 2024
@jkamp-aws
Copy link
Author

upload-endless-wait.log
now with read/write.

@icing
Copy link
Contributor

icing commented Oct 17, 2024

Thanks. The uncommon thing here is that the server does not RST the stream, as it clearly has no intention of reading any more data from curl. You seem to hide its identity, but maybe you can reveal what http/2 server that is? May help us in future trouble shooting.

That curl does not abort the transfer upon getting the 413 is a bug. I will work on a fix.

icing added a commit to icing/curl that referenced this issue Oct 17, 2024
When a server signals EOS from its side and the curl
upload is unfinished and the server has not given a
positive HTTP status response, auto RST the stream to
signal that the upload is incomplete and that the whole
transfer can be stopped.

refs curl#15316, where the server responds with 413 on an
upload but does not RST the stream from its side, as
httpd and others do.
@icing
Copy link
Contributor

icing commented Oct 17, 2024

Could you try #15325 in your setup to see if this works there too? I can only simulate the situations partially with our test servers as they reset streams in such situations.

@jkamp-aws
Copy link
Author

There seems to be some routing component I don't have control over. When querying an nginx or apache directly it behaves differently.

With the patch curl exits quickly and with the normal 0 exit code. End logging now looks like this:

< HTTP/2 413 
* [WRITE] cw_out, wrote 13 header bytes -> 13
* [WRITE] download_write header(type=c, blen=13) -> 0
* [WRITE] client_write(type=c, len=13) -> 0
* [HTTP/2] [1] local window update by 10420224
* [HTTP/2] [1] status: HTTP/2 413
< date: Thu, 17 Oct 2024 17:03:25 GMT
* [WRITE] header_collect pushed(type=1, len=37) -> 0
* [WRITE] cw_out, wrote 37 header bytes -> 37
* [WRITE] download_write header(type=4, blen=37) -> 0
* [WRITE] client_write(type=4, len=37) -> 0
* [HTTP/2] [1] header: date: Thu, 17 Oct 2024 17:03:25 GMT
< content-type: text/xml
* [WRITE] header_collect pushed(type=1, len=24) -> 0
* [WRITE] cw_out, wrote 24 header bytes -> 24
* [WRITE] download_write header(type=4, blen=24) -> 0
* [WRITE] client_write(type=4, len=24) -> 0
* [HTTP/2] [1] header: content-type: text/xml
< content-length: 635
* [WRITE] header_collect pushed(type=1, len=21) -> 0
* [WRITE] cw_out, wrote 21 header bytes -> 21
* [WRITE] download_write header(type=4, blen=21) -> 0
* [WRITE] client_write(type=4, len=21) -> 0
* [HTTP/2] [1] header: content-length: 635
< server: Server
* [WRITE] header_collect pushed(type=1, len=16) -> 0
* [WRITE] cw_out, wrote 16 header bytes -> 16
* [WRITE] download_write header(type=4, blen=16) -> 0
* [WRITE] client_write(type=4, len=16) -> 0
* [HTTP/2] [1] header: server: Server
* [HTTP/2] [1] <- FRAME[HEADERS, len=55, hend=1, eos=0]
* HTTP error before end of send, stop sending
* abort upload after having sent 278368 bytes
< 
* [WRITE] header_collect pushed(type=1, len=2) -> 0
* [WRITE] cw_out, wrote 2 header bytes -> 2
* [WRITE] download_write header(type=4, blen=2) -> 0
* [WRITE] client_write(type=4, len=2) -> 0
* [WRITE] cw_out, wrote 635 body bytes -> 635
* [WRITE] download_write body(type=1, blen=635) -> 0
* [WRITE] client_write(type=1, len=635) -> 0
* [WRITE] xfer_write_resp(len=635, eos=0) -> 0
* [HTTP/2] [1] <- FRAME[DATA, len=635, eos=0, padlen=0]
* [HTTP/2] [1] DATA, window=635/10485760
* [HTTP/2] [0] progress ingress: inbufg=0
* [HTTP/2] [0] ingress: read 9 bytes
* [HTTP/2] [1] <- FRAME[DATA, len=0, eos=1, padlen=0]
* [HTTP/2] [1] DATA, window=635/10485760
* [HTTP/2] [1] EOS frame with unfinished upload and HTTP status 413, abort upload by RST
* [HTTP/2] [1] DRAIN select_bits=1
* [HTTP/2] [0] progress ingress: inbufg=0
* [HTTP/2] [0] progress ingress: done
* [HTTP/2] [1] returning CLOSE
* [HTTP/2] handle_stream_close -> 0, 0
* [HTTP/2] [1] -> FRAME[RST_STREAM, len=4, flags=0, error=5]
* [HTTP/2] [1] RESET: STREAM_CLOSED (err 5)
* [HTTP/2] [1] DRAIN select_bits=1
* [HTTP/2] [0] egress: wrote 13 bytes
* [HTTP/2] [1] cf_recv(len=102400) -> 0 0, window=-1/-1, connection 1048575365/1048576000
* [WRITE] download_write body(type=81, blen=0) -> 0
* [WRITE] client_write(type=81, len=0) -> 0
* [WRITE] xfer_write_resp(len=0, eos=1) -> 0
* [WRITE] cw-out is notpaused
* [WRITE] cw-out done
* [READ] client_reset, clear readers

@bagder bagder closed this as completed in fe2a720 Oct 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

3 participants