Advertisement
stuppid_bot

Untitled

Sep 7th, 2013
154
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. var my = this,
  2.     fs = require('fs'),
  3.     http = require('http');
  4.  
  5. my.template = function(str, data) {
  6.     return str.replace(/\{\{\s+(\w+(\.\w+)*)\s+\}\}/g, function(src, name) {
  7.         var part,
  8.             parts = name.split('.'),
  9.             cur = data;
  10.  
  11.          while  (part = parts.shift()) {
  12.             if (!(part in cur)) {
  13.                 return '';
  14.             }
  15.  
  16.             cur = cur[part];
  17.         }
  18.  
  19.         return cur;
  20.     });
  21. };
  22.  
  23. my.render = function(filename) {
  24.     var content = fs.readFileSync(filename, 'utf8');
  25.  
  26.     fs.watchFile(filename, function() {
  27.         console.log('File "' + filename + '" was changed');
  28.  
  29.         fs.readFile(filename, 'utf8', function(err, data) {
  30.             if (err) {
  31.                 throw err;
  32.             }
  33.  
  34.             content = data;
  35.         });
  36.     });
  37.  
  38.     return function(data) {
  39.         return my.template(content, data);
  40.     };
  41. };
  42.  
  43. my.HttpServer = function(options) {      
  44.     var self = this,
  45.         runned = false,
  46.         // настройки по-умолчанию
  47.         defaults = {            
  48.             allowedMethods: ['DELETE', 'GET', 'POST', 'PUT'],
  49.             maxRequestLength: 20000000,
  50.             webRoot: './webroot',
  51.             indexFiles: ['index.htm', 'index.html', 'default.htm', 'default.html'],
  52.             host: '127.0.0.1',
  53.             port: 80
  54.         },
  55.         routeMap = {},
  56.         customTpl = my.render(__dirname + '/data/custom.tpl');
  57.     self.mimeTypes = {};
  58.  
  59.     function setProperties() {
  60.         options = options || {};
  61.  
  62.         for (var p in defaults) {
  63.             if (defaults.hasOwnProperty(p)) {
  64.                 self[p] = p in options ? options[p] : defaults[p];
  65.             }
  66.         }
  67.     }
  68.  
  69.     function loadMimeTypes() {
  70.         var data = fs.readFileSync(__dirname + '/data/mime.types', 'ascii');
  71.         data = data.replace(/#(.*)\n|\n+$/g, '');
  72.         data = data.split('\n');
  73.         var i = data.length,
  74.             parts,
  75.             j;
  76.  
  77.         while (i--) {
  78.             parts = data[i].split(/\s+/g);
  79.             j = parts.length;
  80.  
  81.             while (--j) {
  82.                 self.mimeTypes[parts[j]] = parts[0];
  83.             }
  84.         }
  85.     }
  86.  
  87.     self.getMimeType = function(filename) {
  88.         var matches = filename.match(/\.(\w+)$/);
  89.  
  90.         if (matches) {
  91.             var extension = matches[1];
  92.  
  93.             if (extension in self.mimeTypes) {
  94.                 return self.mimeTypes[extension];
  95.             }
  96.         }
  97.  
  98.         return null;
  99.     };
  100.  
  101.     self.addRoute = function(method, rule, cb) {
  102.         if (!(method in routeMap)) {
  103.             routeMap[method] = [];
  104.         }
  105.  
  106.         routeMap[method].push([rule, cb]);
  107.     };
  108.  
  109.     self.get = function(rule, cb) {
  110.         self.addRoute('GET', rule, cb);
  111.     };
  112.  
  113.     self.post = function(rule, cb) {
  114.         self.addRoute('POST', rule, cb);
  115.     };
  116.  
  117.     self.put = function(rule, cb) {
  118.         self.addRoute('PUT', rule, cb);
  119.     };
  120.  
  121.     self.delete = function(rule, cb) {
  122.         self.addRoute('DELETE', rule, cb);
  123.     };
  124.  
  125.     self.run = function() {
  126.         if (runned) {
  127.             throw 'Server is already running';
  128.         }
  129.  
  130.         runned = true;
  131.  
  132.         http.createServer(function(req, res) {
  133.             function errPage(statusCode, message) {            
  134.                 var status = http.STATUS_CODES[statusCode],
  135.                     html = customTpl({
  136.                         title: statusCode + ' - ' + status,
  137.                         heading: status,
  138.                         content: '<p>' + message + '</p>'
  139.                     });
  140.                 res.writeHead(statusCode, {'Content-Type': 'text/html'});
  141.                 res.end(html);
  142.             }
  143.  
  144.             function err403() {
  145.                 errPage(403, 'Access denied.');
  146.             }
  147.  
  148.             function err404() {
  149.                 errPage(404, 'File or directory not found.');
  150.             }
  151.  
  152.             function err405() {
  153.                 errPage(405, 'HTTP request "' + req.method + '" method is not supported by this URL.')
  154.             }
  155.  
  156.             function err413() {
  157.                 errPage(413, 'Maximum request length exceeded.');
  158.             }
  159.  
  160.             function err500() {
  161.                 errPage(500, 'An application error cccured.');
  162.             }
  163.  
  164.             function err501() {
  165.                  errPage(501, 'HTTP request "' + req.method + '" method is not implemented.')
  166.             }
  167.  
  168.             function sendFile(filename, stats) {                  
  169.                 var stream = fs.createReadStream(filename);
  170.  
  171.                 stream.on('error', function() {
  172.                     console.log(err.stack);
  173.                 });
  174.  
  175.                 stream.on('open', function() {
  176.                     var mime;
  177.                     res.setHeader('Last-Modified', stats.mtime.toUTCString());  
  178.  
  179.                     if (mime = self.getMimeType(filename)) {
  180.                         res.setHeader('Content-Type', mime);
  181.                     }
  182.  
  183.                     res.setHeader('Content-Length', stats.size);
  184.                 });
  185.  
  186.                 stream.pipe(res);
  187.             };
  188.  
  189.             if (self.allowedMethods.indexOf(req.method) == -1) {
  190.                 return err501();
  191.             }
  192.  
  193.             var len = parseInt(req.headers['content-length']);
  194.  
  195.             if (len && len > self.maxRequestLength) {
  196.                 return err413();
  197.             }              
  198.  
  199.             req.on('error', function(err) {
  200.                 console.log(err.stack);
  201.             });
  202.  
  203.             var received = 0;
  204.             req.body = '';
  205.  
  206.             req.on('data', function(chunk) {
  207.                 if ((received += chunk.length) > self.maxRequestLength) {
  208.                     return this.destroy();
  209.                 }
  210.  
  211.                 console.log('Received data: ' + chunk.length + ' bytes');
  212.                 req.body += chunk;
  213.             });
  214.  
  215.             req.on('end', function() {
  216.                 var uri = decodeURI(this.url.split('?')[0]).replace(/[\\/]+/g, '/'),
  217.                     path = self.webRoot + uri;
  218.  
  219.                 if (req.method in routeMap) {
  220.                     var routes = routeMap[req.method],
  221.                         i = routes.length,
  222.                         route,
  223.                         rule,
  224.                         cb,
  225.                         matches;
  226.  
  227.                     while (i--) {
  228.                         route = routes[i];
  229.                         rule = route[0];
  230.                         cb = route[1];
  231.  
  232.                         if (rule instanceof RegExp) {
  233.                             matches = uri.match(rule);
  234.  
  235.                             if (matches) {
  236.                                 return cb.apply(null, [req, res].concat(matches.slice(1)));
  237.                             }
  238.                         }
  239.                         else if (rule == uri) {
  240.                             return cb(req, res);
  241.                         }
  242.                     }
  243.                 }            
  244.  
  245.                 fs.exists(path, function(exists) {
  246.                     if (!exists) {
  247.                         return err404();
  248.                     }
  249.  
  250.                     if (req.method != 'GET') {
  251.                         return err405();
  252.                     }
  253.  
  254.                     fs.stat(path, function(err, stats) {
  255.                         if (err) {
  256.                             console.log(err.stack);
  257.                             return;
  258.                         }
  259.  
  260.                         if (stats.isDirectory()) {
  261.                             fs.readdir(path, function(err, files) {
  262.                                 if (err) {
  263.                                     console.log(err.stack);
  264.                                     return;
  265.                                 }
  266.  
  267.                                 var i = 0;
  268.  
  269.                                 while (i < self.indexFiles.length) {
  270.                                     if (files.indexOf(self.indexFiles[i]) >= 0) {
  271.                                         var filename = path + '/' + self.indexFiles[i];
  272.  
  273.                                         fs.stat(filename, function(err, stats) {
  274.                                             if (stats && stats.isFile()) {
  275.                                                 return sendFile(filename, stats);
  276.                                             }
  277.  
  278.                                             err500();
  279.                                         });
  280.  
  281.                                         return;
  282.                                     }
  283.  
  284.                                     ++i;
  285.                                 }
  286.  
  287.                                 if (!/\/$/.test(uri)) {
  288.                                     uri += '/';
  289.                                 }
  290.  
  291.                                 var html = customTpl({
  292.                                     title: 'Directory listing',
  293.                                     heading: 'Index of ' + uri,
  294.                                     content: '<a href="' + uri.replace(/([^/]+)\/$/, '') + '">moveUp</a><ul>'
  295.                                         + files.map(
  296.                                             function(a) {
  297.                                                 return '<li><a href="' + uri + encodeURIComponent(a)  + '">' + a + '</a></li>';
  298.                                             }
  299.                                         ).join('') + '</ul>'
  300.                                 });
  301.                                 res.writeHead(200, {'Content-Type': 'text/html'});
  302.                                 res.end(html);
  303.                             });
  304.                         }
  305.                         else {
  306.                             if (/\/$/.test(uri)) {
  307.                                 return err404();
  308.                             }
  309.  
  310.                             if (stats.isFile()) {
  311.                                 return sendFile(path, stats);
  312.                             }
  313.  
  314.                             err403();
  315.                         }
  316.                     });
  317.                 });
  318.             });
  319.         }).listen(self.port, self.host);
  320.        
  321.         console.log('Server running at http://%s:%s/', self.host, self.port);
  322.     };
  323.  
  324.     setProperties();
  325.     loadMimeTypes();
  326. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement