From dac5932b5329ab75f0aac48f5a3be5c1c2b1e93e Mon Sep 17 00:00:00 2001 From: ringmaster Date: Wed, 3 Aug 2011 09:52:56 -0400 Subject: [PATCH 1/9] No default routes, not even for favicons. --- lib/jqNode.js | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/lib/jqNode.js b/lib/jqNode.js index dbdc6ca..3495eef 100644 --- a/lib/jqNode.js +++ b/lib/jqNode.js @@ -19,25 +19,21 @@ function route(request, response) { console.log("Received " + method + " request at " + pathName); } - if(pathName === "/favicon.ico") { - $.writeFile("favicon.ico", "image/x-icon"); - } else { - if(handler = routes[pathName][method]){ - if(method === "POST") { - _data = ""; - request.addListener("data", function(chunk) { - _data += chunk; - }); - request.addListener("end", function() { - handler(request, response, require('querystring').parse(_data)); - }); - } else { - handler(request, response, _data); - } + if(handler = routes[pathName][method]){ + if(method === "POST") { + _data = ""; + request.addListener("data", function(chunk) { + _data += chunk; + }); + request.addListener("end", function() { + handler(request, response, require('querystring').parse(_data)); + }); } else { - response.writeHead(200, {'Content-Type' : 'text/html'}); - response.end("

404. Not found.

"); - } + handler(request, response, _data); + } + } else { + response.writeHead(200, {'Content-Type' : 'text/html'}); + response.end("

404. Not found.

"); } } From 5607d68224b393fede43f5c5ef85ddd0c112bdd1 Mon Sep 17 00:00:00 2001 From: ringmaster Date: Wed, 3 Aug 2011 09:55:28 -0400 Subject: [PATCH 2/9] All verbs should support body data. --- lib/jqNode.js | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/lib/jqNode.js b/lib/jqNode.js index 3495eef..f35b47e 100644 --- a/lib/jqNode.js +++ b/lib/jqNode.js @@ -13,24 +13,20 @@ function route(request, response) { method = request.method; _response = response; - _data = parsedUrl.query; + _querystring = parsedUrl.query; if(_debug) { console.log("Received " + method + " request at " + pathName); } if(handler = routes[pathName][method]){ - if(method === "POST") { - _data = ""; - request.addListener("data", function(chunk) { - _data += chunk; - }); - request.addListener("end", function() { - handler(request, response, require('querystring').parse(_data)); - }); - } else { - handler(request, response, _data); - } + _data = ""; + request.addListener("data", function(chunk) { + _data += chunk; + }); + request.addListener("end", function() { + handler(request, response, _querystring, require('querystring').parse(_data)); + }); } else { response.writeHead(200, {'Content-Type' : 'text/html'}); response.end("

404. Not found.

"); From 079723af50fe62bb2766eceb10032befe0873e50 Mon Sep 17 00:00:00 2001 From: ringmaster Date: Wed, 3 Aug 2011 10:04:55 -0400 Subject: [PATCH 3/9] Check for route first then method, and fix example code. --- examples/app.js | 3 ++- lib/jqNode.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/app.js b/examples/app.js index 75ad178..a33d980 100644 --- a/examples/app.js +++ b/examples/app.js @@ -4,8 +4,9 @@ $("/").get(function(request, response) { $.writeFile("index.html"); }); -$("/test").post(function(request, response, data) { +$("/test").post(function(request, response, querystring, data) { console.log(data); + $.write(data.sample); }); $.start(8888, true); diff --git a/lib/jqNode.js b/lib/jqNode.js index f35b47e..5028256 100644 --- a/lib/jqNode.js +++ b/lib/jqNode.js @@ -19,7 +19,7 @@ function route(request, response) { console.log("Received " + method + " request at " + pathName); } - if(handler = routes[pathName][method]){ + if(routes[pathName] && (handler = routes[pathName][method])){ _data = ""; request.addListener("data", function(chunk) { _data += chunk; From d1d656c97a1306d42d236f2aff11f5966f809b92 Mon Sep 17 00:00:00 2001 From: ringmaster Date: Wed, 3 Aug 2011 10:21:22 -0400 Subject: [PATCH 4/9] Add regex route capability, correct 404 response code --- examples/app.js | 2 +- lib/jqNode.js | 36 ++++++++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/examples/app.js b/examples/app.js index a33d980..e82412c 100644 --- a/examples/app.js +++ b/examples/app.js @@ -4,7 +4,7 @@ $("/").get(function(request, response) { $.writeFile("index.html"); }); -$("/test").post(function(request, response, querystring, data) { +$(new RegExp("/test")).post(function(request, response, querystring, data) { console.log(data); $.write(data.sample); }); diff --git a/lib/jqNode.js b/lib/jqNode.js index 5028256..e8ae704 100644 --- a/lib/jqNode.js +++ b/lib/jqNode.js @@ -3,6 +3,7 @@ var fs = require("fs"), url = require("url"); var routes = {}, +regexroutes = [], server = http.createServer(); var _response, _data, _debug = true; @@ -18,8 +19,20 @@ function route(request, response) { if(_debug) { console.log("Received " + method + " request at " + pathName); } + + var handler = false; - if(routes[pathName] && (handler = routes[pathName][method])){ + if(routes[pathName] && (handler = routes[pathName][method])){ + handler = routes[pathName][method]; + } else { + for(routeindex in regexroutes) { + route = regexroutes[routeindex]; + if(pathName.match(route.regex) && method == route.method) { + handler = route.callback; + } + } + } + if(handler) { _data = ""; request.addListener("data", function(chunk) { _data += chunk; @@ -27,17 +40,28 @@ function route(request, response) { request.addListener("end", function() { handler(request, response, _querystring, require('querystring').parse(_data)); }); - } else { - response.writeHead(200, {'Content-Type' : 'text/html'}); + } + else { + response.writeHead(404, {'Content-Type' : 'text/html'}); response.end("

404. Not found.

"); } } function addRoute(url, method, callback) { - if(!routes[url]) { - routes[url] = {}; + finder = /function (.+?)\(/; + url.constructor.toString().match(finder); + switch(RegExp.$1) { + case "RegExp": + regexroutes.push({'regex': url, 'method': method, 'callback': callback}); + break; + default: + + if(!routes[url]) { + routes[url] = {}; + } + routes[url][method] = callback; + break; } - routes[url][method] = callback; } var $ = function(url) { From 7182d8cd432b8c37c042f6595a55596b2116a68b Mon Sep 17 00:00:00 2001 From: ringmaster Date: Wed, 3 Aug 2011 10:23:44 -0400 Subject: [PATCH 5/9] Handle using the first matching route, not the last --- lib/jqNode.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/jqNode.js b/lib/jqNode.js index e8ae704..64dbb6a 100644 --- a/lib/jqNode.js +++ b/lib/jqNode.js @@ -29,6 +29,7 @@ function route(request, response) { route = regexroutes[routeindex]; if(pathName.match(route.regex) && method == route.method) { handler = route.callback; + break; } } } From f8c41a2995066ebbe8f16312e5672ec6194856b4 Mon Sep 17 00:00:00 2001 From: ringmaster Date: Wed, 3 Aug 2011 10:35:38 -0400 Subject: [PATCH 6/9] Pass server config as object. Prep for automatic file dispatch on GET. --- examples/app.js | 2 +- lib/jqNode.js | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/examples/app.js b/examples/app.js index e82412c..f1b6cc6 100644 --- a/examples/app.js +++ b/examples/app.js @@ -9,4 +9,4 @@ $(new RegExp("/test")).post(function(request, response, querystring, data) { $.write(data.sample); }); -$.start(8888, true); +$.start({debug: true}); diff --git a/lib/jqNode.js b/lib/jqNode.js index 64dbb6a..9ecca98 100644 --- a/lib/jqNode.js +++ b/lib/jqNode.js @@ -6,7 +6,7 @@ var routes = {}, regexroutes = [], server = http.createServer(); -var _response, _data, _debug = true; +var _response, _data; function route(request, response) { var parsedUrl = url.parse(request.url, true), @@ -16,7 +16,7 @@ function route(request, response) { _response = response; _querystring = parsedUrl.query; - if(_debug) { + if($.config.debug) { console.log("Received " + method + " request at " + pathName); } @@ -101,15 +101,16 @@ $.fn['delete'] = function(callback) { } -$.start = function(port, debugMode) { - if(!port) { - port = 8888; +$.start = function(config) { + $.config = { + port: 8888, + debug: false, } + for (attrname in config) { $.config[attrname] = config[attrname]; } server.on('request', route); - server.listen(port); - if(debugMode) { - _debug = true; - console.log("Listening at port " + port); + server.listen($.config.port); + if($.config.debug) { + console.log("Listening at port " + $.config.port); } return server; } @@ -130,7 +131,7 @@ $.writeFile = function(fileName, contentType) { fs.readFile(fileName, function(error, data) { if(error) { _response.end("

Unable to load page. File not found

"); - if(_debug) { + if($.config.debug) { console.log(fileName + " not found"); } } else { From 7cd1259a1959b6239038c020881cf024935261d5 Mon Sep 17 00:00:00 2001 From: ringmaster Date: Sat, 20 Aug 2011 15:37:14 -0400 Subject: [PATCH 7/9] Add docroot config parameter to automatically serve files from a filesystem directory. --- examples/app.js | 2 +- lib/jqNode.js | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/examples/app.js b/examples/app.js index f1b6cc6..d618dc0 100644 --- a/examples/app.js +++ b/examples/app.js @@ -9,4 +9,4 @@ $(new RegExp("/test")).post(function(request, response, querystring, data) { $.write(data.sample); }); -$.start({debug: true}); +$.start({debug: true, docroot: __dirname + '/htdocs'}); diff --git a/lib/jqNode.js b/lib/jqNode.js index 9ecca98..71c2141 100644 --- a/lib/jqNode.js +++ b/lib/jqNode.js @@ -33,6 +33,10 @@ function route(request, response) { } } } + if(!handler && $.config.docroot) { + filename = $.config.docroot + pathName.replace(/\.\./, '.'); + handler = function(){$.writeFile(filename, 'text/html');} + } if(handler) { _data = ""; request.addListener("data", function(chunk) { @@ -105,6 +109,7 @@ $.start = function(config) { $.config = { port: 8888, debug: false, + docroot: false, } for (attrname in config) { $.config[attrname] = config[attrname]; } server.on('request', route); @@ -127,14 +132,15 @@ $.writeFile = function(fileName, contentType) { if(!contentType) { contentType = "text/html"; } - _response.writeHead(200, {'Content-Type' : contentType}); fs.readFile(fileName, function(error, data) { if(error) { - _response.end("

Unable to load page. File not found

"); + _response.writeHead(404, {'Content-Type' : 'text/html'}); + _response.end("

404. Not found

"); if($.config.debug) { console.log(fileName + " not found"); } } else { + _response.writeHead(200, {'Content-Type' : contentType}); _response.end(data); } }); From 5b0ea11af1792f3b32654cb157e54e314c54ae35 Mon Sep 17 00:00:00 2001 From: ringmaster Date: Mon, 12 Mar 2012 09:07:57 -0400 Subject: [PATCH 8/9] Mimetypes and debug changes. --- lib/jqNode.js | 46 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/lib/jqNode.js b/lib/jqNode.js index 71c2141..e7fdc7a 100644 --- a/lib/jqNode.js +++ b/lib/jqNode.js @@ -12,13 +12,12 @@ function route(request, response) { var parsedUrl = url.parse(request.url, true), pathName = parsedUrl.pathname, method = request.method; - + _response = response; _querystring = parsedUrl.query; - if($.config.debug) { - console.log("Received " + method + " request at " + pathName); - } + $.debug("Received " + method + " request at " + pathName); + $.debug(request.headers); var handler = false; @@ -35,7 +34,7 @@ function route(request, response) { } if(!handler && $.config.docroot) { filename = $.config.docroot + pathName.replace(/\.\./, '.'); - handler = function(){$.writeFile(filename, 'text/html');} + handler = function(){$.writeFile(filename, $.mimetype(filename));} } if(handler) { _data = ""; @@ -104,6 +103,30 @@ $.fn['delete'] = function(callback) { addRoute(this.url, "DELETE", callback); } +$.mimetypes = { + html: 'text/html', + htm: 'text/html', + png: 'image/png', + jpg: 'image/jpeg', + jpeg: 'image/jpeg', + gif: 'image/gif', + css: 'text/css', + js: 'text/javascript' +}; + +$.mimetype = function(filename) { + filename.match(/\.([^.]+)$/); + if($.mimetypes[RegExp.$1] != undefined) { + return $.mimetypes[RegExp.$1]; + } + return 'application/octet-stream'; +} + +$.debug = function() { + if($.config.debug) { + console.log.apply($, arguments); + } +} $.start = function(config) { $.config = { @@ -112,11 +135,13 @@ $.start = function(config) { docroot: false, } for (attrname in config) { $.config[attrname] = config[attrname]; } - server.on('request', route); - server.listen($.config.port); if($.config.debug) { - console.log("Listening at port " + $.config.port); + console.log('Config Options:'); + for (attrname in $.config) { console.log(' ' + attrname + ': ' + $.config[attrname]); } } + server.on('request', route); + server.listen($.config.port); + $.debug("Listening at port " + $.config.port); return server; } @@ -136,9 +161,7 @@ $.writeFile = function(fileName, contentType) { if(error) { _response.writeHead(404, {'Content-Type' : 'text/html'}); _response.end("

404. Not found

"); - if($.config.debug) { - console.log(fileName + " not found"); - } + $.debug(fileName + " not found"); } else { _response.writeHead(200, {'Content-Type' : contentType}); _response.end(data); @@ -147,3 +170,4 @@ $.writeFile = function(fileName, contentType) { } exports.$ = $; + From 146a8ee801b83e0d6fe1767e6187ce144f305192 Mon Sep 17 00:00:00 2001 From: ringmaster Date: Mon, 12 Mar 2012 09:08:27 -0400 Subject: [PATCH 9/9] Package version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c44261b..a3b1caa 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "jqNode", "description": "An easy to use jQuery-esque library for NodeJS", - "version": "0.0.1", + "version": "0.0.2", "author": "Pradeek ", "keywords": ["framework", "jquery", "web"], "repository": "git://github.com/pradeek/jqNode",