From 3d017571cab4f2df1214b3ad25c9456dd62d3224 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Wed, 13 Aug 2014 10:54:36 -0400 Subject: [PATCH] feature(ponse) mv req, res functions to ponse --- cloudcmd.js | 13 +- lib/server.js | 7 +- lib/server/join.js | 13 +- lib/server/main.js | 320 ---------------------------------- lib/server/ponse.js | 331 ++++++++++++++++++++++++++++++++++++ lib/server/rest.js | 20 ++- lib/server/rest/markdown.js | 5 +- 7 files changed, 363 insertions(+), 346 deletions(-) create mode 100644 lib/server/ponse.js diff --git a/cloudcmd.js b/cloudcmd.js index ce51acea..025fe47e 100644 --- a/cloudcmd.js +++ b/cloudcmd.js @@ -7,6 +7,7 @@ main = require(DIR_SERVER + 'main'), format = require(DIR_SERVER + 'format'), mellow = require(DIR_SERVER + 'mellow'), + ponse = require(DIR_SERVER + 'ponse'), HTMLDIR = main.HTMLDIR, @@ -216,7 +217,7 @@ var name, p, isAuth, isFS, path; if (request && response) { - name = main.getPathName(request); + name = ponse.getPathName(request); isAuth = Util.strCmp(name, ['/auth', '/auth/github']); isFS = Util.strCmp(name, '/') || Util.isContainStrAtBegin(name, FS); @@ -232,7 +233,7 @@ Util.log('* Routing' + '-> ' + name); p.name = main.HTMLDIR + name + '.html'; - main.sendFile(p); + ponse.sendFile(p); } else if (isFS) { name = Util.rmStrOnce(name, CloudFunc.FS) || main.SLASH; path = mellow.convertPath(name); @@ -244,9 +245,9 @@ if (error) if (error.code === 'ENOTDIR') { p.name = path; - main.sendFile(p); + ponse.sendFile(p); } else { - main.sendError(error, p); + ponse.sendError(error, p); } else buildIndex(dir, function(error, data) { @@ -255,9 +256,9 @@ p.name = PATH_INDEX; if (error) - main.sendError(error, p); + ponse.sendError(error, p); else - main.sendResponse(data, p, NOT_LOG); + ponse.send(data, p, NOT_LOG); }); }); } diff --git a/lib/server.js b/lib/server.js index 244d5514..c64d5afd 100644 --- a/lib/server.js +++ b/lib/server.js @@ -32,6 +32,7 @@ init: function() {} }, join = require(DIR_SERVER + 'join'), + ponse = require(DIR_SERVER + 'ponse'), express = require(DIR_SERVER + 'express'), expressApp, @@ -102,7 +103,7 @@ url = protocol + hostName + sslPort + req.url; - main.redirect({ + ponse.redirect({ response: res, url: url }); @@ -190,7 +191,7 @@ isMin = config.minify, parsedUrl = URL.parse(req.url), query = parsedUrl.search || '', - path = main.getPathName(req), + path = ponse.getPathName(req), name = path; if (!expressApp) @@ -208,7 +209,7 @@ function(error, params) { var sendName = params && params.name || name; - main.sendFile({ + ponse.sendFile({ name : sendName, cache : config.cache, gzip : true, diff --git a/lib/server/join.js b/lib/server/join.js index aba9bf0f..a4dc7016 100644 --- a/lib/server/join.js +++ b/lib/server/join.js @@ -3,8 +3,9 @@ var DIR = '../', DIR_SERVER = DIR + 'server/', - main = require(DIR_SERVER + 'main'), files = require(DIR_SERVER + 'files'), + ponse = require(DIR_SERVER + 'ponse'), + Util = require(DIR + 'util'), CloudFunc = require(DIR + 'cloudfunc'), zlib = require('zlib'); @@ -17,7 +18,7 @@ var names, exec = Util.exec, readFunc = exec.with(readPipe, req, res), - path = main.getPathName(req), + path = ponse.getPathName(req), regExp = new RegExp('^/join/'), isJoin = path.match(regExp); @@ -36,11 +37,11 @@ function readPipe(req, res, names) { var stream, - path = main.getPathName(req), + path = ponse.getPathName(req), gzip = zlib.createGzip(), - isGzip = main.isGZIP(req); + isGzip = ponse.isGZIP(req); - main.mainSetHeader({ + ponse.setHeader({ name : names[0], cache : true, gzip : isGzip, @@ -60,7 +61,7 @@ if (res.headersSent) stream.end(msg); else - main.sendError(msg, { + ponse.send.error(msg, { request : req, response : res, name : path diff --git a/lib/server/main.js b/lib/server/main.js index ffb2b086..c91f11dc 100644 --- a/lib/server/main.js +++ b/lib/server/main.js @@ -13,25 +13,12 @@ ext, path, fs, zlib, url, pipe, CloudFunc, diffPatch, querystring, - OK, RANGE, FILE_NOT_FOUND, MOVED_PERMANENTLY, - REQUEST, RESPONSE, - Config = { server : true, socket : true, port : 80 }; - /* Consts */ - - exports.OK = OK = 200; - RANGE = 206; - MOVED_PERMANENTLY = 301; - exports.FILE_NOT_FOUND = FILE_NOT_FOUND = 404; - - exports.REQUEST = REQUEST = 'request'; - exports.RESPONSE = RESPONSE = 'response'; - /* Native Modules*/ exports.crypto = require('crypto'), exports.child_process = require('child_process'), @@ -60,19 +47,6 @@ exports.rootrequire = rootrequire, exports.quietrequire = quietrequire, - exports.generateHeaders = generateHeaders, - exports.getQuery = getQuery, - exports.getPathName = getPathName, - exports.isGZIP = isGZIP, - exports.mainSetHeader = mainSetHeader, - - exports.sendFile = sendFile, - exports.sendResponse = sendResponse, - exports.sendError = sendError, - exports.redirect = redirect, - - exports.checkParams = checkParams, - /* compitability with old versions of node */ exports.fs.exists = exports.fs.exists || exports.path.exists, @@ -162,298 +136,4 @@ */ function isWin32() { return process.platform === 'win32'; } - /** - * Функция создаёт заголовки файлов - * в зависимости от расширения файла - * перед отправкой их клиенту - * @param pParams - * name - имя файла - * gzip - данные сжаты gzip'ом - * query - * https://developers.google.com/speed/docs/best-practices/caching?hl=ru#LeverageProxyCaching - */ - function generateHeaders(params) { - var header, p, extension, type, encoding, isContain, cmp, - maxAge = 31337 * 21; - - if (params.name) { - p = params, - extension = Util.getExt(p.name), - type = ext[extension] || 'text/plain', - encoding = ''; - - /* if type of file any, but img - then we shoud specify charset */ - isContain = Util.isContainStr(type, ['img', 'image', 'audio']); - if (!isContain) - encoding = '; charset=UTF-8'; - - isContain = Util.isContainStr(p.query, 'download'); - if (isContain) - type = 'application/octet-stream'; - - header = { - 'Access-Control-Allow-Origin' : '*', - 'Content-Type' : type + encoding, - 'Vary' : 'Accept-Encoding', - 'Accept-Ranges' : 'bytes' - }; - - if (p.time) - Util.copyObj(header, { - 'Last-Modified' : p.time - }); - - if (p.range) - Util.copyObj(header, { - 'Content-Range' : 'bytes ' + p.range.start + - '-' + p.range.end + - '/' + p.range.sizeTotal, - - 'Content-Length': p.range.size - }); - - cmp = Util.strCmp(ext, '.appcache'); - if (!p.cache || cmp) - maxAge = 0; - - header['Cache-Control'] = 'max-age=' + maxAge; - - if (p.gzip) - header['Content-Encoding'] = 'gzip'; - } - - return header; - } - - function mainSetHeader(pParams) { - var p, header, gzip, - lRet = checkParams(pParams); - - if (lRet) { - p = pParams; - gzip = p.isGzip || isGZIP(p.request) && p.gzip; - - header = generateHeaders({ - name : p.name, - time : p.time, - range : p.range, - length : p.length, - cache : p.cache, - gzip : gzip, - query : getQuery(p.request) - }); - - setHeader(header, p.response); - p.response.statusCode = p.status || OK; - } - } - - /** - * send file to client thru pipe - * and gzip it if client support - * - */ - function sendFile(params) { - var p = params, - ret = checkParams(params); - - if (ret) - fs.lstat(p.name, function(error, stat) { - var time, length, range, isGzip, - options = {}; - - if (error) { - sendError(error, params); - } else { - isGzip = isGZIP(p.request) && p.gzip; - time = stat.mtime, - length = stat.size, - range = getRange(p.request, length); - - if (range) - Util.copyObj(p, { - range : range, - status : RANGE - }); - - Util.copyObj(p, { - time : time - }); - - mainSetHeader(params); - - options = { - gzip : isGzip, - range : range - }; - - pipe.create(p.name, p.response, options, function(error) { - if (error) - sendError(error, params); - }); - } - }); - } - - - /** - * Функция высылает ответ серверу - * @param data - * @param params - * @param notLog - */ - function sendResponse(data, params, notLog) { - var p, isGzip, head, - ret = checkParams(params); - - if (ret) { - p = params; - data = data; - isGzip = p.gzip && isGZIP(p.request); - - head = generateHeaders({ - name : p.name, - cache : p.cache, - gzip : isGzip, - query : p.query - }); - - setHeader(head, p.response); - - if (!notLog) - Util.log(data); - - /* если браузер поддерживает gzip-сжатие - сжимаем данные*/ - Util.exec.if(!isGzip, - function() { - if (!p.data) - p.data = data; - - p.response.statusCode = p.status || OK; - p.response.end(p.data); - }, - - function(callback) { - zlib.gzip (data, function(error, data) { - if (!error) - p.data = data; - else { - p.status = FILE_NOT_FOUND; - p.data = error.message; - } - - callback(); - }); - }); - } - } - - - /** - * redirect to another URL - */ - function redirect(pParams) { - var p, header, - lRet = Util.checkObjTrue(pParams, [RESPONSE]); - - if (lRet) { - p = pParams; - - header = { - 'Location': p.url - }; - - setHeader(header, p.response); - p.response.statusCode = MOVED_PERMANENTLY; - p.response.end(); - } - } - - - /** - * send error response - */ - function sendError(error, params) { - var data, ret = checkParams(params); - - if (ret) { - params.status = FILE_NOT_FOUND; - data = error.message || '' + error; - - sendResponse(data, params); - } - } - - function checkParams(params, additional) { - var ret = Util.checkObjTrue(params, ['name', REQUEST, RESPONSE]); - - if (ret && additional) - ret = Util.checkObjTrue(params, additional); - - return ret; - } - - function getQuery(req) { - var query, parsed; - - if (req) { - parsed = url.parse(req.url); - query = parsed.query; - } - - return query; - } - - function getPathName(req) { - var pathname, parsed; - - if (req) { - parsed = url.parse(req.url); - pathname = parsed.pathname; - /* supporting of Russian language in directory names */ - pathname = querystring.unescape(pathname); - } - - return pathname; - } - - function isGZIP(req) { - var enc, is; - - if (req) { - enc = req.headers['accept-encoding'] || ''; - is = enc.match(/\bgzip\b/); - } - - return is; - } - - function setHeader(header, response) { - var name; - - if (!response.headersSent && Util.isObject(header)) - for (name in header) - response.setHeader(name, header[name]); - } - - function getRange(req, sizeTotal) { - var range, start, end, size, parts, - rangeStr = req.headers.range; - - if (rangeStr) { - parts = rangeStr.replace(/bytes=/, '').split('-'); - start = parts[0]; - end = parts[1] || sizeTotal - 1; - size = (end - start) + 1; - - range = { - start : start - 0, - end : end - 0, - size : size, - sizeTotal : sizeTotal - }; - } - - return range; - } })(); diff --git a/lib/server/ponse.js b/lib/server/ponse.js new file mode 100644 index 00000000..3b89c7ab --- /dev/null +++ b/lib/server/ponse.js @@ -0,0 +1,331 @@ +(function() { + 'use strict'; + + var fs = require('fs'), + zlib = require('zlib'), + url = require('url'), + querystring = require('querystring'), + + DIR_JSON = __dirname + '/../../json/', + + Util = require('../util'), + pipe = require('./pipe'), + ext = require(DIR_JSON + 'ext'), + + OK = 200, + RANGE = 206, + MOVED_PERMANENTLY = 301, + FILE_NOT_FOUND = 404, + + REQUEST = 'request', + RESPONSE = 'response'; + + exports.redirect = redirect; + + exports.send = send; + exports.sendError = sendError; + exports.sendFile = sendFile; + + exports.isGZIP = isGZIP; + + exports.getPathName = getPathName; + exports.getQuery = getQuery; + + exports.setHeader = setHeader; + + exports.checkParams = checkParams; + + /* Функция высылает ответ серверу + * @param data + * @param params + * @param notLog + */ + function send(data, params, notLog) { + var p, isGzip, head, + ret = checkParams(params); + + if (ret) { + p = params; + data = data; + isGzip = p.gzip && isGZIP(p.request); + + head = generateHeaders({ + name : p.name, + cache : p.cache, + gzip : isGzip, + query : p.query + }); + + fillHeader(head, p.response); + + if (!notLog) + Util.log(data); + + /* если браузер поддерживает gzip-сжатие - сжимаем данные*/ + Util.exec.if(!isGzip, + function() { + if (!p.data) + p.data = data; + + p.response.statusCode = p.status || OK; + p.response.end(p.data); + }, + + function(callback) { + zlib.gzip (data, function(error, data) { + if (!error) + p.data = data; + else { + p.status = FILE_NOT_FOUND; + p.data = error.message; + } + + callback(); + }); + }); + } + } + + /** + * Функция создаёт заголовки файлов + * в зависимости от расширения файла + * перед отправкой их клиенту + * @param pParams + * name - имя файла + * gzip - данные сжаты gzip'ом + * query + * https://developers.google.com/speed/docs/best-practices/caching?hl=ru#LeverageProxyCaching + */ + function generateHeaders(params) { + var header, p, extension, type, encoding, isContain, cmp, + maxAge = 31337 * 21; + + if (params.name) { + p = params, + extension = Util.getExt(p.name), + type = ext[extension] || 'text/plain', + encoding = ''; + + /* if type of file any, but img - then we shoud specify charset */ + isContain = Util.isContainStr(type, ['img', 'image', 'audio']); + if (!isContain) + encoding = '; charset=UTF-8'; + + isContain = Util.isContainStr(p.query, 'download'); + if (isContain) + type = 'application/octet-stream'; + + header = { + 'Access-Control-Allow-Origin' : '*', + 'Content-Type' : type + encoding, + 'Vary' : 'Accept-Encoding', + 'Accept-Ranges' : 'bytes' + }; + + if (p.time) + Util.copyObj(header, { + 'Last-Modified' : p.time + }); + + if (p.range) + Util.copyObj(header, { + 'Content-Range' : 'bytes ' + p.range.start + + '-' + p.range.end + + '/' + p.range.sizeTotal, + + 'Content-Length': p.range.size + }); + + cmp = Util.strCmp(ext, '.appcache'); + if (!p.cache || cmp) + maxAge = 0; + + header['Cache-Control'] = 'max-age=' + maxAge; + + if (p.gzip) + header['Content-Encoding'] = 'gzip'; + } + + return header; + } + + function setHeader(pParams) { + var p, header, gzip, + lRet = checkParams(pParams); + + if (lRet) { + p = pParams; + gzip = p.isGzip || isGZIP(p.request) && p.gzip; + + header = generateHeaders({ + name : p.name, + time : p.time, + range : p.range, + length : p.length, + cache : p.cache, + gzip : gzip, + query : getQuery(p.request) + }); + + fillHeader(header, p.response); + p.response.statusCode = p.status || OK; + } + } + + function fillHeader(header, response) { + var isObject = Util.isObject(header), + isSent = response.headersSent; + + if (!isSent && isObject) + Object.keys(header).forEach(function(name) { + response.setHeader(name, header[name]); + }); + } + + /** + * send file to client thru pipe + * and gzip it if client support + * + */ + function sendFile(params) { + var p = params, + ret = checkParams(params); + + if (ret) + fs.lstat(p.name, function(error, stat) { + var time, length, range, isGzip, + options = {}; + + if (error) { + sendError(error, params); + } else { + isGzip = isGZIP(p.request) && p.gzip; + time = stat.mtime, + length = stat.size, + range = getRange(p.request, length); + + if (range) + Util.copyObj(p, { + range : range, + status : RANGE + }); + + Util.copyObj(p, { + time : time + }); + + setHeader(params); + + options = { + gzip : isGzip, + range : range + }; + + pipe.create(p.name, p.response, options, function(error) { + if (error) + sendError(error, params); + }); + } + }); + } + + /** + * send error response + */ + function sendError(error, params) { + var data, ret = checkParams(params); + + if (ret) { + params.status = FILE_NOT_FOUND; + data = error.message || '' + error; + + send(data, params); + } + } + + function checkParams(params, additional) { + var ret = Util.checkObjTrue(params, ['name', REQUEST, RESPONSE]); + + if (ret && additional) + ret = Util.checkObjTrue(params, additional); + + return ret; + } + + function getQuery(req) { + var query, parsed; + + if (req) { + parsed = url.parse(req.url); + query = parsed.query; + } + + return query; + } + + function getPathName(req) { + var pathname, parsed; + + if (req) { + parsed = url.parse(req.url); + pathname = parsed.pathname; + /* supporting of Russian language in directory names */ + pathname = querystring.unescape(pathname); + } + + return pathname; + } + + function getRange(req, sizeTotal) { + var range, start, end, size, parts, + rangeStr = req.headers.range; + + if (rangeStr) { + parts = rangeStr.replace(/bytes=/, '').split('-'); + start = parts[0]; + end = parts[1] || sizeTotal - 1; + size = (end - start) + 1; + + range = { + start : start - 0, + end : end - 0, + size : size, + sizeTotal : sizeTotal + }; + } + + return range; + } + + function isGZIP(req) { + var enc, is; + + if (req) { + enc = req.headers['accept-encoding'] || ''; + is = enc.match(/\bgzip\b/); + } + + return is; + } + + /** + * redirect to another URL + */ + function redirect(pParams) { + var p, header, + lRet = Util.checkObjTrue(pParams, [RESPONSE]); + + if (lRet) { + p = pParams; + + header = { + 'Location': p.url + }; + + setHeader(header, p.response); + p.response.statusCode = MOVED_PERMANENTLY; + p.response.end(); + } + } + +})(); diff --git a/lib/server/rest.js b/lib/server/rest.js index 696a962a..24bf2562 100644 --- a/lib/server/rest.js +++ b/lib/server/rest.js @@ -34,6 +34,8 @@ pack = require(DIR + 'pack'), mellow = require(DIR + 'mellow'), format = require(DIR + 'format'), + ponse = require(DIR + 'ponse'), + isWin32 = process.platform === 'win32'; @@ -53,7 +55,7 @@ if (request && response) { apiURL = CloudFunc.apiURL; - name = main.getPathName(request); + name = ponse.getPathName(request); ret = Util.isContainStr(name, apiURL); if (ret) { @@ -74,9 +76,9 @@ params.query = options.query; if (error) - main.sendError(error, params); + ponse.sendError(error, params); else - main.sendResponse(data, params, options.notLog); + ponse.send(data, params, options.notLog); }); } } @@ -93,7 +95,7 @@ */ function sendData(params, callback) { var p, isFS, isMD, - ret = main.checkParams(params); + ret = ponse.checkParams(params); if (ret) { p = params; @@ -128,11 +130,11 @@ function onFS(params, callback) { var p, query, path, - ret = main.checkParams(params); + ret = ponse.checkParams(params); if (ret) { p = params; - query = main.getQuery(p.request); + query = ponse.getQuery(p.request); p.name = Util.rmStrOnce(p.name, CloudFunc.FS) || '/'; path = mellow.convertPath(p.name); @@ -151,7 +153,7 @@ }; if (isFile) { - main.sendFile(params); + ponse.sendFile(params); } else { if (!error) { data.path = format.addSlashToEnd(p.name); @@ -216,7 +218,7 @@ * @param pParams {method, body, requrest, response} */ function onGET(params, callback) { - var p, cmd, json, ret = main.checkParams(params); + var p, cmd, json, ret = ponse.checkParams(params); if (ret) { p = params; @@ -233,7 +235,7 @@ break; case 'config': - main.sendFile({ + ponse.sendFile({ name : JSONDIR + 'config.json', request : p.request, response: p.response, diff --git a/lib/server/rest/markdown.js b/lib/server/rest/markdown.js index 3127eeaf..63363b94 100644 --- a/lib/server/rest/markdown.js +++ b/lib/server/rest/markdown.js @@ -9,7 +9,8 @@ fs = require('fs'), pipe = main.pipe, - mellow = require(DIR_SERVER + 'mellow'); + mellow = require(DIR_SERVER + 'mellow'), + ponse = require(DIR_SERVER + 'ponse'); exports.operate = operate; @@ -22,7 +23,7 @@ switch(method) { case 'GET': name = Util.rmStrOnce(name, '/markdown'); - query = main.getQuery(request); + query = ponse.getQuery(request); if (query === 'relative') name = DIR + name;