Skip to content

WebSocket GET handshake (upgrade) routing #2594

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

Closed
ibc opened this issue Mar 14, 2015 · 13 comments
Closed

WebSocket GET handshake (upgrade) routing #2594

ibc opened this issue Mar 14, 2015 · 13 comments

Comments

@ibc
Copy link

ibc commented Mar 14, 2015

I don't meam an "integrated WebSocket server" but the possibility of performing express routing for WebSocket handshake requests.

Node httpServer emits an "upgrade" event for HTTP GET requests including a "Upgrade" header. Express may provide a new "method" called "websocket" for handling them (if the "Upgrade" header has value "websocket"), so the GET request may be processed as any other HTTP verb:

var app = express();

app.websocket('/websocket/:service', function(req, res, next) {
  [...]
});

In this way, Cookies present in the HTTP request may be checked using express middlewares (for example).

@dougwilson
Copy link
Contributor

Perhaps, but Express is not a HTTP server, it is only a function. You just pass an Express app yo the requestListener osf whatever HTTP server module you choose to use.

All an app is is app(req, res, next). You can even typeof on your app variable. Because of this, Express has no way to actually listen to any events on the HTTP server.

@dougwilson
Copy link
Contributor

As for using Express middleware with websockets, this is already possible without any effort from express. Many many people already do this today, especially with express-session.

@dougwilson
Copy link
Contributor

I'm not dismissing this (or I would have closed the issue), but if you or someone could put together a PR that is even just a WIP towards this against the 5.x branch, that would have the best chance of getting in :)

@LinusU
Copy link
Member

LinusU commented Mar 21, 2015

FYI I don't think it's necessary to listen to the event, that is just a convenience for other libraries (i.e. socket.io). We just need to check if the Upgrade: header is present and act accordingly.

@dougwilson
Copy link
Contributor

Please make a PR :)

@ibc
Copy link
Author

ibc commented Mar 22, 2015

IMHO this is not so easy. AFAIK the httpServer will emit upgrade upon receipt of a GET request with header "Upgrade", and it is in that event where existing WS libraries (such as ws or websocket-node) react to perform the handshake or notify the app. What I mean is that, at that point ("upgrade" event fired) the WS server as already control over the request. Express should keep the "upgrade" event until a middleware handles it. Otherwise it should be replied with 404 as usual, but for that something should listen for the "upgrade" event and invoke the app.handle() method somehow...

@dougwilson
Copy link
Contributor

Sure. The problem is I really don't use WebSockets, so I'm really looking for someone to offer a PR against the 5.x branch for this idea is all, otherwise if no on I going to make a PR, I may have to close this issue since it's not being acted on.

The PR can even be a WIP, as I said above. I'm just looking for code to demonstrate your idea.

@olalonde
Copy link

+1 I'm currently using a custom handleUpgrade to do authentication before passing the request to https://github.com/websockets/ws/ but it would be nice to be able to use express middleware / routing. Not interested in using socket.io

@olalonde
Copy link

Just wrote this module: https://github.com/olalonde/express-websocket

var http = require('http');
var ws = require('ws');

module.exports = function (app, wss) {
  if (!wss) {
    wss = new ws.Server({ noServer: true });
  }

  // https://github.com/websockets/ws/blob/master/lib/WebSocketServer.js#L77
  return function (req, socket, upgradeHead) {
    var res = new http.ServerResponse(req);
    res.assignSocket(socket);

    res.websocket = function (cb) {
      var head = new Buffer(upgradeHead.length);
      upgradeHead.copy(head);
      wss.handleUpgrade(req, socket, head, function (client) {
        //client.req = req; res.req
        wss.emit('connection'+req.url, client);
        wss.emit('connection', client);
        cb(client);
      });
    };

    return app(req, res);
  };
};

Basically, it routes the request to an express app and exposes the res.websocket() method which starts the websocket connection.

@dougwilson
Copy link
Contributor

There hasn't been much discussion in here for a month. Any thoughts on issuing a PR to discuss over? Otherwise, I may need to close this for becoming stale.

@dcousens
Copy link

dcousens commented Jun 28, 2016

It'd be awesome to do something like the above that @olalonde has done, and I might be adopting his solution (if slightly modified).
As it currently stands, it feels very strangely architectured IMHO.

edit: my solution:

let http = require('http')
let express = require('express')

let app = express()
let server = http.createServer(...)

// ... etc
server.on('upgrade', (req, socket) => {
  let res = new http.ServerResponse(req)
  res.assignSocket(socket)

  res.on('finish', () => res.socket.destroy())
  app(req, res)
})

// elsewhere
  router.use('/', (req, res, next) => {
    if (!req.headers ||
      req.headers.upgrade === undefined ||
      req.headers.upgrade.toLowerCase() !== 'websocket') return next()

    wss.handleUpgrade(req, req.socket, undefined, (socket) => {
      console.log('upgraded!')
      socket.send('woo')
      socket.close()
    })
  })

@toomim
Copy link

toomim commented May 10, 2017

I just ran across this old thread. Perhaps the following library is relevant now?
https://www.npmjs.com/package/express-ws

@IamLizu
Copy link
Member

IamLizu commented Sep 2, 2024

Closing as stale.

@IamLizu IamLizu closed this as not planned Won't fix, can't repro, duplicate, stale Sep 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants