I was finally able to get node-spdy and express.js to establish an actual SPDY session yesterday. I had been spiking pretty heavily, so today I retrace my steps to ensure I understand what I did.
In my express branch of node-spdy, I have only added the express.js skeleton app with SPDY configuration:
* a715da7 (HEAD, express) SPDY configuration for express appNice. That means that Fedor Indunty wrote node-spdy ready-made for connect-express integration.
* 687cce4 Skeleton express app
* 9d9e2b7 (origin/master, origin/HEAD, master) Merge branch 'master' of github.com:indutny/node-spdy
As for the changes to express.js (and connect, on which express.js is built), I think that they can be summarized as:
- connect: create a lib/spdy.js copied from lib/https.js
- express: create a lib/spdy.js copied from lib/https.js
- express: decorate the SPDY Response class with render methods from the Response object in express
- express: decorate the SPDY Response class with send, contentType, header (and probably other) methods from the express Response object
First up,
lib/spdy.js
in connect (copied almost directly from lib/https.js
):Next, I do the same for
/*!
* Connect - SPDYServer
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var HTTPServer = require('./http').Server
, spdy = require('spdy');
/**
* Initialize a new `Server` with the given
*`options` and `middleware`. The SPDY api
* is identical to the HTTPS api, which
* is identical to the [HTTP](http.html) server,
* however TLS `options` must be provided before
* passing in the optional middleware.
*
* @params {Object} options
* @params {Array} middleawre
* @return {Server}
* @api public
*/
var Server = exports.Server = function SPDYServer(options, middleware) {
this.stack = [];
middleware.forEach(function(fn){
this.use(fn);
}, this);
spdy.Server.call(this, options, this.handle);
};
/**
* Inherit from `http.Server.prototype`.
*/
Server.prototype.__proto__ = spdy.Server.prototype;
// mixin HTTPServer methods
Object.keys(HTTPServer.prototype).forEach(function(method){
Server.prototype[method] = HTTPServer.prototype[method];
});
lib/spdy.js
in express.js:Also in express.js/
/*!
* Express - SPDYServer
* Copyright(c) 2010 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var connect = require('connect')
, HTTPServer = require('./http')
, spdy = require('spdy');
/**
* Expose `SPDYServer`.
*/
exports = module.exports = SPDYServer;
/**
* Server proto.
*/
var app = SPDYServer.prototype;
/**
* Initialize a new `SPDYServer` with the
* given `options`, and optional `middleware`.
*
* @param {Object} options
* @param {Array} middleware
* @api public
*/
function SPDYServer(options, middleware){
connect.SPDYServer.call(this, options, []);
this.init(middleware);
};
/**
* Inherit from `connect.SPDYServer`.
*/
app.__proto__ = connect.SPDYServer.prototype;
// mixin HTTPServer methods
Object.keys(HTTPServer.prototype).forEach(function(method){
app[method] = HTTPServer.prototype[method];
});
lib/spdy.js
, I mixin rendering related methods from express.js's Response
:var connect = require('connect')Lastly, I have to mixin other methods to the SPDY
, HTTPServer = require('./http')
, spdy = require('spdy')
, spdy_res = spdy.Response.prototype
, http = require('http')
, res = http.ServerResponse.prototype;
// ...
// TODO: don't hard-code which methods get mixed-in
spdy_res.partial = res.partial;
spdy_res.render = res.render;
spdy_res._render = res._render;
Response
class. As noted last night, I cannot do so in lib/spdy.js
. I have to do that directly in lib/express.js
to ensure that the necessary methods have been defined at runtime:/**Unless I missed something that ought to do it. As it turns out, I did miss something. When I try to start up the server, I get:
* Response extensions.
*/
require('./response');
var http = require('http')
, res = http.ServerResponse.prototype
, spdy = require('../../../lib/spdy')
, spdy_res = spdy.Response.prototype;
spdy_res.send = res.send;
spdy_res.header = res.header;
spdy_res.contentType = res.contentType;
➜ node-spdy git:(express) node test/express/app.jsAw nuts, the error on line 49 of
node.js:183
throw e; // process.nextTick error, or 'error' event on first tick
^
TypeError: Cannot read property 'prototype' of undefined
at Object.<anonymous> (/home/cstrom/repos/node-spdy/node_modules/express/lib/spdy.js:49:35)
at Module._compile (module.js:423:26)
at Object..js (module.js:429:10)
at Module.load (module.js:339:31)
at Function._load (module.js:298:12)
at require (module.js:367:19)
at Object.<anonymous> (/home/cstrom/repos/node-spdy/node_modules/express/lib/express.js:14:18)
at Module._compile (module.js:423:26)
at Object..js (module.js:429:10)
at Module.load (module.js:339:31)
express/lib/app.js
is coming from:app.__proto__ = connect.SPDYServer.prototype;It looks as though, in addition to mucking directly with
express/lib/express.js
, I also mucked with connect/lib/connect.js
.In
connect/lib/connect.js
, I need to define and export SPDYServer, which ought to make that error go away. For good measure, I also replace the call to HTTPSServer with a SPDYServer call (node-spdy will fallback to plain-old https if SPDY is not available):var HTTPServer = require('./http').ServerThat does the trick. I again have my SPDY session working with express.js.
, HTTPSServer = require('./https').Server
, SPDYServer = require('./spdy').Server
, fs = require('fs');
// ...
function createServer() {
if ('object' == typeof arguments[0]) {
// return new HTTPSServer(arguments[0], Array.prototype.slice.call(arguments, 1));
return new SPDYServer(arguments[0], Array.prototype.slice.call(arguments, 1));
} else {
return new HTTPServer(Array.prototype.slice.call(arguments));
}
//...
exports.HTTPServer = HTTPServer;
exports.HTTPSServer = HTTPSServer;
exports.SPDYServer = SPDYServer;
In the end, I had to do the following to get express.js SPDY-ized:
- connect: create a lib/spdy.js copied from lib/https.js
- connect: export SPDYServer from the main connect object and replace the main HTTPS server with the SPDYServer
- express: create a lib/spdy.js copied from lib/https.js
- express: decorate the SPDY Response class with render methods from the Response object in express (needs to be done in lib/express.js)
- express: decorate the SPDY Response class with send, contentType, header (and probably other) methods from the express Response object
Day #55
No comments:
Post a Comment