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

fetch can't connect to HTTP/2-only servers #12517

Closed
andreubotella opened this issue Oct 22, 2021 · 4 comments · Fixed by #12530
Closed

fetch can't connect to HTTP/2-only servers #12517

andreubotella opened this issue Oct 22, 2021 · 4 comments · Fixed by #12530

Comments

@andreubotella
Copy link
Contributor

andreubotella commented Oct 22, 2021

This came up when working on #12472, since WPT's HTTP/2 server on port 9000 is HTTP/2-only. It also seems to be the cause of #12208.

Here's a test case – run it on a checkout of the Deno repo.

import { runWithTestUtil } from "./tools/wpt/runner.ts";

// `runWithTestUtil` starts the WPT server
await runWithTestUtil(false, async () => {
  const client = Deno.createHttpClient({
    caCerts: [
      await Deno.readTextFile("./tools/wpt/certs/cacert.pem"),
    ]
  });
  const res = await fetch("https://web-platform.test:9000", { client });
  console.log(await res.text());
});
error: Uncaught (in promise) TypeError: error sending request for url (https://web-platform.test:9000/): invalid HTTP version parsed
    at async mainFetch (deno:ext/fetch/26_fetch.js:280:14)

reqwest with rustls does support connecting to HTTP/2-only servers, as shown by the following Rust sample:

#[tokio::main]
async fn main() -> Result<()> {
  let cert = fs::read("tools/wpt/certs/cacert.pem")?;
  let client = ClientBuilder::new()
    .add_root_certificate(Certificate::from_pem(&cert)?)
    .build()?;
  let response = client.get("https://web-platform.test:9000").send().await?;

  println!("HTTP version: {:?}", response.version());
  println!("{}", response.text().await?);
  Ok(())
}

The configuration of reqwest that Deno uses for fetching is more complicated than this, however, and I'm not sure if this is a bug with Deno's configuration, or a bug with reqwest.

@lucacasonato
Copy link
Member

@andreubotella What happens if you set http2_prior_knowledge on the client builder?

@andreubotella
Copy link
Contributor Author

@andreubotella What happens if you set http2_prior_knowledge on the client builder?

The fetch does succeed if you do that. But of course, that's not something that can be enabled by default (although maybe it could be an option in Deno.createHttpClient(), alongside http1_only).

@lucacasonato
Copy link
Member

The fetch does succeed if you do that. But of course, that's not something that can be enabled by default (although maybe it could be an option in Deno.createHttpClient(), alongside http1_only).

Sure. That suggests the issue stems from ALPN.

@andreubotella
Copy link
Contributor Author

This also affects servers which support both HTTP/1.1 and HTTP/2, since fetch() will connect only to HTTP/1.1 even if h2 is earlier in the server's ALPN list.

It seems like this regressed in #11491.

andreubotella pushed a commit to andreubotella/deno that referenced this issue Oct 25, 2021
`fetch()` and client-side websocket used to support HTTP/2, but this
regressed in denoland#11491. This patch reenables it by explicitly adding `h2`
and `http/1.1` to the list of ALPN protocols on the HTTP and websocket
clients.

Fixes denoland#12517.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants