Permalink
Browse files

Add support for middleware above node

through the 'preprocess' hook. See the test for details, I'll document
this when I'm happy it's stable
  • Loading branch information...
1 parent 7cf4b68 commit a7125c31fb845f5abf6fe94f4ae123807a12f6e7 @mhansen committed Jul 26, 2010
Showing with 98 additions and 36 deletions.
  1. +46 −36 lib/antinode.js
  2. +11 −0 tests/common.js
  3. +20 −0 tests/fixtures/redirector.js
  4. +21 −0 tests/test-301.js
View
@@ -46,54 +46,25 @@ function handlers_init() {
}
}
+/* default preprocessor - just send the file out */
+var preprocess_request = map_request_to_local_file;
+
exports.start = function(custom_settings, callback) {
settings = custom_settings || {};
settings.__proto__ = exports.default_settings;
load_hostspecific_handlers();
+ if (settings.request_preprocessor) {
+ preprocess_request = settings.request_preprocessor;
+ }
log.level = settings.log_level;
log.info( "Starting server on port", settings.port);
server = http.createServer(function(req,resp) {
log.debug("Request from", req.connection.remoteAddress, "for", req.url);
log.debug(JSON.stringify(req.headers));
-
- var url = uri.parse(req.url);
- //if the parsed url doesn't have a pathname, default to '/'
- var pathname = (url.pathname || '/');
- var clean_pathname = pathname.
- replace(/\.\.\//g,''). //disallow parent directory access
- replace(/\%20/g,' '); //convert spaces
-
- function select_vhost() {
- if (req.headers.host) {
- var hostname = req.headers.host.split(':')[0]; //remove port
- return settings.hosts[hostname] || settings.default_host;
- } else {
- return settings.default_host;
- }
- }
- var vhost = select_vhost(req.headers.host);
- if (vhost.handler && vhost.handler.handle) {
- var action = vhost.handler.handle(req,resp);
- if(action && typeof action === 'function') {
- if(vhost.handler.handler_environment){
- action.apply(vhost.handler.handler_environment(req, resp))
- }
- else {
- action(req, resp);
- }
- return;
- }
- }
- var path = pathlib.join(vhost.root, clean_pathname);
- if (path.match(/\.sjs$/)) {
- execute_sjs(path, req, resp);
- } else {
- serve_static_file(path, req, resp);
- }
-
+ preprocess_request(req, resp, map_request_to_local_file);
});
server.listen(settings.port);
handlers_init();
@@ -109,6 +80,45 @@ exports.start = function(custom_settings, callback) {
});
};
+/* decides which file on our file system the request is asking for
+ * then dispatch to stream_file to send it out */
+function map_request_to_local_file(req, resp) {
+ var url = uri.parse(req.url);
+ //if the parsed url doesn't have a pathname, default to '/'
+ var pathname = (url.pathname || '/');
+ var clean_pathname = pathname.
+ replace(/\.\.\//g,''). //disallow parent directory access
+ replace(/\%20/g,' '); //convert spaces
+
+ function select_vhost() {
+ if (req.headers.host) {
+ var hostname = req.headers.host.split(':')[0]; //remove port
+ return settings.hosts[hostname] || settings.default_host;
+ } else {
+ return settings.default_host;
+ }
+ }
+ var vhost = select_vhost(req.headers.host);
+ if (vhost.handler && vhost.handler.handle) {
+ var action = vhost.handler.handle(req,resp);
+ if(action && typeof action === 'function') {
+ if(vhost.handler.handler_environment){
+ action.apply(vhost.handler.handler_environment(req, resp))
+ }
+ else {
+ action(req, resp);
+ }
+ return;
+ }
+ }
+ var path = pathlib.join(vhost.root, clean_pathname);
+ if (path.match(/\.sjs$/)) {
+ execute_sjs(path, req, resp);
+ } else {
+ serve_static_file(path, req, resp);
+ }
+}
+
exports.stop = function(callback) {
if (server) {
if (callback) server.addListener('close', callback);
View
@@ -26,6 +26,7 @@ exports.settings = {
},
"log_level": antinode.log_levels.ERROR
};
+settings.request_preprocessor = require('./fixtures/redirector').preprocessor;
/* Testing helper functions */
@@ -40,6 +41,7 @@ exports.settings = {
*
* expected_res.statusCode: The expected response code
* expected_res.body: The expected HTTP response body
+ * expected_res.headers: The expected HTTP response headers (only test the ones specified)
* Leave any of these values undefined, and they won't be tested
*/
exports.test_http = function(test, req, expected_res, callback) {
@@ -49,6 +51,15 @@ exports.test_http = function(test, req, expected_res, callback) {
if (expected_res.statusCode) {
test.equals(response.statusCode, expected_res.statusCode);
}
+ if (expected_res.headers) {
+ for (var name in expected_res.headers) {
+ if (expected_res.headers.hasOwnProperty(name)) {
+ var expected_header = expected_res.headers[name];
+ var actual_header = response.headers[name];
+ test.equals(expected_header, actual_header);
+ }
+ }
+ }
if (expected_res.body) {
response.setEncoding('binary');
var offset = 0;
@@ -0,0 +1,20 @@
+var url = require('url');
+var sys = require('sys');
+
+/* export a single function 'preprocessor'
+ * this is middleware - it intercepts functions before anitnode has a chance to serve them
+ * you can rewrite rules, do redirects here, whatever */
+exports['preprocessor'] = function (req, resp, callback) {
+ if (req.headers.host === '301.domain.com') {
+ return redirect_to("http://default-host"+req.url);
+ }
+ else {
+ callback(req, resp);
+ }
+ function redirect_to(url) {
+ resp.writeHead(301, {
+ 'Location': url
+ });
+ resp.end('');
+ }
+}
View
@@ -0,0 +1,21 @@
+require ('./common');
+
+exports['redirect 301 to new domain'] = function (test) {
+ antinode.start(settings, function () {
+ test_http(test, {
+ 'method':'HEAD',
+ 'pathname':'/lol',
+ 'headers':{ 'host': '301.domain.com' }
+ }, {
+ 'statusCode': 301,
+ 'headers' : {
+ 'location': 'http://default-host/lol'
+ },
+ 'body': ''
+ },
+ function () {
+ antinode.stop();
+ test.done();
+ });
+ })
+};

0 comments on commit a7125c3

Please sign in to comment.