X-Git-Url: https://git.josue.xyz/?p=VSoRC%2F.git;a=blobdiff_plain;f=node_modules%2Fnode-static%2Flib%2Fnode-static.js;fp=node_modules%2Fnode-static%2Flib%2Fnode-static.js;h=0000000000000000000000000000000000000000;hp=15d814420beb9bfd8d29129a9e3110b945f9522b;hb=5e96dd57ddd883604e87f62bdddcb111c63a6e1a;hpb=acb5f682a2b75b972710cabd81658f63071324b0 diff --git a/node_modules/node-static/lib/node-static.js b/node_modules/node-static/lib/node-static.js deleted file mode 100644 index 15d8144..0000000 --- a/node_modules/node-static/lib/node-static.js +++ /dev/null @@ -1,393 +0,0 @@ -var fs = require('fs') - , events = require('events') - , buffer = require('buffer') - , http = require('http') - , url = require('url') - , path = require('path') - , mime = require('mime') - , util = require('./node-static/util'); - -// Current version -var version = [0, 7, 9]; - -var Server = function (root, options) { - if (root && (typeof(root) === 'object')) { options = root; root = null } - - // resolve() doesn't normalize (to lowercase) drive letters on Windows - this.root = path.normalize(path.resolve(root || '.')); - this.options = options || {}; - this.cache = 3600; - - this.defaultHeaders = {}; - this.options.headers = this.options.headers || {}; - - this.options.indexFile = this.options.indexFile || "index.html"; - - if ('cache' in this.options) { - if (typeof(this.options.cache) === 'number') { - this.cache = this.options.cache; - } else if (! this.options.cache) { - this.cache = false; - } - } - - if ('serverInfo' in this.options) { - this.serverInfo = this.options.serverInfo.toString(); - } else { - this.serverInfo = 'node-static/' + version.join('.'); - } - - this.defaultHeaders['server'] = this.serverInfo; - - if (this.cache !== false) { - this.defaultHeaders['cache-control'] = 'max-age=' + this.cache; - } - - for (var k in this.defaultHeaders) { - this.options.headers[k] = this.options.headers[k] || - this.defaultHeaders[k]; - } -}; - -Server.prototype.serveDir = function (pathname, req, res, finish) { - var htmlIndex = path.join(pathname, this.options.indexFile), - that = this; - - fs.stat(htmlIndex, function (e, stat) { - if (!e) { - var status = 200; - var headers = {}; - var originalPathname = decodeURI(url.parse(req.url).pathname); - if (originalPathname.length && originalPathname.charAt(originalPathname.length - 1) !== '/') { - return finish(301, { 'Location': originalPathname + '/' }); - } else { - that.respond(null, status, headers, [htmlIndex], stat, req, res, finish); - } - } else { - // Stream a directory of files as a single file. - fs.readFile(path.join(pathname, 'index.json'), function (e, contents) { - if (e) { return finish(404, {}) } - var index = JSON.parse(contents); - streamFiles(index.files); - }); - } - }); - function streamFiles(files) { - util.mstat(pathname, files, function (e, stat) { - if (e) { return finish(404, {}) } - that.respond(pathname, 200, {}, files, stat, req, res, finish); - }); - } -}; - -Server.prototype.serveFile = function (pathname, status, headers, req, res) { - var that = this; - var promise = new(events.EventEmitter); - - pathname = this.resolve(pathname); - - fs.stat(pathname, function (e, stat) { - if (e) { - return promise.emit('error', e); - } - that.respond(null, status, headers, [pathname], stat, req, res, function (status, headers) { - that.finish(status, headers, req, res, promise); - }); - }); - return promise; -}; - -Server.prototype.finish = function (status, headers, req, res, promise, callback) { - var result = { - status: status, - headers: headers, - message: http.STATUS_CODES[status] - }; - - headers['server'] = this.serverInfo; - - if (!status || status >= 400) { - if (callback) { - callback(result); - } else { - if (promise.listeners('error').length > 0) { - promise.emit('error', result); - } - else { - res.writeHead(status, headers); - res.end(); - } - } - } else { - // Don't end the request here, if we're streaming; - // it's taken care of in `prototype.stream`. - if (status !== 200 || req.method !== 'GET') { - res.writeHead(status, headers); - res.end(); - } - callback && callback(null, result); - promise.emit('success', result); - } -}; - -Server.prototype.servePath = function (pathname, status, headers, req, res, finish) { - var that = this, - promise = new(events.EventEmitter); - - pathname = this.resolve(pathname); - - // Make sure we're not trying to access a - // file outside of the root. - if (pathname.indexOf(that.root) === 0) { - fs.stat(pathname, function (e, stat) { - if (e) { - finish(404, {}); - } else if (stat.isFile()) { // Stream a single file. - that.respond(null, status, headers, [pathname], stat, req, res, finish); - } else if (stat.isDirectory()) { // Stream a directory of files. - that.serveDir(pathname, req, res, finish); - } else { - finish(400, {}); - } - }); - } else { - // Forbidden - finish(403, {}); - } - return promise; -}; - -Server.prototype.resolve = function (pathname) { - return path.resolve(path.join(this.root, pathname)); -}; - -Server.prototype.serve = function (req, res, callback) { - var that = this, - promise = new(events.EventEmitter), - pathname; - - var finish = function (status, headers) { - that.finish(status, headers, req, res, promise, callback); - }; - - try { - pathname = decodeURI(url.parse(req.url).pathname); - } - catch(e) { - return process.nextTick(function() { - return finish(400, {}); - }); - } - - process.nextTick(function () { - that.servePath(pathname, 200, {}, req, res, finish).on('success', function (result) { - promise.emit('success', result); - }).on('error', function (err) { - promise.emit('error'); - }); - }); - if (! callback) { return promise } -}; - -/* Check if we should consider sending a gzip version of the file based on the - * file content type and client's Accept-Encoding header value. - */ -Server.prototype.gzipOk = function (req, contentType) { - var enable = this.options.gzip; - if(enable && - (typeof enable === 'boolean' || - (contentType && (enable instanceof RegExp) && enable.test(contentType)))) { - var acceptEncoding = req.headers['accept-encoding']; - return acceptEncoding && acceptEncoding.indexOf("gzip") >= 0; - } - return false; -} - -/* Send a gzipped version of the file if the options and the client indicate gzip is enabled and - * we find a .gz file mathing the static resource requested. - */ -Server.prototype.respondGzip = function (pathname, status, contentType, _headers, files, stat, req, res, finish) { - var that = this; - if (files.length == 1 && this.gzipOk(req, contentType)) { - var gzFile = files[0] + ".gz"; - fs.stat(gzFile, function (e, gzStat) { - if (!e && gzStat.isFile()) { - var vary = _headers['Vary']; - _headers['Vary'] = (vary && vary != 'Accept-Encoding' ? vary + ', ' : '') + 'Accept-Encoding'; - _headers['Content-Encoding'] = 'gzip'; - stat.size = gzStat.size; - files = [gzFile]; - } - that.respondNoGzip(pathname, status, contentType, _headers, files, stat, req, res, finish); - }); - } else { - // Client doesn't want gzip or we're sending multiple files - that.respondNoGzip(pathname, status, contentType, _headers, files, stat, req, res, finish); - } -} - -Server.prototype.parseByteRange = function (req, stat) { - var byteRange = { - from: 0, - to: 0, - valid: false - } - - var rangeHeader = req.headers['range']; - var flavor = 'bytes='; - - if (rangeHeader) { - if (rangeHeader.indexOf(flavor) == 0 && rangeHeader.indexOf(',') == -1) { - /* Parse */ - rangeHeader = rangeHeader.substr(flavor.length).split('-'); - byteRange.from = parseInt(rangeHeader[0]); - byteRange.to = parseInt(rangeHeader[1]); - - /* Replace empty fields of differential requests by absolute values */ - if (isNaN(byteRange.from) && !isNaN(byteRange.to)) { - byteRange.from = stat.size - byteRange.to; - byteRange.to = stat.size ? stat.size - 1 : 0; - } else if (!isNaN(byteRange.from) && isNaN(byteRange.to)) { - byteRange.to = stat.size ? stat.size - 1 : 0; - } - - /* General byte range validation */ - if (!isNaN(byteRange.from) && !!byteRange.to && 0 <= byteRange.from && byteRange.from < byteRange.to) { - byteRange.valid = true; - } else { - console.warn("Request contains invalid range header: ", rangeHeader); - } - } else { - console.warn("Request contains unsupported range header: ", rangeHeader); - } - } - return byteRange; -} - -Server.prototype.respondNoGzip = function (pathname, status, contentType, _headers, files, stat, req, res, finish) { - var mtime = Date.parse(stat.mtime), - key = pathname || files[0], - headers = {}, - clientETag = req.headers['if-none-match'], - clientMTime = Date.parse(req.headers['if-modified-since']), - startByte = 0, - length = stat.size, - byteRange = this.parseByteRange(req, stat); - - /* Handle byte ranges */ - if (files.length == 1 && byteRange.valid) { - if (byteRange.to < length) { - - // Note: HTTP Range param is inclusive - startByte = byteRange.from; - length = byteRange.to - byteRange.from + 1; - status = 206; - - // Set Content-Range response header (we advertise initial resource size on server here (stat.size)) - headers['Content-Range'] = 'bytes ' + byteRange.from + '-' + byteRange.to + '/' + stat.size; - - } else { - byteRange.valid = false; - console.warn("Range request exceeds file boundaries, goes until byte no", byteRange.to, "against file size of", length, "bytes"); - } - } - - /* In any case, check for unhandled byte range headers */ - if (!byteRange.valid && req.headers['range']) { - console.error(new Error("Range request present but invalid, might serve whole file instead")); - } - - // Copy default headers - for (var k in this.options.headers) { headers[k] = this.options.headers[k] } - // Copy custom headers - for (var k in _headers) { headers[k] = _headers[k] } - - headers['Etag'] = JSON.stringify([stat.ino, stat.size, mtime].join('-')); - headers['Date'] = new(Date)().toUTCString(); - headers['Last-Modified'] = new(Date)(stat.mtime).toUTCString(); - headers['Content-Type'] = contentType; - headers['Content-Length'] = length; - - for (var k in _headers) { headers[k] = _headers[k] } - - // Conditional GET - // If the "If-Modified-Since" or "If-None-Match" headers - // match the conditions, send a 304 Not Modified. - if ((clientMTime || clientETag) && - (!clientETag || clientETag === headers['Etag']) && - (!clientMTime || clientMTime >= mtime)) { - // 304 response should not contain entity headers - ['Content-Encoding', - 'Content-Language', - 'Content-Length', - 'Content-Location', - 'Content-MD5', - 'Content-Range', - 'Content-Type', - 'Expires', - 'Last-Modified'].forEach(function (entityHeader) { - delete headers[entityHeader]; - }); - finish(304, headers); - } else { - res.writeHead(status, headers); - - this.stream(key, files, length, startByte, res, function (e) { - if (e) { return finish(500, {}) } - finish(status, headers); - }); - } -}; - -Server.prototype.respond = function (pathname, status, _headers, files, stat, req, res, finish) { - var contentType = _headers['Content-Type'] || - mime.lookup(files[0]) || - 'application/octet-stream'; - - if(this.options.gzip) { - this.respondGzip(pathname, status, contentType, _headers, files, stat, req, res, finish); - } else { - this.respondNoGzip(pathname, status, contentType, _headers, files, stat, req, res, finish); - } -} - -Server.prototype.stream = function (pathname, files, length, startByte, res, callback) { - - (function streamFile(files, offset) { - var file = files.shift(); - - if (file) { - file = path.resolve(file) === path.normalize(file) ? file : path.join(pathname || '.', file); - - // Stream the file to the client - fs.createReadStream(file, { - flags: 'r', - mode: 0666, - start: startByte, - end: startByte + (length ? length - 1 : 0) - }).on('data', function (chunk) { - // Bounds check the incoming chunk and offset, as copying - // a buffer from an invalid offset will throw an error and crash - if (chunk.length && offset < length && offset >= 0) { - offset += chunk.length; - } - }).on('close', function () { - streamFile(files, offset); - }).on('error', function (err) { - callback(err); - console.error(err); - }).pipe(res, { end: false }); - } else { - res.end(); - callback(null, offset); - } - })(files.slice(0), 0); -}; - -// Exports -exports.Server = Server; -exports.version = version; -exports.mime = mime; - - -