-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Connection reset while connecting https://storage.googleapis.com
with rustls
#1809
Comments
Oh, I got it. |
The HTTP/2 spec (RFC 9113) doesn't make the |
Thanks for the quick response!
What's the expect behavior if client specify the same let url = "https://storage.googleapis.com/";
let content = client
.get(url)
.body("")
.header("host", "storage.googleapis.com")
.send()
.await
.expect("Failed to send request"); |
It shouldn't be an error, at least the spec doesn't say it should. |
Agreed. So we need to investigate further why |
Well, between the two, only rustls supports ALPN, which means it will use HTTP/2 automatically (if the server supports it). The native-tls backend doesn't have ALPN support, the request is using HTTP/1 (unless you use |
No, it shouble be a error
|
Is it a good idea to remove let (head, body) = req.into_parts();
let mut req = ::http::Request::from_parts(head, ());
super::strip_connection_headers(req.headers_mut(), true);
if let Some(len) = body.size_hint().exact() {
if len != 0 || headers::method_has_defined_payload_semantics(req.method()) {
headers::set_content_length_if_missing(req.headers_mut(), len);
}
} Seems * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN: server accepted h2
* Server certificate:
* subject: CN=storage.googleapis.com
* start date: Apr 3 08:27:38 2023 GMT
* expire date: Jun 26 08:27:37 2023 GMT
* subjectAltName: host "storage.googleapis.com" matched cert's "storage.googleapis.com"
* issuer: C=US; O=Google Trust Services LLC; CN=GTS CA 1C3
* SSL certificate verify ok.
* using HTTP/2
* h2h3 [:method: GET]
* h2h3 [:path: /]
* h2h3 [:scheme: https]
* h2h3 [:authority: storage.googleapis.com]
* h2h3 [user-agent: curl/8.0.1]
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x55adae534ea0)
> GET / HTTP/2
> Host: storage.googleapis.com
> user-agent: curl/8.0.1
> accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
< HTTP/2 400
< x-guploader-uploadid: ADPycduo3u9MXg5lYHW7eUp6VLsPw1Fb0pLKmlnIJL61MMtngobtRf2xFfOYRfrDsUiJU_rQhIuRCvIdglI7QGU1yhxQ1w
< content-type: application/xml; charset=UTF-8
< content-length: 181
< date: Wed, 26 Apr 2023 15:14:24 GMT
< expires: Wed, 26 Apr 2023 15:14:24 GMT
< cache-control: private, max-age=0
< server: UploadServer
< alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
<
* Connection #0 to host 192.168.1.104 left intact
<?xml version='1.0' encoding='UTF-8'?><Error><Code>MissingSecurityHeader</Code><Message>Your request was missing a required header.</Message><Details>Authorization</Details></Error>% Curl trace: 146 │ == Info: using HTTP/2
147 │ == Info: h2h3 [:method: GET]
148 │ == Info: h2h3 [:path: /]
149 │ == Info: h2h3 [:scheme: https]
150 │ == Info: h2h3 [:authority: storage.googleapis.com]
151 │ == Info: h2h3 [user-agent: curl/8.0.1]
152 │ == Info: h2h3 [accept: */*]
153 │ == Info: Using Stream ID: 1 (easy handle 0x560ca1aebea0)
154 │ => Send SSL data, 5 bytes (0x5)
155 │ 0000: ....=
156 │ => Send SSL data, 1 bytes (0x1)
157 │ 0000: .
158 │ => Send header, 83 bytes (0x53)
159 │ 0000: GET / HTTP/2
160 │ 000e: Host: storage.googleapis.com
161 │ 002c: user-agent: curl/8.0.1
162 │ 0044: accept: */*
163 │ 0051:
164 │ <= Recv SSL data, 5 bytes (0x5) |
That's saying that the server (recipient) must not use
I don't believe so. The spec points out that intermediaries may need to forward the header on.
Does curl actually snip it out if you specify an additional one? Such as If you don't explicitly set the header field with reqwest, it will only automatically include one in HTTP/1. It won't set one in an HTTP/2 request. |
The curl trace shows that the > curl --trace-ascii curl.trace -H "host: storage.googleapis.com" "https://storage.googleapis.com"
<?xml version='1.0' encoding='UTF-8'?><Error><Code>MissingSecurityHeader</Code><Message>Your request was missing a required header.</Message><Details>Authorization</Details></Error> The 142 │ => Send SSL data, 5 bytes (0x5)
143 │ 0000: ....Q
144 │ => Send SSL data, 1 bytes (0x1)
145 │ 0000: .
146 │ == Info: using HTTP/2
147 │ == Info: h2h3 [:method: GET]
148 │ == Info: h2h3 [:path: /]
149 │ == Info: h2h3 [:scheme: https]
150 │ == Info: h2h3 [:authority: storage.googleapis.com]
151 │ == Info: h2h3 [user-agent: curl/8.0.1]
152 │ == Info: h2h3 [accept: */*]
153 │ == Info: Using Stream ID: 1 (easy handle 0x560ca1aebea0)
154 │ => Send SSL data, 5 bytes (0x5)
155 │ 0000: ....=
156 │ => Send SSL data, 1 bytes (0x1)
157 │ 0000: .
158 │ => Send header, 83 bytes (0x53)
159 │ 0000: GET / HTTP/2
160 │ 000e: Host: storage.googleapis.com
161 │ 002c: user-agent: curl/8.0.1
162 │ 0044: accept: */*
163 │ 0051:
164 │ <= Recv SSL data, 5 bytes (0x5) |
From RFC 9113:
I don't think hyper should forcibly strip that header, if the user purposefully put it there, since the spec indicates some intermediaries may need to pass it along. |
I am not suggesting that How can we ensure that the request is sent successfully? Or do you think that the issue lies with the server and |
It might be a server issue? Then again, I suppose any server is allowed to reject any request for whatever reason they want. Do you need to explicitly set the host header? reqwest will make sure it's correctly set automatically depending on version. |
I read about the curl code First, the curl defines some field in the header which should not be in the h2 request, FYI https://github.com/curl/curl/blob/master/lib/http.c#L4758-L4765 Then, the curl removes the field defined above https://github.com/curl/curl/blob/master/lib/http.c#L4833-L4839 FYI https://github.com/curl/curl/blob/master/lib/http.h#L294-L306 |
Agreed. The error message does indicate that the connection is reset by remote.
No, actually I can remove the related host setting logic. It's just confusing that the same request doesn't work on HTTP/2. I'm okay with it if it's the expected behavior. |
Oh, they're sending a I assumed it was the server replying with a 400, which is fine, a server can say anything is bad in that sense. |
Here's something interesting @seanmonstar @Xuanwo I can't reproduce this error on MacOS but I reproduce it on Linux.(I'm not sure if is there any platform-spec behavior in this lib? |
Can you set up |
I know what happens! The package-capture tools change the behavior. Damn.. |
but also in the above section:
Then retaining or tripping the |
I can also see the same behaviour when trying to fetch It looks like nginx has a similar issue when serving HTTP/2, but it returns In applications, this issue can be surprising, because it'll only break once a server accepts HTTP/2. This could lead to a similar situation to the January 2022 Firefox outage triggered1 by Google enabling HTTP/3 serving by default on GCP load balancers. So I can see the argument for the library taking care of this. However, sometimes you need to sign requests including the In any case, the simple answer for applications not signing requests is "don't explicitly set the Footnotes
|
I think at this point the issue can just serve as background for why a server might be unhappy. |
Hi, I came across a strange issue where sending a request via
rustls
with thehost
header tohttps://storage.googleapis.com
results in the connection being reset.Related to apache/opendal#2125 (comment)
Reproduce
Cargo.toml
main.rs
With rustls:
With native-tls:
If we remove the
host
header, it works too:Question
How do
rustls
andnative-tls
interact with thehost
header? Is this behavior expected?The text was updated successfully, but these errors were encountered: