├── index.js ├── .gitmodules ├── examples ├── public │ ├── lobby.html │ ├── error │ │ ├── 404.html │ │ └── 500.html │ └── index.html ├── simple_server.js ├── clustering.js ├── clustering_with_sessions.js ├── routes.js └── sessions.js ├── .travis.yml ├── .gitignore ├── changelist.md ├── docs ├── routes.md └── benchmarks.md ├── lib ├── util.js ├── redirections.js ├── routes │ ├── route_data.js │ └── action.js ├── cluster_server.js ├── config.js ├── index.js ├── session.js ├── routes.js ├── mime.js └── http_server.js ├── package.json ├── test └── serveme_tests.js └── README.md /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib'); 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/utyl"] 2 | path = lib/utyl 3 | url = https://github.com/muit/utyl.git 4 | -------------------------------------------------------------------------------- /examples/public/lobby.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |

Lobby

7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/public/error/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

ERROR: 404

5 |
6 |

Page not found.

7 | 8 | -------------------------------------------------------------------------------- /examples/public/error/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

ERROR: 500


5 |

Internal server error.

6 | 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.12.7' 4 | before_install: 5 | - currentfolder=${PWD##*/} 6 | - if [ "$currentfolder" != 'serveMe' ]; then cd .. && eval "mv $currentfolder serveMe" && cd serveMe; fi 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | lib-cov 3 | *.seed 4 | *.log 5 | *.csv 6 | *.dat 7 | *.out 8 | *.pid 9 | *.gz 10 | 11 | pids 12 | logs 13 | results 14 | 15 | node_modules 16 | npm-debug.log 17 | npm-debug.log.* 18 | *.swp 19 | *.pem 20 | connect.sh 21 | password* -------------------------------------------------------------------------------- /changelist.md: -------------------------------------------------------------------------------- 1 | # Serveme list of changes 2 | You will find all the new changes ordered by version here. 3 | ### 0.8.2 4 | - Listening callback and event. 5 | - Readme fix 6 | 7 | ### 0.8.1 8 | - Implemented require on the routes 9 | - Route callbacks are now optional 10 | - Testing new features 11 | - Fixes 12 | 13 | ### 0.8 14 | - Implemented multiple route algorithm (Performance) 15 | - Internal documentation (Docs) 16 | - Changed routes protected word "data" to "_action" (Use) 17 | - Core refactorized and simplified (Performance) 18 | - New logging messages (Use) 19 | - More fixes and codestyle -------------------------------------------------------------------------------- /docs/routes.md: -------------------------------------------------------------------------------- 1 | # Internal route structure 2 | This document defines how do the internal routes work and how is their structure. 3 | 4 | 5 | ### Routes without parameters 6 | 7 | ```javascript 8 | //route: /arg0/arg1 9 | 10 | simpleRoutesDB = { 11 | "/arg0/arg1": { 12 | "_action": new Action(callback) 13 | } 14 | } 15 | ``` 16 | 17 | ### Routes with parameters 18 | The path of a route will be split in arguments by "/". Each argument will become a new level on the routeDB. 19 | 20 | ```javascript 21 | //route: /arg0/arg1/:param 22 | 23 | complexRouteDB = { 24 | "arg0": { 25 | "arg1": { 26 | "_action": new Action(callback) 27 | } 28 | } 29 | } 30 | ``` -------------------------------------------------------------------------------- /examples/simple_server.js: -------------------------------------------------------------------------------- 1 | //Require serve-me package 2 | var ServeMe = require('..'); 3 | 4 | //******************************* 5 | // HTTP SERVER 6 | // Only server the html & other files 7 | //******************************* 8 | var port = 3000; 9 | var options = { 10 | directory: "./examples/public", 11 | debug: false, 12 | log: true, 13 | secure: false 14 | }; 15 | 16 | //Start the Server 17 | var serveMe = ServeMe(options, port); 18 | serveMe.start(); 19 | 20 | //Route example 21 | serveMe.routes.get("/hello", function() { 22 | return "hello world!"; 23 | }); 24 | 25 | //Event example 26 | serveMe.on("http_request", function() { 27 | console.log("Hey! One more friend..."); 28 | }); -------------------------------------------------------------------------------- /lib/util.js: -------------------------------------------------------------------------------- 1 | 2 | //ES6 Temporal implementation 3 | Object.assign = function(target, object) { 4 | if (typeof object == 'undefined') { 5 | return object; 6 | } else if (typeof target == 'undefined') { 7 | return target; 8 | } 9 | var item, tItem; 10 | for (var prop in object) { 11 | item = object[prop]; 12 | if (typeof item == 'object' && item !== null) { 13 | tItem = target[prop]; 14 | if (typeof tItem == 'object' && tItem !== null) { 15 | target[prop] = Object.assign(tItem, item); 16 | } else { 17 | target[prop] = item; 18 | } 19 | } else if (item !== null) { 20 | target[prop] = item; 21 | } 22 | } 23 | return target; 24 | } 25 | -------------------------------------------------------------------------------- /lib/redirections.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /****************************** 4 | * ServeMe 5 | * Simple Web Server. 6 | ******************************/ 7 | 8 | 9 | /****************************** 10 | * Redirections Class 11 | * 12 | * @api public 13 | ******************************/ 14 | var Redirection = { 15 | get: function(url, method) { 16 | if (!url) return null; 17 | return this.all[method+"<#?>"+url]; 18 | }, 19 | 20 | add: function(url, method, redirectionUrl) { 21 | if (!url) return; 22 | this.all[method+"<#?>"+url] = redirectionUrl; 23 | }, 24 | 25 | contains: function(url, method) { 26 | return !!this.all[method+"<#?>"+url]; 27 | }, 28 | 29 | all: {}, 30 | }; 31 | 32 | module.exports = exports = Redirection; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "serve-me", 3 | "version": "0.8.2", 4 | "description": "Simple NodeJs web server API.", 5 | "license": "MIT", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/muit/serveMe" 9 | }, 10 | "homepage": "https://github.com/muit/serveMe", 11 | "scripts": { 12 | "test": "node_modules/mocha/bin/mocha" 13 | }, 14 | "keywords": [ 15 | "server", 16 | "http", 17 | "https", 18 | "api", 19 | "simple", 20 | "web" 21 | ], 22 | "author": "Muitxer (https://github.com/muit)", 23 | "devDependencies": { 24 | "mocha": "2.0.1", 25 | "request": "2.47.0", 26 | "expect.js": "^0.3.1" 27 | }, 28 | "dependencies": { 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /examples/clustering.js: -------------------------------------------------------------------------------- 1 | /************************* 2 | *Clustering Example 3 | *************************/ 4 | 5 | //Require serve-me package 6 | var ServeMe = require('..'); 7 | 8 | //******************************* 9 | // HTTP SERVER 10 | // Only server the html & other files 11 | //******************************* 12 | var port = 3000; 13 | var options = { 14 | directory: "./examples/public", 15 | debug: false, 16 | log: true, 17 | 18 | cluster: { 19 | //Enabling clustering 20 | enabled: true, 21 | 22 | cpus: "max", //(Optional, Default: "max") Number of cpus of the cluster 23 | auto_reload: true //(Optional, Default: true) Set it to true to reload cluster workers if died 24 | } 25 | }; 26 | 27 | //ATENTION: Cluster functionality stills in development. Its stability is limited. 28 | 29 | //Start the Server 30 | var serveMe = ServeMe(options, port); 31 | serveMe.start(); 32 | 33 | //Route example 34 | serveMe.routes.get("/hello", function() { 35 | return "hello world!"; 36 | }); -------------------------------------------------------------------------------- /lib/routes/route_data.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /** 4 | * Module exports. 5 | */ 6 | module.exports = exports = RouteData; 7 | 8 | function RouteData(routes, action) { 9 | this.routes = routes; 10 | this.action = action; 11 | } 12 | 13 | RouteData.prototype = { 14 | routes: null, 15 | action: null, 16 | 17 | require: function(check, fail) { 18 | this.action.addRequire(check, fail); 19 | }, 20 | 21 | 22 | //Direct handlers to create new routes 23 | get: function(url, callback) { 24 | return this.add(url, "GET", callback); 25 | }, 26 | 27 | set: function(url, callback) { 28 | return this.add(url, "SET", callback); 29 | }, 30 | 31 | post: function(url, callback) { 32 | return this.add(url, "POST", callback); 33 | }, 34 | 35 | update: function(url, callback) { 36 | return this.add(url, "UPDATE", callback); 37 | }, 38 | 39 | patch: function(url, callback) { 40 | return this.add(url, "PATCH", callback); 41 | }, 42 | 43 | delete: function(url, callback) { 44 | return this.add(url, "DELETE", callback); 45 | }, 46 | 47 | add: function(url, method, callback) { 48 | if (typeof callback == "string") { 49 | //Temporal disable redirections here 50 | //Redirection.add(url, method, callback); 51 | return this.routes; 52 | } else { 53 | return this.routes.add(url, method, callback); 54 | } 55 | }, 56 | 57 | }; -------------------------------------------------------------------------------- /lib/routes/action.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /** 4 | * Module exports. 5 | */ 6 | module.exports = exports = Action; 7 | 8 | function Action(cb) { 9 | if(!cb) return; 10 | this.callbacks = (cb instanceof Array)? cb : [cb]; 11 | } 12 | 13 | Action.prototype = { 14 | require: null, 15 | callbacks: [], 16 | fails: [], 17 | 18 | execute: function(req, res, next) { 19 | if (this.require && this.require(req, res, next) == false) { 20 | 21 | var len = this.fails.length; 22 | 23 | if (len == 1) { 24 | return this.fails[0](req, res, next); 25 | } 26 | 27 | /* Not yet implemented multiple fails 28 | for(var i = 0; i < len; i++) { 29 | this.fails[i](req, res, next); 30 | } 31 | */ 32 | return; 33 | } 34 | 35 | var len = this.callbacks.length; 36 | 37 | if (len == 1) { 38 | return this.callbacks[0](req, res, next); 39 | } 40 | 41 | /* Not yet implemented multiple routes 42 | for(var i = 0; i < len; i++) { 43 | this.callbacks[i](req, res, next); 44 | } 45 | */ 46 | return; 47 | }, 48 | 49 | addCallback: function(callback) { 50 | if (callback) 51 | this.callbacks.push(callback); 52 | }, 53 | 54 | addRequire: function(check, fail) { 55 | this.require = check; 56 | if(!fail) return; 57 | 58 | this.fails = (fail instanceof Array)? fail : [fail]; 59 | }, 60 | 61 | haveCallbacks: function() { 62 | return this.callbacks.length > 0; 63 | } 64 | } -------------------------------------------------------------------------------- /examples/clustering_with_sessions.js: -------------------------------------------------------------------------------- 1 | /************************* 2 | *Clustering Example 3 | *************************/ 4 | 5 | //Require serve-me package 6 | var ServeMe = require('..'); 7 | 8 | //******************************* 9 | // HTTP SERVER 10 | // Only server the html & other files 11 | //******************************* 12 | var port = 3000; 13 | var options = { 14 | directory: "./examples/public", 15 | debug: false, 16 | log: false, 17 | 18 | cluster: { 19 | //Enabling clustering 20 | enabled: true, 21 | 22 | cpus: "max", //(Optional, Default: "max") Number of cpus of the cluster 23 | auto_reload: true //(Optional, Default: true) Set it to true to reload cluster workers if died 24 | }, 25 | 26 | session: { 27 | enabled: true, 28 | //OPTIONAL: 29 | //Session url - Sessions will be created when any client visit this url. 30 | new_session_url: "/" 31 | } 32 | }; 33 | 34 | //ATENTION: Cluster functionality stills in development. Its stability is limited. 35 | 36 | //Start the Server 37 | var serveMe = ServeMe(options, port); 38 | serveMe.start(); 39 | 40 | //New session event 41 | serveMe.on("new_session", function() { 42 | console.log("Hey! One more friend..."); 43 | return true; 44 | }); 45 | 46 | serveMe.on("session", function() { 47 | console.log("Oh! You again."); 48 | }); 49 | 50 | serveMe.on("end_session", function() { 51 | console.log("Bye Bye My friend. ;("); 52 | }); -------------------------------------------------------------------------------- /lib/cluster_server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var cluster = require('cluster'); 4 | var os = require('os'); 5 | 6 | module.exports = exports = ClusterServer; 7 | 8 | var HttpServer = require('./http_server'); 9 | 10 | function ClusterServer(main, port, onStarted) { 11 | //Limit the cluster to the cpus amount 12 | if (main.config.cluster.cpus == "max" || main.config.cluster.cpus >= os.cpus().length) { 13 | main.config.cluster.cpus = os.cpus().length; 14 | } 15 | 16 | this.name = 'ServeMe.Cluster'; 17 | this.start(main, port, onStarted); 18 | }; 19 | 20 | ClusterServer.prototype.start = function(main, port, onStarted) { 21 | var self = this; 22 | 23 | if (cluster.isMaster) { 24 | for (var i = 0; i < main.config.cluster.cpus; i++) { 25 | cluster.fork(); 26 | } 27 | 28 | cluster.on('death', function(worker) { 29 | // Log process deaths. 30 | main.impLog(self.name + '> worker ' + worker.pid + ' died.'); 31 | 32 | // If autoRestart is true, spin up another to replace it 33 | if (main.config.cluster.auto_restart) { 34 | main.impLog(self.name + '> Restarting worker thread...'); 35 | cluster.fork(); 36 | } 37 | }); 38 | 39 | cluster.on('fork', function(worker) { 40 | main.impLog(self.name + '> starting worker thread #' + worker.id); 41 | }); 42 | 43 | //self.server = new HttpServer(main, port); 44 | } else { 45 | // Worker threads run the server 46 | self.server = new HttpServer(main, port, onStarted); 47 | } 48 | }; 49 | 50 | ClusterServer.prototype.stop = function() { 51 | for (var id in cluster.workers) { 52 | cluster.workers[id].kill(); 53 | } 54 | }; -------------------------------------------------------------------------------- /examples/routes.js: -------------------------------------------------------------------------------- 1 | //Require serve-me package 2 | var ServeMe = require('..'); 3 | 4 | //******************************* 5 | // HTTP SERVER 6 | // Only server the html & other files 7 | //******************************* 8 | var port = 3000; 9 | var options = { 10 | directory: "./examples/public", 11 | debug: false, 12 | log: true, 13 | }; 14 | 15 | //Start the server 16 | var server = ServeMe(options, port); 17 | 18 | //Lets count visits! 19 | var counter = 0; 20 | 21 | server.get("/", function() { 22 | counter += 1; 23 | return "" + counter; 24 | }); 25 | //Each time localhost:3000/ is visited the counter value is shown. 26 | 27 | //Same routes with different methods 28 | server.get("/user", function() { 29 | return "All the users are here :3"; 30 | }) 31 | .post("/user", function() { //Routes can be anidated. 32 | return "New user"; 33 | }); 34 | 35 | //You can use dynamic routes. 36 | server.get("/user/:name/profile/:id", function(req) { 37 | return "This is the profile of " + req.params.name + " with id " + req.params.id; 38 | }); 39 | 40 | 41 | //Answer with a different status 42 | server.get("/admin", function() { 43 | return { 44 | status: 403, 45 | body: "Cant access here!" 46 | }; 47 | }); 48 | 49 | //Need async on your routes? 50 | server.get("/chicken", function(req, next) { 51 | next({ 52 | status: 404, 53 | body: "There is no chicken", 54 | }); 55 | }); 56 | 57 | 58 | server.get("/index.html").require( 59 | function() { 60 | //Authenticated? 61 | return false; 62 | }, 63 | function(req, res){ 64 | return "Cant enter here!"; 65 | } 66 | ); 67 | 68 | //Create a fast redirection 69 | server.get("/lobby", "/lobby.html"); 70 | 71 | server.start(); -------------------------------------------------------------------------------- /examples/sessions.js: -------------------------------------------------------------------------------- 1 | //Require serve-me package 2 | var ServeMe = require('..'); 3 | 4 | //******************************* 5 | // HTTP SERVER 6 | // Only server the html & other files 7 | //******************************* 8 | var port = 3000; 9 | var options = { 10 | home: "index.html", 11 | directory: "./examples/public", 12 | debug: false, 13 | log: false, 14 | session: { 15 | enabled: true, 16 | //OPTIONAL: 17 | //Session url - Sessions will be created when any client visit this url. 18 | new_session_url: "/login", 19 | global_path: true 20 | } 21 | }; 22 | // Load ServeMe 23 | var serveMe = ServeMe(options, port); 24 | 25 | var username = "bear", 26 | password = "drowssap"; 27 | 28 | 29 | serveMe.on("new_session", function(evt) { 30 | var session = evt.session; 31 | // Will be called each new session petition reaches. 32 | serveMe.log("\nNew user..."); 33 | serveMe.log(session.data); 34 | // if user is correct & password too 35 | if (username == session.data.username && password == session.data.password) { 36 | serveMe.log(" " + session.data.username + " has logged in.\n"); 37 | return "Happy to see you " + session.data.username; // return true or a string to accept the new session 38 | //The string returned will be the response data. 39 | } 40 | // else return false (or nothing) 41 | serveMe.log(" Couldn't log in.\n"); 42 | return false; 43 | }); 44 | /**A session will be created visiting that url: 45 | * Name: 'bear' 46 | * Password: 'drowssap' 47 | * localhost:3000/session?user=bear&password=drowssap 48 | * 49 | * If you look then the console, you can see how 'bear' has logged in. 50 | */ 51 | 52 | serveMe.on("session", function(evt) { 53 | var session = evt.session; 54 | // Will be called each existing session enters. 55 | 56 | // If you recharge the webpage before, this message will be printed. 57 | serveMe.log(" " + session.data.username + " entered again!"); 58 | return "Hi again, " + session.data.username; 59 | }); 60 | 61 | // Start the server 62 | serveMe.start(port); -------------------------------------------------------------------------------- /docs/benchmarks.md: -------------------------------------------------------------------------------- 1 | # Benchmarks 2 | 3 | These are local benchmarks. Will show only the diference between Serve-Me modes, not the global performance of Serve-Me. 4 | 5 | ### Debug Disabled 6 | 7 | | Benchmark | Value | 8 | | :-------------------- |:----------------:| 9 | |Transactions | 55883 hits | 10 | |Availability | 100.00 % | 11 | |Elapsed time | 89.36 secs | 12 | |Data transferred | 955.10 MB | 13 | |Response time | 0.02 secs | 14 | |Transaction rate | 625.35 trans/sec | 15 | |Throughput | 10.69 MB/sec | 16 | |Concurrency | 10.93 | 17 | |Successful transactions| 55887 | 18 | |Failed transactions | 0 | 19 | |Longest transaction | 0.06 | 20 | |Shortest transaction | 0.00 | 21 | 22 | 23 | 24 | ### Debug Enabled 25 | 26 | | Benchmark | Value | 27 | | :-------------------- |:----------------:| 28 | |Transactions | 48285 hits | 29 | |Availability | 100.00 % | 30 | |Elapsed time | 89.40 secs | 31 | |Data transferred | 825.22 MB | 32 | |Response time | 0.02 secs | 33 | |Transaction rate | 540.09 trans/sec | 34 | |Throughput | 10.89 MB/sec | 35 | |Concurrency | 10.89 | 36 | |Successful transactions| 48287 | 37 | |Failed transactions | 0 | 38 | |Longest transaction | 0.06 | 39 | |Shortest transaction | 0.00 | 40 | 41 | 42 | ### Cluster(beta) Enabled & Debug Disabled 43 | 44 | ATENTION: This benchmark is using cluster in beta version (0.4.3). Results may change. 45 | 46 | | Benchmark | Value | 47 | | :-------------------- |:----------------:| 48 | |Transactions | 60744 hits | 49 | |Availability | 100.00 % | 50 | |Elapsed time | 89.37 secs | 51 | |Data transferred | 1038.16 MB | 52 | |Response time | 0.02 secs | 53 | |Transaction rate | 679.68 trans/sec | 54 | |Throughput | 11.62 MB/sec | 55 | |Concurrency | 12.51 | 56 | |Successful transactions| 60747 | 57 | |Failed transactions | 0 | 58 | |Longest transaction | 0.14 | 59 | |Shortest transaction | 0.00 | -------------------------------------------------------------------------------- /lib/config.js: -------------------------------------------------------------------------------- 1 | module.exports = exports = Config; 2 | 3 | function Config(options) { 4 | if (!(this instanceof Config)) { 5 | return Config.instance = new Config(options); 6 | } 7 | 8 | options = options || {}; 9 | for (p in options) { 10 | this[p] = options[p]; 11 | } 12 | 13 | this.hostname = process.env[this.hostname_env_var] 14 | 15 | //Default Values: 16 | this.log = (options.log === undefined) ? true : options.log; 17 | this.debug = options.debug || false; 18 | this.home = options.home || "index.html"; 19 | this.directory = generate_public_path(options.directory || "./public"); 20 | this.favicon = options.favicon || "/favicon.ico"; 21 | 22 | 23 | //Https defaults 24 | this.secure = options.secure || false; 25 | this.key = options.key || "./keys/key.pem"; 26 | this.cert = options.cert || "./keys/cert.pem"; 27 | this.error = options.error || { 28 | 404: "404.html", 29 | 500: "500.html", 30 | }; 31 | this.cluster = options.cluster || { 32 | enabled: false, 33 | cpus: 1 34 | }; 35 | 36 | 37 | //Session defaults 38 | this.session = options.session || { 39 | enabled: false, 40 | persistence: false, 41 | lifetime: 7200, 42 | new_session_url: "/session", 43 | global_path: false 44 | }; 45 | this.session.enabled = this.session.enabled || false; 46 | this.session.persistence = this.session.persistence || false; 47 | this.session.lifetime = this.session.lifetime || 7200; 48 | this.session.new_session_url = this.session.new_session_url || "/session"; 49 | this.session.global_path = this.session.global_path || false; 50 | 51 | 52 | //Cluster defaults 53 | this.cluster = options.cluster || { 54 | enabled: false, 55 | cpus: "max", 56 | auto_restart: true 57 | }; 58 | this.cluster.enabled = this.cluster.enabled || false; 59 | this.cluster.cpus = this.cluster.cpus || "max"; 60 | this.cluster.auto_restart = this.cluster.auto_restart || true; 61 | } 62 | 63 | /** 64 | * @api private 65 | */ 66 | function generate_public_path(relative_path) { 67 | if (typeof relative_path === "string") { 68 | if (relative_path[0] === ".") { 69 | return [process.cwd().replace("\\", "/"), relative_path.slice(1)].join(''); 70 | } 71 | } 72 | return relative_path; 73 | } -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module dependencies. 3 | */ 4 | var ClusterServer = require("./cluster_server"), 5 | HttpServer = require('./http_server'), 6 | Routes = require("./routes"), 7 | Redirection = require("./redirections"), 8 | Sessions = require("./session"), 9 | Config = require("./config"), 10 | Package = require('../package.json'); 11 | 12 | /** 13 | * Module exports. 14 | */ 15 | module.exports = ServeMe; 16 | 17 | /** 18 | * Server constructor. 19 | * 20 | * @param {Number} port 21 | * @param {Object} options 22 | * @api public 23 | */ 24 | function ServeMe(options, port) { 25 | if (!(this instanceof ServeMe)) 26 | return ServeMe.instance = new ServeMe(options, port); 27 | 28 | this.config = (options instanceof Config) ? options : new Config(options); 29 | Sessions(this); 30 | 31 | if (Routes) { 32 | this.routes = new Routes(this); 33 | } 34 | this.Redirection = Redirection; 35 | 36 | this.port = port; 37 | var self = this; 38 | 39 | this.version = Package.version; 40 | } 41 | 42 | ServeMe.prototype = { 43 | server: null, 44 | /** 45 | * Starts the server 46 | * @param {Number} port [http server port] 47 | * @return {Object} [server object] 48 | */ 49 | start: function(port, onStarted) { 50 | //If port is the callback 51 | if(typeof port == "function") { 52 | onStarted = port; 53 | port = null; 54 | } 55 | 56 | if (this.config.cluster.enabled) { 57 | return this.server = new ClusterServer(this, port || this.port, onStarted); 58 | } else { 59 | return this.server = new HttpServer(this, port || this.port, onStarted); 60 | } 61 | }, 62 | 63 | /** 64 | * Resets the server 65 | */ 66 | reset: ServeMe.reset = function() { 67 | this.stop(); 68 | this.start(this.port); 69 | Sessions(this); 70 | }, 71 | 72 | /** 73 | * Stops the server 74 | */ 75 | stop: function() { 76 | if (this.server) { 77 | this.server.stop(); 78 | } 79 | 80 | if (this.routes) { 81 | //this.routes.reset("all"); 82 | } 83 | 84 | Sessions.reset(); 85 | }, 86 | 87 | //Routes 88 | routes: null, 89 | Redirection: null, 90 | 91 | get: function(url, callback) { 92 | return this.add(url, "GET", callback); 93 | }, 94 | 95 | set: function(url, callback) { 96 | return this.add(url, "SET", callback); 97 | }, 98 | 99 | post: function(url, callback) { 100 | return this.add(url, "POST", callback); 101 | }, 102 | 103 | update: function(url, callback) { 104 | return this.add(url, "UPDATE", callback); 105 | }, 106 | 107 | patch: function(url, callback) { 108 | return this.add(url, "PATCH", callback); 109 | }, 110 | 111 | delete: function(url, callback) { 112 | return this.add(url, "DELETE", callback); 113 | }, 114 | 115 | add: function(url, method, callback) { 116 | if (typeof callback == "string") { 117 | Redirection.add(url, method, callback); 118 | return this; 119 | } else { 120 | return this.routes.add(url, method, callback); 121 | } 122 | }, 123 | 124 | 125 | //Session 126 | Session: ServeMe.Session = Sessions, 127 | 128 | /** 129 | * On Event 130 | * @param {String} identifier [name of the event] 131 | * @param {Function} callback [method called when event is active] 132 | */ 133 | on: function(identifier, callback) { 134 | this.events[identifier] = callback; 135 | }, 136 | 137 | /** 138 | * Call Event 139 | * @param {String} identifier [name of the event] 140 | */ 141 | call: function(identifier, data) { 142 | var event = this.events[identifier]; 143 | if (typeof event == "function") { 144 | return event(data); 145 | } 146 | return undefined; 147 | }, 148 | 149 | events: {}, 150 | 151 | impLog: function(msg, enter) { 152 | if(msg.replace(" ", "").length > 0) 153 | msg = ">> "+msg; 154 | if(enter) 155 | msg = "\n"+msg; 156 | 157 | console.log(msg); 158 | }, 159 | 160 | log: function(msg, enter) { 161 | if (this.config && this.config.log !== false) 162 | this.impLog(msg, enter); 163 | } 164 | }; -------------------------------------------------------------------------------- /lib/session.js: -------------------------------------------------------------------------------- 1 | var urlParser = require('url'); 2 | 3 | /** 4 | * Module exports. 5 | */ 6 | module.exports = exports = Session; 7 | 8 | var ServeMe; 9 | 10 | function Session(arg, opts) { 11 | if (!(this instanceof Session)) { 12 | ServeMe = arg; 13 | 14 | if (ServeMe.config.session.enabled) { 15 | if (ServeMe.config.session.lifetime) { 16 | ServeMe.config.session.persistence = ServeMe.config.session.persistence ? ServeMe.config.session.persistence : true; 17 | } else { 18 | ServeMe.config.session.persistent = false; 19 | ServeMe.config.session.lifetime = 3600; 20 | } 21 | } 22 | } else { 23 | if (!ServeMe) { 24 | throw new SessionNotLoaded("Session must be loaded."); 25 | } 26 | if (typeof opts != "object") { 27 | throw new IncorrectArgument("Session options cant be a " + typeof opts + "."); 28 | } 29 | if (typeof arg != "string") { 30 | throw new IncorrectArgument("Session id cant be a " + typeof arg + "."); 31 | } 32 | 33 | this.id = arg; 34 | this.data = opts.data || {}; 35 | this.path = opts.path; 36 | if (opts.domain != "localhost") { 37 | this.domain = opts.domain; 38 | } 39 | } 40 | } 41 | 42 | Session._sessions = {}; 43 | Session.timeout = undefined; 44 | 45 | Session.lookupOrCreate = function(url, request) { 46 | if (!ServeMe.config.session.enabled) { 47 | return; 48 | } 49 | 50 | var id = Session.getIdFromRequest(request, {}), 51 | session, 52 | data; 53 | 54 | if (session = Session._sessions[id]) { 55 | data = ServeMe.call("session", { 56 | session: session 57 | }); 58 | } else if (url.pathname == ServeMe.config.session.new_session_url) { 59 | session = new Session(id, { 60 | path: ServeMe.config.session.global_path ? undefined : url.pathname, 61 | data: url.query, 62 | domain: request.domain 63 | }); 64 | 65 | var result = ServeMe.call("new_session", { 66 | session: session, 67 | request: request 68 | }); 69 | 70 | if (result !== false && result !== undefined) { 71 | Session._sessions[id] = session; 72 | data = result; 73 | } else { 74 | session = undefined; 75 | } 76 | } 77 | 78 | if (!this.timeout) { 79 | this.timeout = setTimeout(Session.cleanUp, 60000); 80 | } 81 | if (session) { 82 | session.expiration = (+new Date()) + ServeMe.config.session.lifetime * 1000; 83 | } 84 | 85 | return { 86 | session: session, 87 | data: data 88 | }; 89 | }; 90 | 91 | Session.lookup = function(url, request) { 92 | if (!ServeMe.config.session.enabled) { 93 | return; 94 | } 95 | 96 | var id = Session.getIdFromRequest(request, {}), 97 | session; 98 | 99 | if (session = Session._sessions[id]) { 100 | ServeMe.call("session", { 101 | session: session, 102 | request: request 103 | }); 104 | } 105 | 106 | if (!this.timeout) { 107 | this.timeout = setTimeout(Session.cleanUp, 60000); 108 | } 109 | if (session) { 110 | session.expiration = (+new Date()) + ServeMe.config.session.lifetime * 1000; 111 | } 112 | 113 | return session; 114 | }; 115 | 116 | Session.cleanUp = function() { 117 | ServeMe.log("ServeMe: Cleaning Sessions.") 118 | var now = +new Date(); 119 | var next = Infinity; 120 | this.timeout = null; 121 | 122 | for (var id in Session._sessions) { 123 | if (hasOwnProp(Session._sessions, id)) { 124 | var session = Session._sessions[id]; 125 | if (session.expiration < now) { 126 | ServeMe.call("end_session", session); 127 | delete session; 128 | } else 129 | next = (next < session.expiration) ? next : session.expiration; 130 | } 131 | } 132 | 133 | if (next < Infinity) 134 | this.timeout = setTimeout(Session.cleanUp, next - (+new Date()) + 1000); 135 | }; 136 | 137 | Session.reset = function() { 138 | Session._sessions = {}; 139 | ServeMe = undefined; 140 | }; 141 | 142 | Session.getIdFromRequest = function(req, opts) { 143 | if (req.headers.cookie) { 144 | var m = /SID=([^ ,;]*)/.exec(req.headers.cookie); 145 | if (m && hasOwnProp(this._sessions, m[1])) { 146 | return m[1]; 147 | } 148 | } 149 | 150 | if (opts.sessionID) { 151 | return opts.sessionID; 152 | } 153 | return randomString(64); 154 | }; 155 | 156 | Session.prototype.getSetCookieHeaderValue = function() { 157 | var parts = ['SID=' + this.id]; 158 | if (this.path) { 159 | parts.push('path=' + this.path); 160 | } 161 | 162 | if (this.domain) { 163 | parts.push('domain=' + this.domain); 164 | } 165 | 166 | if (ServeMe.config.session.persistence ? ServeMe.config.session.persistence : true) { 167 | parts.push('expires=' + msUTCString(this.expiration)); 168 | } 169 | 170 | return parts.join('; '); 171 | }; 172 | 173 | Session.prototype.destroy = function() { 174 | delete Session._sessions[this.id]; 175 | }; 176 | 177 | 178 | 179 | function msUTCString(ms) { 180 | return (new Date(ms)).toUTCString(); 181 | } 182 | 183 | function hasOwnProp(o, p) { 184 | return Object.prototype.hasOwnProperty.call(o, p); 185 | } 186 | 187 | function randomString(bits) { 188 | var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', 189 | rand, 190 | i, 191 | ret = ''; 192 | 193 | while (bits > 0) { 194 | rand = Math.floor(Math.random() * 0x100000000); 195 | for (i = 26; i > 0 && bits > 0; i -= 6, bits -= 6) 196 | ret += chars[0x3F & rand >>> i]; 197 | } 198 | return ret; 199 | } 200 | 201 | function IncorrectArgument(message) { 202 | this.name = "IncorrectArgument"; 203 | this.message = (message || ""); 204 | } 205 | IncorrectArgument.prototype = Error.prototype; 206 | 207 | function SessionNotLoaded(message) { 208 | this.name = "SessionNotLoaded"; 209 | this.message = (message || ""); 210 | } 211 | SessionNotLoaded.prototype = Error.prototype; -------------------------------------------------------------------------------- /lib/routes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module exports. 3 | */ 4 | module.exports = exports = Routes; 5 | 6 | require("./util"); 7 | var Action = require("./routes/action.js"); 8 | var RouteData = require("./routes/route_data.js") 9 | 10 | function Routes(core) { 11 | this.core = core; 12 | } 13 | 14 | Routes.prototype = { 15 | core: null, 16 | simpleRouteDB: {}, 17 | complexRouteDB: {}, 18 | 19 | add: function(url, method, callback) { 20 | if (typeof url != "string") { 21 | throw new IncorrectArgumentType("Routes.add: Url must be string, not " + typeof url + "."); 22 | } 23 | if (typeof method === "function") { 24 | throw new IncorrectArgumentType("Routes.add: add(url, callback) is decreaped. Use set, get, update, post or delete instead."); 25 | } else if (typeof method != "string") { 26 | throw new IncorrectArgumentType("Routes.add: Method must be string, not " + typeof method + "."); 27 | } 28 | 29 | var action; 30 | 31 | if (urlHaveParams(url)) { 32 | action = this.addComplex(url, method, callback); 33 | } else { 34 | this.simpleRouteDB[url] = this.simpleRouteDB[url] || { 35 | _action: {} 36 | }; 37 | action = new Action(callback); 38 | this.simpleRouteDB[url]._action[method] = action; 39 | } 40 | 41 | return new RouteData(this, action); 42 | }, 43 | 44 | addComplex: function(url, method, callback) { 45 | var segs = url.split("/"); 46 | segs = segs.reverse(); 47 | 48 | var hash = { 49 | _action: {}, 50 | }; 51 | var action = hash._action[method] = new Action(callback); 52 | 53 | var seg, next; 54 | for (var i = 0; i < segs.length; i++) { 55 | seg = segs[i]; 56 | if (seg === "") { 57 | continue; 58 | } 59 | 60 | next = {}; 61 | if (seg.indexOf(":") === 0) { 62 | seg = seg.replace(":", ""); 63 | 64 | if (!next.param) { 65 | next.param = {}; 66 | } 67 | next.param = hash; 68 | next.param.paramId = seg; 69 | } else { 70 | next[seg] = hash; 71 | } 72 | 73 | //Next state assign 74 | hash = next; 75 | } 76 | this.complexRouteDB = Object.assign(this.complexRouteDB, hash); 77 | 78 | return action; 79 | }, 80 | 81 | get: function(url, callback) { 82 | return this.add(url, "GET", callback); 83 | }, 84 | set: function(url, callback) { 85 | return this.add(url, "SET", callback); 86 | }, 87 | post: function(url, callback) { 88 | return this.add(url, "POST", callback); 89 | }, 90 | update: function(url, callback) { 91 | return this.add(url, "UPDATE", callback); 92 | }, 93 | patch: function(url, callback) { 94 | return this.add(url, "PATCH", callback); 95 | }, 96 | delete: function(url, callback) { 97 | return this.add(url, "DELETE", callback); 98 | }, 99 | 100 | take: function(method, url, params) { 101 | if (typeof url != "string") { 102 | throw new IncorrectArgumentType("Routes.take: Url must be string, not " + typeof url + "."); 103 | } 104 | 105 | var route = this.simpleRouteDB[url]; 106 | if (route) { 107 | var action = route._action[method]; 108 | if (action) { 109 | action.params = params; 110 | return action; 111 | } 112 | } 113 | 114 | return this.takeComplex(method, url, params); 115 | }, 116 | 117 | takeComplex: function(method, url, params) { 118 | var action = null; 119 | params = params || {}; 120 | 121 | //Check for the perfect route 122 | var segs = url.split("/"); 123 | var seg; 124 | var hash = this.complexRouteDB; 125 | for (var i = 0, len = segs.length; i < len; i++) { 126 | seg = segs[i]; 127 | 128 | if (seg === "") { 129 | continue; 130 | } 131 | 132 | if (seg == "_action" || seg == "paramId") { 133 | return route; 134 | } 135 | 136 | if (hash[seg] === undefined) { 137 | //Detect parameters 138 | if (hash.param) { 139 | action = hash.param._action || action; 140 | params[hash.param.paramId] = seg; 141 | 142 | hash = hash.param; 143 | } else { 144 | return action; 145 | } 146 | } else { 147 | hash = hash[seg]; 148 | } 149 | } 150 | 151 | if (hash._action) { 152 | //return a route 153 | action = hash._action[method]; 154 | } 155 | //return the possible params 156 | if (action) { 157 | action.params = params; 158 | } 159 | return action; 160 | }, 161 | 162 | serve: function(url, request, response) { 163 | var action = this.take(request.method, url.pathname, url.query); 164 | 165 | if (action) { 166 | request.params = action.params; 167 | var data = action.execute(request, response, function(data) { 168 | next(response, data); 169 | }); 170 | next(response, data); 171 | 172 | return action.haveCallbacks(); 173 | } 174 | return false; 175 | }, 176 | 177 | reset: function() { 178 | delete this.complexRouteDB; 179 | this.complexRouteDB = {}; 180 | delete this.simpleRouteDB; 181 | this.simpleRouteDB = {}; 182 | } 183 | }; 184 | 185 | function next(res, data) { 186 | if (data == undefined) return; 187 | 188 | var status = data.status || 200; 189 | var body = data.body || JSON.stringify(data.json) || ""; 190 | 191 | if (typeof data == "string") { 192 | body = data; 193 | } 194 | 195 | res.writeHead(status, { 196 | 'Content-Length': body.length, 197 | 'Content-Type': data.body || !data.json? 'text/plain' : 'application/json' 198 | }); 199 | res.end(body); 200 | } 201 | 202 | function IncorrectArgumentType(message) { 203 | this.name = "IncorrectArgumentType"; 204 | this.message = message || ""; 205 | } 206 | 207 | IncorrectArgumentType.prototype = Error.prototype; 208 | 209 | function urlHaveParams(url) { 210 | return url.contains("/:"); 211 | } -------------------------------------------------------------------------------- /lib/mime.js: -------------------------------------------------------------------------------- 1 | exports.get = function(extension) { 2 | return mime[extension] || "text/plain"; 3 | }; 4 | 5 | var mime = { 6 | //Text Files 7 | 'css': 'text/css', 8 | '323': 'text/h323', 9 | 'htm': 'text/html', 10 | 'html': 'text/html', 11 | 'stm': 'text/html', 12 | 'uls': 'text/iuls', 13 | 'bas': 'text/plain', 14 | 'c': 'text/plain', 15 | 'h': 'text/plain', 16 | 'txt': 'text/plain', 17 | 'rtx': 'text/richtext', 18 | 'sct': 'text/scriptlet', 19 | 'tsv': 'text/tab-separated-values', 20 | 'htt': 'text/webviewhtml', 21 | 'htc': 'text/x-component', 22 | 'etx': 'text/x-setext', 23 | 'vcf': 'text/x-vcard', 24 | 25 | //'application Files 26 | 'otf': 'application/octet-stream', 27 | 'ttf': 'application/octet-stream', 28 | 'eot': 'application/vnd.ms-fontobject', 29 | 'evy': 'application/envoy', 30 | 'fif': 'application/fractals', 31 | 'spl': 'application/futuresplash', 32 | 'hta': 'application/hta', 33 | 'acx': 'application/internet-property-stream', 34 | 'hqx': 'application/mac-binhex40', 35 | 'doc': 'application/msword', 36 | 'dot': 'application/msword', 37 | '*': 'application/octet-stream', 38 | 'bin': 'application/octet-stream', 39 | 'class': 'application/octet-stream', 40 | 'dms': 'application/octet-stream', 41 | 'exe': 'application/octet-stream', 42 | 'lha': 'application/octet-stream', 43 | 'lzh': 'application/octet-stream', 44 | 'oda': 'application/oda', 45 | 'axs': 'application/olescript', 46 | 'pdf': 'application/pdf', 47 | 'prf': 'application/pics-rules', 48 | 'p10': 'application/pkcs10', 49 | 'crl': 'application/pkix-crl', 50 | 'ai': 'application/postscript', 51 | 'eps': 'application/postscript', 52 | 'ps': 'application/postscript', 53 | 'rtf': 'application/rtf', 54 | 'setpay':'application/set-payment-initiation', 55 | 'setreg':'application/set-registration-initiation', 56 | 'xla': 'application/vnd.ms-excel', 57 | 'xlc': 'application/vnd.ms-excel', 58 | 'xlm': 'application/vnd.ms-excel', 59 | 'xls': 'application/vnd.ms-excel', 60 | 'xlt': 'application/vnd.ms-excel', 61 | 'xlw': 'application/vnd.ms-excel', 62 | 'msg': 'application/vnd.ms-outlook', 63 | 'sst': 'application/vnd.ms-pkicertstore', 64 | 'cat': 'application/vnd.ms-pkiseccat', 65 | 'stl': 'application/vnd.ms-pkistl', 66 | 'pot': 'application/vnd.ms-powerpoint', 67 | 'pps': 'application/vnd.ms-powerpoint', 68 | 'ppt': 'application/vnd.ms-powerpoint', 69 | 'mpp': 'application/vnd.ms-project', 70 | 'wcm': 'application/vnd.ms-works', 71 | 'wdb': 'application/vnd.ms-works', 72 | 'wks': 'application/vnd.ms-works', 73 | 'wps': 'application/vnd.ms-works', 74 | 'hlp': 'application/winhlp', 75 | 'bcpio': 'application/x-bcpio', 76 | 'cdf': 'application/x-cdf', 77 | 'z': 'application/x-compress', 78 | 'tgz': 'application/x-compressed', 79 | 'cpio': 'application/x-cpio', 80 | 'csh': 'application/x-csh', 81 | 'dcr': 'application/x-director', 82 | 'dir': 'application/x-director', 83 | 'dxr': 'application/x-director', 84 | 'dvi': 'application/x-dvi', 85 | 'gtar': 'application/x-gtar', 86 | 'gz': 'application/x-gzip', 87 | 'hdf': 'application/x-hdf', 88 | 'ins': 'application/x-internet-signup', 89 | 'isp': 'application/x-internet-signup', 90 | 'iii': 'application/x-iphone', 91 | 'js': 'application/x-javascript', 92 | 'mjs': 'application/x-javascript', 93 | 'latex': 'application/x-latex', 94 | 'mdb': 'application/x-msaccess', 95 | 'crd': 'application/x-mscardfile', 96 | 'clp': 'application/x-msclip', 97 | 'dll': 'application/x-msdownload', 98 | 'm13': 'application/x-msmediaview', 99 | 'm14': 'application/x-msmediaview', 100 | 'mvb': 'application/x-msmediaview', 101 | 'wmf': 'application/x-msmetafile', 102 | 'mny': 'application/x-msmoney', 103 | 'pub': 'application/x-mspublisher', 104 | 'scd': 'application/x-msschedule', 105 | 'trm': 'application/x-msterminal', 106 | 'wri': 'application/x-mswrite', 107 | 'ncdf': 'application/x-netcdf', 108 | 'nc': 'application/x-netcdf', 109 | 'pma': 'application/x-perfmon', 110 | 'pmc': 'application/x-perfmon', 111 | 'pml': 'application/x-perfmon', 112 | 'pmr': 'application/x-perfmon', 113 | 'pmw': 'application/x-perfmon', 114 | 'p12': 'application/x-pkcs12', 115 | 'pfx': 'application/x-pkcs12', 116 | 'p7b': 'application/x-pkcs7-certificates', 117 | 'spc': 'application/x-pkcs7-certificates', 118 | 'p7r': 'application/x-pkcs7-certreqresp', 119 | 'p7c': 'application/x-pkcs7-mime', 120 | 'p7m': 'application/x-pkcs7-mime', 121 | 'p7s': 'application/x-pkcs7-signature', 122 | 'sh': 'application/x-sh', 123 | 'shar': 'application/x-shar', 124 | 'swf': 'application/x-shockwave-flash', 125 | 'sit': 'application/x-stuffit', 126 | 'sv4cpio':'application/x-sv4cpio', 127 | 'sv4crc':'application/x-sv4crc', 128 | 'tar': 'application/x-tar', 129 | 'tcl': 'application/x-tcl', 130 | 'tex': 'application/x-tex', 131 | 'texi': 'application/x-texinfo', 132 | 'texinfo':'application/x-texinfo', 133 | 'roff': 'application/x-troff', 134 | 't': 'application/x-troff', 135 | 'tr': 'application/x-troff', 136 | 'man': 'application/x-troff-man', 137 | 'me': 'application/x-troff-me', 138 | 'ms': 'application/x-troff-ms', 139 | 'ustar': 'application/x-ustar', 140 | 'src': 'application/x-wais-source', 141 | 'cer': 'application/x-x509-ca-cert', 142 | 'crt': 'application/x-x509-ca-cert', 143 | 'der': 'application/x-x509-ca-cert', 144 | 'pko': 'application/ynd.ms-pkipko', 145 | 'zip': 'application/zip', 146 | 147 | //Image Files 148 | 'bmp': 'image/bmp', 149 | 'cod': 'image/cis-cod', 150 | 'gif': 'image/gif', 151 | 'ief': 'image/ief', 152 | 'jpe': 'image/jpeg', 153 | 'jpeg': 'image/jpeg', 154 | 'jpg': 'image/jpeg', 155 | 'jfif': 'image/pipeg', 156 | 'svg': 'image/svg+xml', 157 | 'tif': 'image/tiff', 158 | 'tiff': 'image/tiff', 159 | 'ras': 'image/x-cmu-raster', 160 | 'cmx': 'image/x-cmx', 161 | 'ico': 'image/x-icon', 162 | 'pnm': 'image/x-portable-anymap', 163 | 'pbm': 'image/x-portable-bitmap', 164 | 'pgm': 'image/x-portable-graymap', 165 | 'ppm': 'image/x-portable-pixmap', 166 | 'rgb': 'image/x-rgb', 167 | 'xbm': 'image/x-xbitmap', 168 | 'xpm': 'image/x-xpixmap', 169 | 'xwd': 'image/x-xwindowdump', 170 | }; 171 | -------------------------------------------------------------------------------- /lib/http_server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /****************************** 4 | * ServeMe 5 | * Simple Web Server. 6 | ******************************/ 7 | 8 | var urlParser = require('url'); 9 | var fs = require('fs'); 10 | var mime = require("./mime.js"); 11 | var http = require('http'); 12 | var https = require('https'); 13 | if (typeof Utyl == "undefined") require("./utyl/utyl.js"); 14 | 15 | var ServeMe; 16 | var config; 17 | 18 | module.exports = exports = HttpServer; 19 | /****************************** 20 | * Http Server Class 21 | * 22 | * @api public 23 | ******************************/ 24 | function HttpServer(main, port, onStarted) { 25 | ServeMe = main; 26 | config = ServeMe.config; 27 | 28 | var self = this; 29 | 30 | if (!port) { 31 | //Default port 32 | port = 8080; 33 | ServeMe.log("Need a port. Using " + port + " by default."); 34 | } 35 | 36 | if (!config.secure) { 37 | this.server = http.createServer(function(request, response) { 38 | self.serve(self, request, response); 39 | }); 40 | } else { 41 | if (!config.key) { 42 | throw new Error("ServeMe: SSH Key path is missing."); 43 | } 44 | if (!config.cert) { 45 | throw new Error("ServeMe: SSH Certificate path is missing."); 46 | } 47 | 48 | var ssl = { 49 | key: fs.readFileSync(config.key), 50 | cert: fs.readFileSync(config.cert), 51 | }; 52 | this.server = https.createServer(ssl, function(request, response) { 53 | self.serve(self, request, response); 54 | }); 55 | } 56 | 57 | this.server.listen(port, config.hostname, function() { 58 | ServeMe.impLog('ServeMe v' + ServeMe.version + "\n----------"); 59 | ServeMe.impLog('Listening at port: ' + port); 60 | ServeMe.impLog('Secure mode(https) ' + (config.secure ? "enabled" : "disabled")); 61 | ServeMe.impLog('Debug mode ' + (config.debug ? "enabled" : "disabled")); 62 | 63 | if (config.session.enabled) { 64 | ServeMe.impLog('Sessions ' + config.session.enabled ? "enabled" : "disabled"); 65 | } 66 | 67 | //Start Events 68 | if (typeof onStarted == "function") { 69 | onStarted(); 70 | } 71 | ServeMe.call("listening"); 72 | }); 73 | 74 | this.server.on('error', function(e) { 75 | if (!ServeMe.call("error", e)) { 76 | throw new Error("An error ocurred in the server: " + e); 77 | } 78 | }); 79 | } 80 | 81 | 82 | HttpServer.prototype = { 83 | /****************************** 84 | * Cache Storage 85 | ******************************/ 86 | cache: {}, 87 | 88 | /****************************** 89 | * Serve files or code 90 | * @api private 91 | ******************************/ 92 | serve: function(self, request, response) { 93 | ServeMe.call("http_request", { 94 | request: request, 95 | response: response 96 | }); 97 | 98 | var url = urlParser.parse(request.url, true); 99 | var client = request.headers['X-Forwarded-For'] || request.connection.remoteAddress; 100 | 101 | ServeMe.log("Serving (" + request.method + ")" + url.pathname + " to " + client, true); 102 | this.sessionBuffer = undefined; 103 | 104 | if (config.session.enabled === true) { 105 | this.sessionBuffer = ServeMe.Session.lookupOrCreate(url, request); 106 | } 107 | 108 | //Route detection 109 | if (self.serveRoute(url, request, response)) { 110 | ServeMe.log(" Served route."); 111 | return; 112 | } 113 | 114 | if (url.pathname.endsWith("/")) { 115 | //Serve a direction 116 | url.pathname += "index.html"; 117 | self.serveFile(200, url, request, response); 118 | } else if (url.pathname.contains('..')) { 119 | //Restrict path 120 | self.serveError(404, url, request, response); 121 | } else { 122 | self.serveFile(200, url, request, response); 123 | } 124 | }, 125 | 126 | /****************************** 127 | * Serve index.html 128 | * @api private 129 | ******************************/ 130 | serveHome: function(self, url, request, response) { 131 | url.pathname = '/' + config.home; 132 | self.serveFile(200, url, request, response); 133 | }, 134 | 135 | /****************************** 136 | * Serve js or css 137 | * @api private 138 | ******************************/ 139 | serveFile: function(status, url, request, response) { 140 | var self = this; 141 | var path = config.directory + url.pathname.replace(/%20/g, ' '); 142 | 143 | if (config.debug || this.cache[path] === undefined) { 144 | this.readFile(path, function(err, data) { 145 | if (err) { 146 | ServeMe.log(" Couldn't serve file. 404."); 147 | self.serveError(404, url, request, response); 148 | return; 149 | } 150 | if (!config.debug) { 151 | self.cache[path] = data; 152 | } 153 | ServeMe.log(" Served file from disk."); 154 | writeResponse(status, url, data, request, response); 155 | }); 156 | } else { 157 | ServeMe.log(" Served file from cache."); 158 | writeResponse(status, url, this.cache[path], request, response); 159 | } 160 | }, 161 | 162 | /** 163 | * Will be called when an error appears 164 | * @api private 165 | */ 166 | serveError: function(status, url, request, response) { 167 | if (this.sessionBuffer && this.sessionBuffer.session && this.sessionBuffer.data) { 168 | response.writeHead(200, { 169 | 'Content-Length': this.sessionBuffer.data.length, 170 | 'Content-Type': "text/plain", 171 | 'Set-Cookie': this.sessionBuffer.session.getSetCookieHeaderValue() 172 | }); 173 | response.end(this.sessionBuffer.data); 174 | ServeMe.log(" Served Session response."); 175 | return; 176 | } 177 | 178 | if (!config.error[status]) { 179 | ServeMe.log("The error page " + status + " is not defined.\nYou must set 'options.error[" + status + "]' to something!"); 180 | return 181 | //throw new Error("The error page " + status + " is not defined.\nYou must set 'options.error[" + status + "]' to something!"); 182 | } 183 | 184 | var self = this; 185 | var file = config.error[status]; 186 | var path = config.directory + '/error/' + file; 187 | 188 | if (config.debug || this.cache[path] === undefined) { 189 | this.readFile(path, function(err, data) { 190 | if (err) { 191 | writeResponse(500, url, "ERROR: 500 - Internal server error.", request, response, ""); 192 | ServeMe.log(status + " error page may not exist.\n Could not found it on: " + path); 193 | return; 194 | //throw new Error(status + " error page may not exist.\nSpecified file path: " + path + "\n"); 195 | } 196 | 197 | if (!config.debug) 198 | self.cache[path] = data; 199 | 200 | writeResponse(status, url, data, request, response, file); 201 | }); 202 | } else 203 | writeResponse(status, url, this.cache[path], request, response, file); 204 | }, 205 | 206 | serveRoute: function(url, request, response) { 207 | var redirectionUrl = ServeMe.Redirection.get(url.pathname, request.method); 208 | if (redirectionUrl) { 209 | url.pathname = redirectionUrl; 210 | this.serveFile(200, url, request, response); 211 | 212 | } else if (ServeMe.routes) { 213 | //Avoid route crash 214 | try { 215 | return ServeMe.routes.serve(url, request, response); 216 | } catch (e) { 217 | console.log(e.stack); 218 | return true; 219 | } 220 | } 221 | return false; 222 | }, 223 | 224 | getFileData: function(file, request, response) { 225 | var path = config.directory + file; 226 | ServeMe.log("\nServing " + file); 227 | 228 | if (config.debug || this.cache[path] === undefined) { 229 | var self = this; 230 | this.readFile(path, function(err, data) { 231 | if (err) { 232 | self.serveError(404, undefined, request, response); 233 | ServeMe.log(" Couldn't serve file. 404."); 234 | return undefined; 235 | } 236 | if (!config.debug) { 237 | self.cache[path] = data; 238 | } 239 | ServeMe.log(" Served file from disk."); 240 | return data; 241 | }); 242 | } else { 243 | ServeMe.log(" Served file from cache."); 244 | return this.cache[path]; 245 | } 246 | }, 247 | 248 | readFile: function(path, callback) { 249 | fs.readFile(path, callback); 250 | }, 251 | 252 | /****************************** 253 | * Stop server 254 | * @api public 255 | ******************************/ 256 | stop: function() { 257 | this.server.close(); 258 | } 259 | } 260 | 261 | /** 262 | * @api private 263 | */ 264 | function writeResponse(status, url, data, request, response, file) { 265 | var type = mime.get((file ? file : url.pathname).split(".").pop()), 266 | head = { 267 | 'Content-Length': data.length, 268 | 'Content-Type': type 269 | }; 270 | 271 | response.writeHead(status, head); 272 | response.end(data); 273 | } -------------------------------------------------------------------------------- /test/serveme_tests.js: -------------------------------------------------------------------------------- 1 | var request = require('request'), 2 | expect = require('expect.js'), 3 | urlParser = require('url'); 4 | 5 | describe('ServeMe HttpServer', function() { 6 | var ServeMe; 7 | 8 | before(function(done) { 9 | server = require("..")({ 10 | log: false 11 | }, 3000); 12 | done(); 13 | }); 14 | 15 | it('can be loaded', function(done) { 16 | expect(server).not.to.be(undefined); 17 | expect(server.server).not.to.be(undefined); 18 | 19 | done(); 20 | }); 21 | 22 | it('can be started', function(done) { 23 | expect(server.start()).not.to.be(null); 24 | done(); 25 | }); 26 | 27 | it('can be reseted', function(done) { 28 | expect(function() { 29 | server.reset(); 30 | }).not.to.throwException(); 31 | done(); 32 | }); 33 | 34 | after(function() { 35 | server.stop(); 36 | }); 37 | }); 38 | 39 | describe('ServeMe config', function() { 40 | 41 | before(function(done) { 42 | process.env['SERVE_ME_TEST_ENV_VAR_IP'] = '192.168.1.1'; 43 | done(); 44 | }); 45 | 46 | after(function(done) { 47 | process.env['SERVE_ME_TEST_ENV_VAR_IP'] = undefined; 48 | done(); 49 | }); 50 | 51 | it('will load the hostname from an env variable', function(done) { 52 | server = require("..")({ 53 | log: false, 54 | hostname_env_var : 'SERVE_ME_TEST_ENV_VAR_IP' 55 | }, 3000); 56 | expect(server).not.to.be(undefined); 57 | expect(server.server).not.to.be(undefined); 58 | expect(server.config.hostname).to.be('192.168.1.1'); 59 | 60 | done(); 61 | }); 62 | 63 | it('will allow an undefined hostname', function(done) { 64 | server = require("..")({ 65 | log: false 66 | }, 3000); 67 | expect(server).not.to.be(undefined); 68 | expect(server.server).not.to.be(undefined); 69 | expect(server.config.hostname).to.be(undefined); 70 | 71 | done(); 72 | }); 73 | 74 | it('will use an undefined hostname if env var is not available', function(done) { 75 | server = require("..")({ 76 | log: false, 77 | hostname_env_var : 'SERVE_ME_TEST_ENV_VAR_IP_NOT_EXISTS' 78 | }, 3000); 79 | expect(server).not.to.be(undefined); 80 | expect(server.server).not.to.be(undefined); 81 | expect(server.config.hostname).to.be(undefined); 82 | 83 | done(); 84 | }); 85 | 86 | }); 87 | 88 | describe('ServeMe Routes', function() { 89 | var server; 90 | 91 | before(function(done) { 92 | server = require("..")({ 93 | log: false 94 | }, 3000); 95 | done(); 96 | }); 97 | 98 | it('can add a simple route and gets the callback', function(done) { 99 | var callback = function() { 100 | return "added a route"; 101 | }; 102 | server.get("/api/user", callback); 103 | 104 | expect(server.routes.simpleRouteDB["/api/user"]._action.GET.callbacks[0]) 105 | .to.be(callback); 106 | done(); 107 | }); 108 | 109 | it('can add a complex route and gets the callback', function(done) { 110 | var callback = function() { 111 | return "added a route"; 112 | }; 113 | server.get("/api/user/:name", callback); 114 | 115 | expect(server.routes.complexRouteDB.api.user.param._action.GET.callbacks[0]) 116 | .to.be(callback); 117 | done(); 118 | }); 119 | 120 | it('can´t get an uncreated route', function(done) { 121 | var action = server.routes.take("GET", "/user"); 122 | expect(isEmpty(action)).to.be(true); 123 | done(); 124 | }); 125 | 126 | it('can get a simple route', function(done) { 127 | var callback = function() { 128 | return "added a route"; 129 | }; 130 | server.get("/api/user", callback); 131 | 132 | expect(server.routes.take("GET", "/api/user").callbacks[0]).to.be(callback); 133 | done(); 134 | }); 135 | 136 | it('can get a complex route', function(done) { 137 | var callback = function() { 138 | return "added a route"; 139 | }; 140 | server.get("/api/user/:name", callback); 141 | 142 | expect(server.routes.take("GET", "/api/user/:name").callbacks[0]).to.be(callback); 143 | done(); 144 | }); 145 | 146 | it('can require in a route', function(done) { 147 | var callback = function() { 148 | return "added a route"; 149 | }; 150 | 151 | var fail = function() { 152 | return "added a fail route"; 153 | }; 154 | 155 | server.get("/api/user", callback).require( 156 | function(){ 157 | return true 158 | }, fail); 159 | 160 | expect(server.routes.take("GET", "/api/user").callbacks[0]).to.be(callback); 161 | expect(server.routes.take("GET", "/api/user").fails[0]).to.be(fail); 162 | 163 | done(); 164 | }); 165 | 166 | it('can reset all routes', function(done) { 167 | server.routes.get("/foo", function() { 168 | return "got a route"; 169 | }); 170 | 171 | expect(function() { 172 | server.routes.reset(); 173 | }).not.to.throwException(); 174 | expect(server.routes.simpleRouteDB).to.be.ok(); 175 | expect(server.routes.complexRouteDB).to.be.ok(); 176 | done(); 177 | }); 178 | 179 | it('can receive a route message', function(done) { 180 | server.reset(); 181 | 182 | server.routes.get("/hello", function() { 183 | return "Hello World"; 184 | }); 185 | 186 | request.get('http://localhost:' + 3000 + '/hello', function(err, res, body) { 187 | expect(res.statusCode).to.equal(200); 188 | expect(res.body).to.equal("Hello World"); 189 | done(); 190 | }); 191 | }); 192 | 193 | after(function() { 194 | server.stop(); 195 | }); 196 | 197 | it('can success a require in a route', function(done) { 198 | server.reset(); 199 | 200 | var callback = function() { return "added a success route"; }; 201 | 202 | var fail = function() { return ""; }; 203 | 204 | server.get("/api", callback).require( 205 | function(){ 206 | return true; 207 | }, fail); 208 | 209 | request.get('http://localhost:' + 3000 + '/api', function(err, res, body) { 210 | expect(res.statusCode).to.equal(200); 211 | expect(res.body).to.equal("added a success route"); 212 | done(); 213 | }); 214 | }); 215 | 216 | it('can fail a require in a route', function(done) { 217 | server.reset(); 218 | 219 | var callback = function() { return ""; }; 220 | 221 | var fail = function() { 222 | return "added a fail route"; 223 | }; 224 | 225 | server.get("/api", callback).require( 226 | function(){ 227 | return false; 228 | }, fail); 229 | 230 | request.get('http://localhost:' + 3000 + '/api', function(err, res, body) { 231 | expect(res.statusCode).to.equal(200); 232 | expect(res.body).to.equal("added a fail route"); 233 | done(); 234 | }); 235 | }); 236 | 237 | it('will set the correct content type for String data', function(done) { 238 | server.reset(); 239 | 240 | server.routes.get("/hello", function() { 241 | return "Hello World"; 242 | }); 243 | 244 | request.get('http://localhost:' + 3000 + '/hello', function(err, res, body) { 245 | expect(res.statusCode).to.equal(200); 246 | expect(res.body).to.equal("Hello World"); 247 | expect(res.headers['content-type']).to.equal('text/plain'); 248 | done(); 249 | }); 250 | }); 251 | 252 | it('will set the correct content type for JSON data', function(done) { 253 | server.reset(); 254 | 255 | server.routes.get("/hello", function() { 256 | return { 257 | json: { test: true } 258 | }; 259 | }); 260 | 261 | request.get('http://localhost:' + 3000 + '/hello', function(err, res, body) { 262 | expect(res.statusCode).to.equal(200); 263 | expect(res.body).to.equal('{"test":true}'); 264 | expect(res.headers['content-type']).to.equal('application/json'); 265 | done(); 266 | }); 267 | }); 268 | 269 | }); 270 | 271 | 272 | describe('ServeMe Sessions', function() { 273 | var ServeMe; 274 | 275 | before(function(done) { 276 | ServeMe = require("..")({ 277 | log: false, 278 | session: { 279 | enabled: true, 280 | persistence: false, 281 | lifetime: 86400 282 | } 283 | }); 284 | done(); 285 | }); 286 | 287 | it('exists', function(done) { 288 | expect(ServeMe.Session).not.to.be(undefined); 289 | done(); 290 | }); 291 | 292 | it('cant create a session whitout loading Sessions', function(done) { 293 | ServeMe.stop(); 294 | ServeMe = require(".."); 295 | 296 | expect(function() { 297 | new ServeMe.Session("0", { 298 | path: "/session/login", 299 | domain: "localhost" 300 | }); 301 | }).to.throwException(); 302 | 303 | done(); 304 | 305 | ServeMe = require("..")({ 306 | session: { 307 | enabled: true, 308 | persistence: false, 309 | lifetime: 86400 310 | } 311 | }); 312 | }); 313 | 314 | it('can create a session', function(done) { 315 | var session = new ServeMe.Session("0", { 316 | path: "/session/login", 317 | domain: "localhost" 318 | }); 319 | expect(session).to.be.a(ServeMe.Session); 320 | 321 | done(); 322 | }); 323 | 324 | it('created sessions contains correct arguments', function(done) { 325 | var session = new ServeMe.Session("0", { 326 | path: "/session/login", 327 | domain: "mysite.com" 328 | }); 329 | expect(session.path).to.be("/session/login"); 330 | expect(session.domain).to.be("mysite.com"); 331 | 332 | done(); 333 | }); 334 | 335 | after(function() { 336 | ServeMe.stop(); 337 | }); 338 | }); 339 | 340 | function isEmpty(obj) { 341 | for(var prop in obj) { 342 | if(obj.hasOwnProperty(prop)) 343 | return false; 344 | } 345 | return true; 346 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Serve-Me 2 | 3 | [![NPM](https://nodei.co/npm/serve-me.png?downloadRank=true&stars=true)](https://nodei.co/npm/serve-me/) 4 | 5 | [![Build Status](https://travis-ci.org/muit/serveMe.svg)](https://travis-ci.org/muit/serveMe) 6 | ![Downloads](http://img.shields.io/npm/dm/serve-me.svg) 7 | 8 | ServeMe is a [DSL](http://en.wikipedia.org/wiki/Domain-specific_language) for creating simple web applications with nodejs. 9 | ```javascript 10 | ServeMe = require('serve-me')(); 11 | 12 | ServeMe.start(3000); 13 | ``` 14 | 15 | ## Installing 16 | 17 | ``` 18 | npm install serve-me 19 | ``` 20 | 21 | ## Setting up the options 22 | The options can be set in the ServeMe loading, but by default it will use the folder "./public" and the file "index.html". 23 | ```javascript 24 | //Require the module 25 | ServeMe = require("serve-me"); 26 | 27 | //Set the options 28 | var serveMe = ServeMe({ 29 | debug: true, 30 | /**If debug mode is enabled, it will load each file again every http request, else the files will wait in cache. 31 | * Also prints more logs 32 | **/ 33 | 34 | log: true, 35 | //(Optional) If log is enabled the server reports all the files served and more information. 36 | 37 | home: "mypage.html", 38 | //(Optional) home will change the html file served in "/" (by default: 'index.html') 39 | 40 | directory: "./www", 41 | //(Optional) directory will change the default public folder ('./public') 42 | 43 | error: { 44 | 404: "404.html", 45 | 500: "500.html" 46 | /**Error pages depending on the error code. 47 | * That specified files must exist in the 'public/error' folder. 48 | * Model: 'errorcode': "file.html" 49 | **/ 50 | }, 51 | 52 | //(Optional) 53 | secure: false, 54 | //Will use https when enabled. 55 | //ATENTION: A key and a certificate must be provided. 56 | //By default serve-me will use: 57 | key: "./keys/key.pem", 58 | cert: "./keys/cert.pem", 59 | }); 60 | 61 | //Start the server 62 | serveMe.start(3000);//3000 is the port. Of course you can change it. 63 | 64 | //Also you can add a callback to wait for the server to start. 65 | serveMe.start(3000, function(){ 66 | console.log("Is Up!"); 67 | }); 68 | ``` 69 | 70 | ## Routes 71 | 72 | To add specific actions to url paths ServeMe includes Routes. 73 | 74 | Create a route example: 75 | ```javascript 76 | serveMe.get("/hello", function(){ 77 | return "Hello World!"; 78 | }); 79 | ``` 80 | 81 | You can create get, post, update or other method routes, and add different behaviours to them. 82 | ```javascript 83 | serveMe.get("/user", function(){ 84 | return "I get all the users"; 85 | }); 86 | 87 | serveMe.post("/user", function(){ 88 | return "I create an user"; 89 | }); 90 | ``` 91 | 92 | Routes overview: 93 | ```javascript 94 | serveMe.METHOD("path", function(request, response, next){ 95 | var result = "" //Direct response as text 96 | 97 | result = { //Custom response 98 | status: 200, //Result status 99 | body: "", //Response as text 100 | json: {}, //Response as json 101 | } 102 | 103 | next result; 104 | //or 105 | return result; 106 | }); 107 | ``` 108 | 109 | ### Responding with custom status or json 110 | Just returning an object with some attributes, you will be able to customise your answer easily. 111 | ```javascript 112 | serveMe.get("/api/profile", function(request){ 113 | return { 114 | status: 404, 115 | 116 | //return a json 117 | json: {}, 118 | //or return a simple text 119 | body: "" 120 | }; 121 | }); 122 | ``` 123 | 124 | PD: You can anidate routes to have a simpler syntax. 125 | ```javascript 126 | serveMe.get("/chicken", function(){ 127 | return "fried_chicken"; 128 | }) 129 | .post("/cat", function(){ 130 | return { 131 | json: { 132 | lives: 6 133 | } 134 | }; 135 | }) 136 | ``` 137 | 138 | ### Dynamic routes 139 | Since v0.7.3 the dynamic routes are implemented. And.. nothing is better than some examples. 140 | 141 | ```javascript 142 | serveMe.get("/user/:name", function(req){ 143 | return "This is the profile of " + req.params.name; 144 | }); 145 | 146 | serveMe.get("/posts/:id", function(req){ 147 | return "Post with id " + req.params.id; 148 | }); 149 | ``` 150 | With the dynamic routes you can have a dinamic content and rest api applications running easily on serve-me. 151 | 152 | ### Redirection Routes 153 | To link urls to a view or file, replace the "callback" of a route with the url: 154 | ```javascript 155 | serveMe.get("/lobby", "/lobby.html"); 156 | ``` 157 | 158 | ### Require 159 | To make the development easier Serve-me have the require method, witch allows you to execute a route only in some situations. 160 | 161 | ```javascript 162 | function fail(req, res, next) { 163 | return "Failed"; 164 | } 165 | 166 | serveMe.get("/profile", doSomething).require( function(){ 167 | //returns a boolean: true-> passed the require 168 | return true; 169 | }, fail); 170 | ``` 171 | Fail will be calles when the require callback returns false. 172 | 173 | 174 | ### Reset 175 | For specific uses you can reset all the routes: 176 | ```javascript 177 | serveMe.routes.reset(); 178 | ``` 179 | 180 | ## Events 181 | 182 | To add actions to specific events yo can use the ServeMe Events. 183 | ```javascript 184 | serveMe.on("event_name", function(data){ 185 | console.log("I am an event!"); 186 | }); 187 | ``` 188 | "event_name" is the name required to select de action wanted. 189 | 190 | These are the available events for now: 191 | - "listening": Server is started and listening. 192 | - "http_request": Each http connection. 193 | - "new_session": A new session can be created. 194 | - "end_session": An existing session lifetime ends. 195 | - "session": An existing session connects. 196 | - "error": An error appears. 197 | 198 | If you want to create your own event, you can activate it with: 199 | ```javascript 200 | serveMe.call("event_name"); 201 | ``` 202 | 203 | 204 | ## Sessions 205 | 206 | The sessions have been implemented to facilitate the creation of user sessions or similar tasks, mainly using cookies. 207 | 208 | First of all we need to enable sessions in the serveme options: 209 | ```javascript 210 | var serveMe = ServeMe({ 211 | debug: false, 212 | 213 | session:{ 214 | enabled: true, //Enable sessions 215 | persistence: true, //if false disables the lifetime, and the session never ends (default true) 216 | lifetime: 86400, //Life of the session in seconds (default: 1 day) 217 | new_session_url: "/session/new", //Url selected to create sessions 218 | //new session petition will be created each visit 219 | } 220 | }); 221 | ``` 222 | 223 | Then "session/new" will reqistry each visitor in a new session. But one more step is needed. To alow the customization of the session registry you can use the "new_session" event like this: 224 | ```javascript 225 | var username = "bear"; 226 | var password = "drowssap"; 227 | 228 | serveMe.on("new_session", function(new_session){ 229 | //new_session.data contains all the url arguments. 230 | //Login example: 231 | if( new_session.data.username == username && 232 | new_session.data.password == password) 233 | { 234 | //if there are the correct credentials allow a new session creation, returning true. 235 | return true; 236 | } 237 | //else returning false. 238 | return false; 239 | }); 240 | ``` 241 | 242 | session.data contains all the url arguments, for example a session request like 243 | ```javascript 244 | /session/new?username=bear&password=drowssap 245 | ``` 246 | 247 | will give us that session.data: 248 | ```javascript 249 | >{ 250 | > username: "bear", 251 | > password: "drowssap" 252 | >} 253 | ``` 254 | 255 | ## Cluster 256 | Cluster if the functionality that allows serve-me to run in multi-threading mode. 257 | 258 | It must be enabled in the initial options: 259 | ```javascript 260 | ServeMe = require("serve-me"); 261 | 262 | var serveMe = ServeMe({ 263 | cluster: { 264 | // Enabling cluster 265 | enabled: true, 266 | 267 | // Amount of cpus that will be used. By default is "max". 268 | cpus: "max" 269 | 270 | // 'cpus' needs to be a number. If not it will be the maximum amount of cpus ("max") 271 | }, 272 | }); 273 | 274 | serveMe.start(3000); 275 | ``` 276 | 277 | ## Issues 278 | 279 | Let me know your suggestions and bugs found to improve Serve-me [here!](https://github.com/muit/serveMe/issues)! 280 | 281 | [https://github.com/muit/serveMe/issues](https://github.com/muit/serveMe/issues) 282 | 283 | ## License 284 | 285 | The MIT License (MIT) 286 | 287 | Copyright (c) 2014-2015 @muitxer (https://github.com/muit) 288 | 289 | Permission is hereby granted, free of charge, to any person obtaining a copy 290 | of this software and associated documentation files (the "Software"), to deal 291 | in the Software without restriction, including without limitation the rights 292 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 293 | copies of the Software, and to permit persons to whom the Software is 294 | furnished to do so, subject to the following conditions: 295 | 296 | The above copyright notice and this permission notice shall be included in 297 | all copies or substantial portions of the Software. 298 | 299 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 300 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 301 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 302 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 303 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 304 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 305 | THE SOFTWARE. 306 | 307 | -------------------------------------------------------------------------------- /examples/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |

Lets make this heavy


7 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 8 | 9 | 10 | --------------------------------------------------------------------------------