Wednesday, August 17, 2011

Express-Spdy on Node 0.5.4

‹prev | My Chain | next›

With my git-scribe changes more or less complete (in my fork), I am ready to switch focus again back to SPDY. I do not believe that this will necessitate any updates to The SPDY Book (though who knows?). This is more just clean-up and maintenance that I need to do before moving on.

Up today, I am going to finally tackle the first (and so far only) known issue affecting express-spdy: keep alive HTTP headers. The SPDY SPDY protocol spec explicitly prohibits keep-alives. Although Chrome is not choking on these currently, it would be good to eliminate them.

But even before that, I may as well ensure that everything is still working on node 0.5.4. So I download 0.5.4 and install it per the express-spdy install instructions (skipping the openssl install because I already had that working). Along the way, I update the install instructions to reference unstable node (0.5) rather than installing from github.

With that, I am ready to load things up. Sadly, instead of seeing my nice CA signed certificate, I am greeted by a connection error. Checking the server, I see:
➜  express-spdy-test  node app.js
Express server listening on port 3000

assert.js:104
throw new assert.AssertionError({
^
AssertionError: missing or invalid endian
at Buffer.writeUInt32 (buffer.js:860:10)
at /home/cstrom/repos/express-spdy-test/node_modules/express-spdy/node_modules/spdy/lib/spdy/protocol.js:72:8
at SPDYServer.<anonymous> (/home/cstrom/repos/express-spdy-test/node_modules/express-spdy/node_modules/spdy/lib/spdy/core.js:113:13)
at SPDYServer.emit (events.js:70:17)
at SecurePair.<anonymous> (tls.js:819:14)
at SecurePair.emit (events.js:64:17)
at SecurePair.maybeInitFinished (tls.js:649:10)
at CleartextStream._push (tls.js:294:17)
at SecurePair.cycle (tls.js:617:20)
at EncryptedStream.write (tls.js:121:13)
Ack! Looks as though I shall be yak shaving today instead of investigating defects. Ah well, there is always tomorrow for defects.

To track this down, I fetch and merge the recent changes to node:
➜  node git:(master) git fetch origin
remote: Counting objects: 6833, done.
remote: Compressing objects: 100% (2047/2047), done.
remote: Total 5769 (delta 4367), reused 4951 (delta 3658)
Receiving objects: 100% (5769/5769), 12.95 MiB | 152 KiB/s, done.
Resolving deltas: 100% (4367/4367), completed with 625 local objects.
From https://github.com/joyent/node
8971b59..4cf931d  master     -> origin/master
58a1d7e..5e37e10  v0.4       -> origin/v0.4
* [new branch]      v8-3.1     -> origin/v8-3.1
From https://github.com/joyent/node
* [new tag]         v0.4.10    -> v0.4.10
* [new tag]         v0.4.9     -> v0.4.9
* [new tag]         v0.5.0     -> v0.5.0
* [new tag]         v0.5.1     -> v0.5.1
* [new tag]         v0.5.2     -> v0.5.2
* [new tag]         v0.5.3     -> v0.5.3
* [new tag]         v0.5.4     -> v0.5.4

➜  node git:(master) git merge origin/master
...
create mode 100644 tools/gyp/tools/pretty_gyp.py
create mode 100755 tools/gyp/tools/pretty_sln.py
create mode 100755 tools/gyp/tools/pretty_vcproj.py
create mode 100755 tools/gyp_node
delete mode 100644 tools/nodejs.pc.in
Wow. Didn't think it had been that long since I updated my local copy of node.

I eventually track down the stacktrace to b7c23ac3 in node.js from last week. Blah.

In that commit (and in node 0.5.4), the writeUInt32 method takes a boolean option to describe the endianness of the Buffer object being written:
Buffer.prototype.writeUInt32 = function(value, offset, bigEndian) {
//... 
assert.ok(typeof (bigEndian) === 'boolean',
'missing or invalid endian');
//...
}
In previous versions of node, the endianness was set via a string:
Buffer.prototype.writeUInt32 = function(value, offset, endian) {
//...
assert.ok(endian !== undefined && endian !== null,
'missing endian');

assert.ok(endian == 'big' || endian == 'little',
'bad endian value');
//...
};
This is how node-spdy is invoking writeUInt32:
buff.writeUInt32(assocStreamID & 0x7fffffff, 4, 'big');
Since 0.5.4 is asserting that the third parameter is a boolean, I get the backtrace.

Complicating matters even further, however, is the fact that writeUInt32 has been removed entirely from master on github (thanks to mscdex in #nodejs for pointing that out). In the next unstable version of node, it will have to be invoked via writeUInt32BE or writeUInt32LE. I'm not sure I'm a fan of including the signedness, the size, the type, and the endiannes in the method name, but it is what it is. Blah.

I think my best strategy is going to be to add a compatibility layer into node-spdy to invoke the proper writeUInt method with the proper arguments. That's gonna get ugly fast, but the first thing that I will do is to explicitly NOT support express-spdy on 0.5.4. The 0.5.4 release should be the only one with the boolean version of writeUInt32. Hopefully after that, I can stick with writeUInt32BE.

I update the express-spdy README and INSTALL instructions. Next, I update the supported engines in express-spdy's package.json to indicate non-support of 0.5.4 (I will update again once 0.5.5 has been released):
//...
"engines": {
"node": ">= 0.5.0-pre < 0.5.4"
},
//...
Lastly, I publish express-spdy to the npm registry:
➜  express-spdy git:(master) npm install .
. Now, if I try to install express-spdy, I get:
➜  tmp  node --version
v0.5.4
➜  tmp  npm install express-spdy
npm ERR! Unsupported
npm ERR! Not compatible with your version of node/npm: express-spdy@0.0.5
npm ERR! Required: {"node":">= 0.5.0-pre < 0.5.4"}
npm ERR! Actual:   {"npm":"1.0.25","node":"v0.5.4"}
Last up tonight, I try out express-spdy on node 0.5.3. Again I follow the instructions in express-spdy's INSTALL instructions. With node 0.5.3, the latest express-spdy installs. More importantly, the site loads: And I have valid SPDY going on: Well, that went sideways pretty quickly, but hopefully I recovered enough to get express-spdy in a usable state. Up tomorrow, I think that I will install node from master so that I can get a head start on node-spdy / express-spdy on node 0.5.5. Day #116

No comments:

Post a Comment