Skip to content

Instantly share code, notes, and snippets.

@bengl
Forked from wesleytodd/framework.js
Last active September 13, 2020 09:17
Show Gist options
  • Save bengl/585de1cf3fe13e94cdd8e97fe0a69e98 to your computer and use it in GitHub Desktop.
Save bengl/585de1cf3fe13e94cdd8e97fe0a69e98 to your computer and use it in GitHub Desktop.
Just noodling on the future Node.js and http
import http from 'http-next'
import fs from 'fs'
const server = http.createServer({
allowHTTP1: true,
allowHTTP2: true,
allowHTTP3: true,
key: fs.readFileSync('localhost-privkey.pem'),
cert: fs.readFileSync('localhost-cert.pem')
})
// Nixed a bunch of error handling to concentrate on the spirit of what I'm getting at here.
// That should totally be added back in. Sorry.
// Now it's just a simple echo server with a favicon since I didn't feel like writing the rest out :D
// Finally: note that I'm not arguing against any other options. Just throwing this out there.
for await (const session of server) {
;(async session => {
for await (const req of session) {
req.handle(() => {
// Two main things on this one:
// 1. All relevant stuff is in a callback which is simply never called in http1.
// 2. Returnable response objects, which I'll get to in a minute.
req.serverPush('/favicon.ico', () => {
const res = new http.ServerResponse()
fs.createReadStream('./public/favico.ico').pipe(res)
return res
}
const reqBody = await req.body()
const res = new http.ServerResponse(200)
res.write(reqBody)
return res // returning here also implicitly ends the writable stream if it has not been ended.
// Could also support returning buffers or strings
})
}
})(session)
}
// tl;dr i really like the concept of returning a response.
@awwright
Copy link

awwright commented Sep 13, 2020

I have a few thoughts on this I would like to present, but I would like to focus on one, the idea of returning a ServerResponse.

I have a library, http-transform, that allows you to do this:

function makeResponse(req){
	const res = new ResponsePassThrough;
	res.statusCode = 200;
	res.setHeader('Content-Type', 'text/plain')
	res.write('Line\r\n');
	// you can also `return res;` but this will return the writable interface, too.
	return res.readable;
}

From here, you can call makeResponse to get an IncomingMessage, and you can pipe it to a ServerResponse object:

function request(req, res){
	// you can also call .pipe() but for compatibility, this doesn't set the headers, it pipes only the body.
	makeResponse(req).pipeMessage(res);
}

Doing this native in Node.js would require a significant undertaking because it has an asymmetrical interface for "Readable" and "Writable" streams. (f the interfaces were symmetrical, you would make data readable by calling write()—but you call push(). Why?)

There are several problems with error propagation I've been unable to completely solve, because of bad assumptions that Node.js makes about event emitters and streams.

To properly implement this, Node.js would need a "Simplex Pair" object, where there is a single buffer that is filled from a Writable side, and drained from a Readable side. (As it stands right now, this is not easy to do, and linking a Readable to a Writable will create at minimum two places where data is buffered.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment