Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' of github.com:mhansen/antinode

Conflicts:
	lib/antinode.js
  • Loading branch information...
commit b4b1177daf76003b1c1d1453accfa6923369d842 2 parents e2a1b0a + 1c77ade
@mhansen authored
View
1  README.markdown
@@ -6,6 +6,7 @@ Run it from the command line.
$ node server.js [settings.json]
+Requires Node.JS v0.1.97 or greater.
If you want to bind to a port under 1024, you'll need to run node with special
privileges.
View
129 lib/antinode.js
@@ -23,39 +23,58 @@ var settings;
var server;
+/* require() all the scripts at the start, so there's no
+ * waiting for in the middle of a request */
+function load_hostspecific_scripts() {
+ for (var host in settings.hosts) {
+ var script = settings.hosts[host]['script'];
+ if (script !== undefined) {
+ /* remove filename extension */
+ var require_name = script.match(/(.*)\..*/)[1];
+ settings.hosts[host].handle = require(require_name).handle;
+ }
+ }
+}
+
exports.start = function(custom_settings, callback) {
settings = custom_settings || {};
settings.__proto__ = exports.default_settings;
+
+ load_hostspecific_scripts();
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));
- function get_local_file_path() {
- 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
+ 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;
- }
+ 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);
-
+ }
+ var vhost = select_vhost(req.headers.host);
+ if (vhost['handle'] !== undefined) {
+ vhost.handle(req,resp);
+ } else {
var path = pathlib.join(vhost.root, clean_pathname);
- return path;
+ if (path.match(/\.sjs$/)) {
+ execute_sjs(path, req, resp);
+ } else {
+ serve_static_file(path, req, resp);
+ }
}
- var path = get_local_file_path();
- handle_request(path, req, resp);
});
server.listen(settings.port);
server.addListener('listening', function() {
@@ -77,7 +96,7 @@ exports.stop = function(callback) {
}
};
-function handle_request(path, req, resp) {
+function serve_static_file(path, req, resp) {
function send_headers(httpstatus, length, content_type, modified_time) {
var headers = {
"Server": "Antinode/"+package.version+" Node.js/"+process.version,
@@ -106,27 +125,23 @@ function handle_request(path, req, resp) {
return file_not_found();
}
if (stats.isDirectory()) {
- return handle_request(pathlib.join(path, "index.html"), req, resp);
+ return serve_static_file(pathlib.join(path, "index.html"), req, resp);
}
if (!stats.isFile()) {
return file_not_found();
} else {
- if (path.match(/\.sjs$/)) {
- execute_sjs(path, req, resp);
- } else {
- var if_modified_since = req.headers['if-modified-since'];
- if (if_modified_since) {
- var req_date = new Date(if_modified_since);
- if (stats.mtime <= req_date && req_date <= Date.now()) {
- return not_modified();
- }
- else stream_file(path, stats);
- } else if (req.method == 'HEAD') {
- send_headers(200, stats.size, mime.mime_type(path), stats.mtime);
- finish(resp);
- } else {
- return stream_file(path, stats);
+ var if_modified_since = req.headers['if-modified-since'];
+ if (if_modified_since) {
+ var req_date = new Date(if_modified_since);
+ if (stats.mtime <= req_date && req_date <= Date.now()) {
+ return not_modified();
}
+ else stream_file(path, stats);
+ } else if (req.method == 'HEAD') {
+ send_headers(200, stats.size, mime.mime_type(path), stats.mtime);
+ finish(resp);
+ } else {
+ return stream_file(path, stats);
}
}
});
@@ -142,6 +157,14 @@ function handle_request(path, req, resp) {
send_headers(200, stats.size, mime.mime_type(file), stats.mtime);
+ req.connection.addListener('timeout', function() {
+ /* dont destroy it when the fd's already closed */
+ if (readStream.fd) {
+ log.debug('timed out. destroying file read stream');
+ readStream.destroy();
+ }
+ });
+
readStream.addListener('open', function() {
log.debug("opened",path);
});
@@ -184,22 +207,26 @@ function handle_request(path, req, resp) {
finish(resp);
}
- function execute_sjs() {
- fs.readFile(path, 'utf8', function(err, script) {
- try {
- if (err) throw err;
- var handler = {
- log: log,
- require: require
- };
- Script.runInNewContext(script, handler, path);
- handler.handle(req, resp);
- }
- catch (e) {
- server_error("Error executing server script "+path+": "+e);
- }
- });
- }
+}
+
+function execute_sjs(path, req, resp) {
+ fs.readFile(path, 'utf8', function(err, script) {
+ try {
+ if (err) throw err;
+ var sandbox = {
+ log: log,
+ require: require,
+ __filename: path,
+ __dirname: pathlib.dirname(path)
+ };
+ Script.runInNewContext(script, sandbox, path);
+ sandbox.handle(req, resp);
+ }
+ catch (e) {
+ resp.writeHead(500,{'Content-Type':'text/plain'});
+ resp.end("Error executing server script "+path+": "+e);
+ }
+ });
}
function finish(resp) {
View
2  package.json
@@ -19,7 +19,7 @@
, "directories" : { "lib" : "./lib/" }
, "main" : "./lib/antinode"
, "bin" : { "antinode" : "./server.js" }
-, "engines" : { "node" : ">=0.1.98" }
+, "engines" : { "node" : ">=0.1.97" }
, "licenses" :
[ { "type" : "MIT"
, "url" : "http://github.com/mhansen/antinode/raw/master/LICENSE"
View
11 tests/common.js
@@ -16,6 +16,9 @@ exports.settings = {
"hosts" : {
"examplevirtualhost.com" : {
"root" : path.join(fixturesDir,"examplevirtualhost.com")
+ },
+ "scripthost.com" : {
+ "script" : path.join(fixturesDir,"scripthost.js")
}
},
"default_host" : {
@@ -27,16 +30,16 @@ exports.settings = {
/* Testing helper functions */
-/** Make an HTTP req (given parameters in req), and test the response
+/** Fires an HTTP request, and test that the response is what we expect
+ *
* test: The nodeunit test object
*
* req.method: HTTP request method
* req.headers: HTTP request headers
* req.pathname: HTTP Request resource
*
- * expected_res represents the expected HTTP Response.
- * expected_res.statusCode
- * expected_res.body
+ * expected_res.statusCode: The expected response code
+ * expected_res.body: The expected HTTP response body
* Leave any of these values undefined, and they won't be tested
*/
exports.test_http = function(test, req, expected_res, callback) {
View
6 tests/fixtures/scripthost.js
@@ -0,0 +1,6 @@
+var sys = require('sys');
+
+exports.handle = function (req, res) {
+ res.writeHead(200, { 'Content-Type': 'text/plain' });
+ res.end('hello world');
+}
View
18 tests/test-scripthost.js
@@ -0,0 +1,18 @@
+require('./common');
+
+exports['Request to host with a script handler'] = function (test) {
+ antinode.start(settings, function() {
+ test_http(test, {
+ 'method':'GET',
+ 'pathname':'/',
+ 'headers': { 'host' : 'scripthost.com' }
+ }, {
+ 'statusCode':200,
+ 'body':'hello world'
+ },
+ function () {
+ antinode.stop();
+ test.done();
+ });
+ });
+};
Please sign in to comment.
Something went wrong with that request. Please try again.