mafintosh / turbo-http

Blazing fast low level http server
MIT License
1k stars 47 forks source link

Add upgrade event support #17

Open hugmanrique opened 6 years ago

hugmanrique commented 6 years ago

This would make this library more similar to the HTTP Node API which would make switching to this lib much easier. The event callback has the following params:

I think having the request and response objects would be ideal. You can already grab the socket and the headers from the req object.

Here's the Node.js docs

doesdev commented 5 years ago

Based on some quick experimentation in hacking support in at the implementation level, it's a bit more complicated than this would suggest. the 3rd argument is actually a Buffer which, based on this, should be "the first packet of the upgraded stream".

But, I've not had much success hacking it in so far. Gonna mess around with it some more and report back if/when I get something working.

doesdev commented 5 years ago

Okay, through some hacking I did get WebSockets upgrade working with ws, with caveats. In addition to the server emitting an upgrade event here are the bits that I found needing to happen in order to make it work with ws.

All of that results in being able to upgrade to WebSockets with ws. That by no means implies that anything I've done in these hacks would be expected to work with anything else or that it even works properly. It seems to work properly enough to pass my tests, but that doesn't mean what I did to get it working is anything near an actual solution.

If I am able to get to something I'm more confident about I'll do a PR (here and in turbo-net).

Here's what the hacky garbage I put together looks like:

function handleUpgrade (server, req, res) {
  if (req.getHeader('connection') !== 'Upgrade') return false
  req.headers = {}
  for (const [k, v] of req.getAllHeaders()) { req.headers[k] = v }

  const write = req.socket.write
  req.socket.write = function (d, len, cb) {
    return write.call(
      req.socket,
      Buffer.isBuffer(d) ? d : Buffer.from(d, 'utf8'),
      len,
      cb
    )
  }
  req.socket.setNoDelay = req.socket.setTimeout = () => {}

  server.emit('upgrade', req, req.socket, Buffer.alloc(0))
  return true
}

// somewhere in a request handler, which must also have access to the server object
function handleRequest (req, res) {
  if (handleUpgrade(server, req, res)) return
  // ...
}