undici icon indicating copy to clipboard operation
undici copied to clipboard

HTTP/2 over unix domain sockets returns `ERR_SSL_WRONG_VERSION_NUMBER`

Open mctrafik opened this issue 1 year ago • 3 comments

Bug Description

I'm trying to send a request to a local server running HTTP/2 without TLS (H2C) over a unix domain socket. This is what my company uses for internal services.

However, when I try to fetch the results, I git an SSL error:

{"library":"SSL routines","reason":"wrong version number","code":"ERR_SSL_WRONG_VERSION_NUMBER"} (fetch) TypeError: fetch failed 

Reproducible By

I'm using node to start the local server:

import { createServer } from 'node:http2';
const server = createServer();
// ...define services.
server.listen('/tmp/test.sock');

I can successfully query the local server via curl:

curl -k -v \
  --unix-socket "/tmp/test.sock" \
  --insecure \
  -d '{"message":"test"}' \
  -H "Content-Type: application/json" \
  --http2-prior-knowledge \
  http://localhost/api/demo_rest

But it doesn't work when querying using undici:

import { Agent, fetch as undiciFetch } from 'undici';

const localhostAgent = new Agent({
  connect: {
    socketPath: '/tmp/test.sock',
    rejectUnauthorized: false,
    requestCert: false,
  },
  allowH2: true,
});

await undiciFetch('http://localhost/api/demo_rest', {
  body: JSON.stringify({ message: 'Greetings' }),
  headers: { 'Content-type': 'application/json' },
  method: 'POST',
  dispatcher: localhostAgent,
});

Expected Behavior

The expected behavior is that when a dispatcher does not request a cert, the fetch is able to make a request to an HTTP/2 server over a unix domain socket.

Logs & Screenshots

N/A

Environment

MacOs 14

Additional context

It feels really weird that I can easily start an insecure HTTP2 server using node, but it's very hard (or impossible) to send requests to it.

mctrafik avatar Feb 28 '24 00:02 mctrafik

Currently we do not support H2C. A PR that adds support would be amazing.

mcollina avatar Feb 28 '24 07:02 mcollina

I've been playing around with this recently, and I believe that is not an easy task given the little context we know when instantiating a plain text connection.

There's no way to differentiate when we are communicating through h2c or plain http/1.1; by setting allowH2: true we can assume that all requests will be h2c if going over an unencrypted channel, but it's problematic to assume all connections will be over h2c, especially as there are just little servers outside supporting this mode.

My thought will be to make this mostly a proper Agent (i.e. H2CAgent or something) so it can be safely used and up to the implementer if they want to customize undici to always assume h2c in plain text connections. wdyt?

cc: @mcollina @ronag

metcoder95 avatar Apr 01 '24 09:04 metcoder95

I think something lower level would be better. IMHO a H2CPool would be low level and composable enough.

mcollina avatar Apr 01 '24 09:04 mcollina