diff options
Diffstat (limited to 'node_modules/@shellscape/koa-send/legacy/index.js')
| -rw-r--r-- | node_modules/@shellscape/koa-send/legacy/index.js | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/node_modules/@shellscape/koa-send/legacy/index.js b/node_modules/@shellscape/koa-send/legacy/index.js new file mode 100644 index 00000000..043c1dd6 --- /dev/null +++ b/node_modules/@shellscape/koa-send/legacy/index.js @@ -0,0 +1,190 @@ +function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _next(value) { step("next", value); } function _throw(err) { step("throw", err); } _next(); }); }; } + +/** + * Module dependencies. + */ +const debug = require('debug')('koa-send'); + +const resolvePath = require('resolve-path'); + +const createError = require('http-errors'); + +const assert = require('assert'); + +const fs = require('mz/fs'); + +const { + normalize, + basename, + extname, + resolve, + parse, + sep +} = require('path'); +/** + * Expose `send()`. + */ + + +module.exports = send; +/** + * Send file at `path` with the + * given `options` to the koa `ctx`. + * + * @param {Context} ctx + * @param {String} path + * @param {Object} [opts] + * @return {Function} + * @api public + */ + +function send(_x, _x2) { + return _send.apply(this, arguments); +} +/** + * Check if it's hidden. + */ + + +function _send() { + _send = _asyncToGenerator(function* (ctx, path, opts = {}) { + assert(ctx, 'koa context required'); + assert(path, 'pathname required'); // options + + debug('send "%s" %j', path, opts); + const root = opts.root ? normalize(resolve(opts.root)) : ''; + const trailingSlash = path[path.length - 1] === '/'; + path = path.substr(parse(path).root.length); + const index = opts.index; + const maxage = opts.maxage || opts.maxAge || 0; + const immutable = opts.immutable || false; + const hidden = opts.hidden || false; + const format = opts.format !== false; + const extensions = Array.isArray(opts.extensions) ? opts.extensions : false; + const brotli = opts.brotli !== false; + const gzip = opts.gzip !== false; + const setHeaders = opts.setHeaders; + + if (setHeaders && typeof setHeaders !== 'function') { + throw new TypeError('option setHeaders must be function'); + } // normalize path + + + path = decode(path); + if (path === -1) return ctx.throw(400, 'failed to decode'); // index file support + + if (index && trailingSlash) path += index; + path = resolvePath(root, path); // hidden file support, ignore + + if (!hidden && isHidden(root, path)) return; + let encodingExt = ''; // serve brotli file when possible otherwise gzipped file when possible + + if (ctx.acceptsEncodings('br', 'identity') === 'br' && brotli && (yield fs.exists(path + '.br'))) { + path = path + '.br'; + ctx.set('Content-Encoding', 'br'); + ctx.res.removeHeader('Content-Length'); + encodingExt = '.br'; + } else if (ctx.acceptsEncodings('gzip', 'identity') === 'gzip' && gzip && (yield fs.exists(path + '.gz'))) { + path = path + '.gz'; + ctx.set('Content-Encoding', 'gzip'); + ctx.res.removeHeader('Content-Length'); + encodingExt = '.gz'; + } + + if (extensions && !/\.[^/]*$/.exec(path)) { + const list = [].concat(extensions); + + for (let i = 0; i < list.length; i++) { + let ext = list[i]; + + if (typeof ext !== 'string') { + throw new TypeError('option extensions must be array of strings or false'); + } + + if (!/^\./.exec(ext)) ext = '.' + ext; + + if (yield fs.exists(path + ext)) { + path = path + ext; + break; + } + } + } // stat + + + let stats; + + try { + stats = yield fs.stat(path); // Format the path to serve static file servers + // and not require a trailing slash for directories, + // so that you can do both `/directory` and `/directory/` + + if (stats.isDirectory()) { + if (format && index) { + path += '/' + index; + stats = yield fs.stat(path); + } else { + return; + } + } + } catch (err) { + const notfound = ['ENOENT', 'ENAMETOOLONG', 'ENOTDIR']; + + if (notfound.includes(err.code)) { + throw createError(404, err); + } + + err.status = 500; + throw err; + } + + if (setHeaders) setHeaders(ctx.res, path, stats); // stream + + ctx.set('Content-Length', stats.size); + if (!ctx.response.get('Last-Modified')) ctx.set('Last-Modified', stats.mtime.toUTCString()); + + if (!ctx.response.get('Cache-Control')) { + const directives = ['max-age=' + (maxage / 1000 | 0)]; + + if (immutable) { + directives.push('immutable'); + } + + ctx.set('Cache-Control', directives.join(',')); + } + + ctx.type = type(path, encodingExt); + ctx.body = fs.createReadStream(path); + return path; + }); + return _send.apply(this, arguments); +} + +function isHidden(root, path) { + path = path.substr(root.length).split(sep); + + for (let i = 0; i < path.length; i++) { + if (path[i][0] === '.') return true; + } + + return false; +} +/** + * File type. + */ + + +function type(file, ext) { + return ext !== '' ? extname(basename(file, ext)) : extname(file); +} +/** + * Decode `path`. + */ + + +function decode(path) { + try { + return decodeURIComponent(path); + } catch (err) { + return -1; + } +} |
