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 Web Socket in Chrome not working #694

Open
ackava opened this issue Feb 12, 2024 · 2 comments
Open

HTTP/2 Web Socket in Chrome not working #694

ackava opened this issue Feb 12, 2024 · 2 comments
Labels
bug Something isn't working

Comments

@ackava
Copy link

ackava commented Feb 12, 2024

Describe the bug
Creating HTTP/2 server mentioned in the example works well with Firefox because Firefox still uses HTTP/1.1 to connect to web server. However, chrome has implemented CONNECT method of HTTP/2, and thus socket.io no longer connects with HTTP/2 server.

Chrome 120 still connects Web Socket over HTTP 1.1, but this stops working from 121 onwards.

To Reproduce

  1. Juse use simple socket.io sample to create HTTP/2 server with SSL certificate.
  2. Try to connect to socket.io server from Google Chorme.

Expected behavior
It should connect to socket.io server, but it does not.

Platform:

  • OS: Desktop
  • Browser: Google Chorme (121.0.6167.161) +

Additional context
For HTTP/1.1 , http2Server emits upgrade event, which engine.io handles correctly.
For HTTP/2, http2Server does not emit upgrade event if web socket client sends HTTP-METHOD='CONNECT'.

Work Around/Recommendation

httpServer.prependListener("stream", (stream, headers) => {

    // we need to look for CONNECT
    if(headers[":method"] !== "CONNECT") {
        return;
    }

    try {

      // this keeps socket alive...
      stream.setTimeout(0);
      (stream as any).setKeepAlive?.(true, 0);
      (stream as any).setNoDelay = function() {
          // this will keep the stream open
      };


      const websocket = new WebSocket(null, void 0, {
          headers
      });
      websocket.setSocket(stream, Buffer.alloc(0), {
          maxPayload: 104857600,
          skipUTF8Validation: false,
      });
      const path = headers[":path"];
      const url = new URL(path, "http://a");
      const _query = {};
      for (const [key, value] of url.searchParams.entries()) {
          _query[key] = value;
      }
      // fake build request
      const req = {
          url: path,
          headers,
          websocket,
          _query
      };
      stream.respond({
          ":status": 200
      });
     // for some reason this is not working !!
      this.handshake("websocket",req,() => { try { stream.end(); } catch {} }).catch(console.error);
  } catch (error) {
      console.error(error);
  }
});
@ackava ackava added the bug Something isn't working label Feb 12, 2024
@ackava ackava closed this as completed Feb 12, 2024
@ackava ackava reopened this Feb 14, 2024
@darrachequesne
Copy link
Member

I could indeed reproduce the issue, thanks for raising this.

Another possible workaround is to start the HTTP/2 server with allowHTTP1: true:

const server = createSecureServer(
  {
    key: readFileSync("./key.pem"),
    cert: readFileSync("./cert.pem"),
    allowHTTP1: true,
  }
);
const io = new Server(server);

Related: websockets/ws#1458

@ackava
Copy link
Author

ackava commented Feb 27, 2024

@darrachequesne allowHTTP1 no longer works with chrome version 121 onwards, it used to work till 120.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants