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

curl: (55) Failed sending HTTP request when trying to send a request with large header size. >8.1.2 #11405

Closed
dimaboyko opened this issue Jul 6, 2023 · 9 comments
Assignees

Comments

@dimaboyko
Copy link

Hi, I am not certain this is a bug, perhaps this was mentioned somewhere, however, I did not discover it, looking at the changelog.
After updating curl from 8.0.1 I have started seeing requests failing to be sent. Further investigation showed, that this is only happening for requests with large header size (10K characters)

I did this

Send a request with large header size. Example:
curl -X GET -L -H "MyHeader: $(printf '%*s' 10000 | tr ' ' 'A')" https://postman-echo.com/get
This is working ok on 8.0.1, but not on 8.1.2.
8.1.2 is returning curl: (55) Failed sending HTTP request

I expected the following

Response from the server.

curl/libcurl version

Error happening with:

curl 8.1.2 (aarch64-alpine-linux-musl) libcurl/8.1.2 OpenSSL/1.1.1u zlib/1.2.12 brotli/1.0.9 nghttp2/1.47.0
Release-Date: 2023-05-30
Protocols: dict file ftp ftps gopher gophers http https imap imaps mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS brotli HSTS HTTP2 HTTPS-proxy IPv6 Largefile libz NTLM NTLM_WB SSL threadsafe TLS-SRP UnixSockets

Request is sent successfully with:

curl 8.0.1 (aarch64-alpine-linux-musl) libcurl/8.0.1 OpenSSL/1.1.1u zlib/1.2.12 brotli/1.0.9 nghttp2/1.43.0
Release-Date: 2023-03-20
Protocols: dict file ftp ftps gopher gophers http https imap imaps mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS brotli HSTS HTTP2 HTTPS-proxy IPv6 Largefile libz NTLM NTLM_WB SSL threadsafe TLS-SRP UnixSockets

operating system

Alpine Linux 3.16 Docker image.
Linux 5.15.49-linuxkit

Screenshot

image
@dfandrich
Copy link
Contributor

dfandrich commented Jul 6, 2023 via email

@icing
Copy link
Contributor

icing commented Jul 6, 2023

That seems likely. I assume you see different behaviour when adding --http1.1?

@dimaboyko
Copy link
Author

@icing yes, adding that is fixing the issue.
As visible on the screenshot, nghttp2 is different in those versions. So it's only happening with HTTP2.

@icing
Copy link
Contributor

icing commented Jul 6, 2023

We introduced a limit when we refactored the http2 code. Most servers I know have a limit on header length to protect themselves from malicious input.

Is this an experiment you are running or do you have a use case for such headers? If yes, what is the limit you are looking for?

@dimaboyko
Copy link
Author

I have discovered this, as libcurl is a downstream dependency of a library that I use in (ethon)
It is a real life usecase, had to adjust what is being sent with the header. The limit I keep in mind always is one from aws alb - https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-limits.html
That would be a little over 15k characters.
I understand this might be quite the edge case, just wanted to bring this to attention, also in case somebody starts getting the error after updating from 8.0.1.

@dfandrich
Copy link
Contributor

dfandrich commented Jul 6, 2023 via email

@ghost
Copy link

ghost commented Jul 7, 2023

If it helps, below is result with Go net/http. I would say that the given server is a poor example, as it doesnt even handle the request as given:

https://developer.mozilla.org/docs/Web/HTTP/Status/431

package main

import (
   "net/http"
   "strings"
   "time"
)

func main() {
   req, err := http.NewRequest("", "https://postman-echo.com/get", nil)
   if err != nil {
      panic(err)
   }
   i := 7989
   for {
      req.Header.Set("MyHeader", strings.Repeat("A", i))
      res, err := new(http.Transport).RoundTrip(req)
      if err != nil {
         panic(err)
      }
      res.Body.Close()
      println(res.Status, i)
      time.Sleep(time.Second)
      i++
   }
}

result:

200 OK 7989
502 Bad Gateway 7990
502 Bad Gateway 7991
502 Bad Gateway 7992
502 Bad Gateway 7993
502 Bad Gateway 7994
502 Bad Gateway 7995
502 Bad Gateway 7996
502 Bad Gateway 7997
502 Bad Gateway 7998
502 Bad Gateway 7999
502 Bad Gateway 8000
502 Bad Gateway 8001
502 Bad Gateway 8002
502 Bad Gateway 8003
502 Bad Gateway 8004
502 Bad Gateway 8005
502 Bad Gateway 8006
502 Bad Gateway 8007
502 Bad Gateway 8008
502 Bad Gateway 8009
502 Bad Gateway 8010
502 Bad Gateway 8011
502 Bad Gateway 8012
431 Request Header Fields Too Large 8013

@icing icing self-assigned this Jul 7, 2023
icing added a commit to icing/curl that referenced this issue Jul 7, 2023
- not quite to infinity
- refs curl#11405
- rewrote the implementation of our internal HTTP/1.x request
  parsing to work with very large lines using dynbufs.
- new default limit is `DYN_HTTP_REQUEST`, aka 1MB, which
  is also the limit of curl's general HTTP request processing.
@icing
Copy link
Contributor

icing commented Jul 7, 2023

Thanks. I made #11407 just now which overcomes these limitations.

Curl internally has a general buffer limited to 1MB for assembling a HTTP request. This limit is now also in effect for HTTP/2 and HTTP/3 request processing with this PR.

@bagder bagder closed this as completed in 4e88024 Jul 8, 2023
@dimaboyko
Copy link
Author

Thank you!

bch pushed a commit to bch/curl that referenced this issue Jul 19, 2023
- not quite to infinity
- rewrote the implementation of our internal HTTP/1.x request
  parsing to work with very large lines using dynbufs.
- new default limit is `DYN_HTTP_REQUEST`, aka 1MB, which
  is also the limit of curl's general HTTP request processing.

Fixes curl#11405
Closes curl#11407
ptitSeb pushed a commit to wasix-org/curl that referenced this issue Sep 25, 2023
- not quite to infinity
- rewrote the implementation of our internal HTTP/1.x request
  parsing to work with very large lines using dynbufs.
- new default limit is `DYN_HTTP_REQUEST`, aka 1MB, which
  is also the limit of curl's general HTTP request processing.

Fixes curl#11405
Closes curl#11407
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants