diff --git a/src/application.js b/src/application.js index edb35d0..0b58f90 100644 --- a/src/application.js +++ b/src/application.js @@ -17,20 +17,20 @@ limitations under the License. const uWS = require("uWebSockets.js"); const Router = require("./router.js"); const { removeDuplicateSlashes, defaultSettings, compileTrust, createETagGenerator, fastQueryParse, NullObject } = require("./utils.js"); -const querystring = require("fast-querystring"); +const { parse } = require("fast-querystring"); const ViewClass = require("./view.js"); -const path = require("path"); -const os = require("os"); +const { join, resolve } = require("path"); +const { cpus } = require("os"); const { Worker } = require("worker_threads"); -const cpuCount = os.cpus().length; +const cpuCount = cpus().length; let workers = []; let taskKey = 0; const workerTasks = new NullObject(); function createWorker() { - const worker = new Worker(path.join(__dirname, 'worker.js')); + const worker = new Worker(join(__dirname, 'worker.js')); workers.push(worker); worker.on('message', (message) => { @@ -87,7 +87,7 @@ class Application extends Router { } } this.set('view', ViewClass); - this.set('views', path.resolve('views')); + this.set('views', resolve('views')); } createWorkerTask(resolve, reject) { @@ -118,7 +118,7 @@ class Application extends Router { if(value === 'extended') { this.settings['query parser fn'] = fastQueryParse; } else if(value === 'simple') { - this.settings['query parser fn'] = querystring.parse; + this.settings['query parser fn'] = parse; } else if(typeof value === 'function') { this.settings['query parser fn'] = value; } else { @@ -131,7 +131,7 @@ class Application extends Router { this.settings['view cache'] = undefined; } } else if(key === 'views') { - this.settings[key] = path.resolve(value); + this.settings[key] = resolve(value); return this; } else if(key === 'etag') { if(typeof value === 'function') { diff --git a/src/declarative.js b/src/declarative.js index 5678878..524cd25 100644 --- a/src/declarative.js +++ b/src/declarative.js @@ -1,8 +1,8 @@ -const acorn = require("acorn"); +const { tokenizer, Parser } = require("acorn"); const { stringify } = require("./utils.js"); const uWS = require("uWebSockets.js"); -const parser = acorn.Parser; +const parser = Parser; const allowedResMethods = ['set', 'header', 'setHeader', 'status', 'send', 'end', 'append']; const allowedIdentifiers = ['query', 'params', ...allowedResMethods]; @@ -29,7 +29,7 @@ module.exports = function compileDeclarative(cb, app) { code = code.replace(/function *\(/, "function __cb("); } - const tokens = [...acorn.tokenizer(code, { ecmaVersion: "latest" })]; + const tokens = [...tokenizer(code, { ecmaVersion: "latest" })]; if(tokens.some(token => ['throw', 'new', 'await'].includes(token.value))) { return false; diff --git a/src/middlewares.js b/src/middlewares.js index d889176..b16a1b1 100644 --- a/src/middlewares.js +++ b/src/middlewares.js @@ -14,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -const fs = require('fs'); -const path = require('path'); +const { statSync } = require('fs'); +const { resolve, join, extname } = require('path'); const bytes = require('bytes'); -const zlib = require('fast-zlib'); +const { Inflate, Gunzip, BrotliDecompress } = require('fast-zlib'); const typeis = require('type-is'); -const querystring = require('fast-querystring'); +const { parse } = require('fast-querystring'); const { fastQueryParse, NullObject } = require('./utils.js'); function static(root, options) { @@ -51,8 +51,8 @@ function static(root, options) { } else return next(); } let _path = url; - let fullpath = path.resolve(path.join(options.root, url)); - if(options.root && !fullpath.startsWith(path.resolve(options.root))) { + let fullpath = resolve(join(options.root, url)); + if(options.root && !fullpath.startsWith(resolve(options.root))) { if(!options.fallthrough) { res.status(403); return next(new Error('Forbidden')); @@ -61,14 +61,14 @@ function static(root, options) { let stat; try { - stat = fs.statSync(fullpath); + stat = statSync(fullpath); } catch(err) { - const ext = path.extname(fullpath); + const ext = extname(fullpath); let i = 0; if(ext === '' && options.extensions) { while(i < options.extensions.length) { try { - stat = fs.statSync(fullpath + '.' + options.extensions[i]); + stat = statSync(fullpath + '.' + options.extensions[i]); _path = url + '.' + options.extensions[i]; break; } catch(err) { @@ -96,8 +96,8 @@ function static(root, options) { } if(options.index) { try { - stat = fs.statSync(path.join(fullpath, options.index)); - _path = path.join(url, options.index); + stat = statSync(join(fullpath, options.index)); + _path = join(url, options.index); } catch(err) { if(!options.fallthrough) { res.status(404); @@ -126,11 +126,11 @@ function createInflate(contentEncoding) { case 'identity': return; case 'deflate': - return new zlib.Inflate(); + return new Inflate(); case 'gzip': - return new zlib.Gunzip(); + return new Gunzip(); case 'br': - return new zlib.BrotliDecompress(); + return new BrotliDecompress(); default: return false; } @@ -320,7 +320,7 @@ const urlencoded = createBodyParser('application/x-www-form-urlencoded', functio if(options.extended) { req.body = fastQueryParse(buf.toString(), options); } else { - req.body = querystring.parse(buf.toString()); + req.body = parse(buf.toString()); } } catch(e) { return next(e); diff --git a/src/response.js b/src/response.js index 39ae1d8..0022573 100644 --- a/src/response.js +++ b/src/response.js @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -const cookie = require("cookie"); -const mime = require("mime-types"); +const { serialize } = require("cookie"); +const { lookup, contentType } = require("mime-types"); const vary = require("vary"); const encodeUrl = require("encodeurl"); const { @@ -24,18 +24,18 @@ const { } = require("./utils.js"); const { Writable } = require("stream"); const { isAbsolute } = require("path"); -const fs = require("fs"); -const Path = require("path"); -const statuses = require("statuses"); +const { statSync, createReadStream } = require("fs"); +const { normalize, sep, resolve, join, basename } = require("path"); +const { message } = require("statuses"); const { sign } = require("cookie-signature"); // events is faster at init, tseep is faster at sending events // since we create a ton of objects and dont send a ton of events, its better to use events here const { EventEmitter } = require("events"); -const http = require("http"); +const { OutgoingMessage } = require("http"); const ms = require('ms'); const etag = require("etag"); -const outgoingMessage = new http.OutgoingMessage(); +const outgoingMessage = new OutgoingMessage(); const symbols = Object.getOwnPropertySymbols(outgoingMessage); const kOutHeaders = symbols.find(s => s.toString() === 'Symbol(kOutHeaders)'); @@ -217,7 +217,7 @@ module.exports = class Response extends Writable { return this; } sendStatus(code) { - return this.status(code).send(statuses.message[+code] ?? code.toString()); + return this.status(code).send(message[+code] ?? code.toString()); } end(data) { if(this.finished) { @@ -350,9 +350,9 @@ module.exports = class Response extends Writable { this.status(403); return done(new Error('Forbidden')); } - const parts = Path.normalize(path).split(Path.sep); - const fullpath = options.root ? Path.resolve(Path.join(options.root, path)) : path; - if(options.root && !fullpath.startsWith(Path.resolve(options.root))) { + const parts = normalize(path).split(sep); + const fullpath = options.root ? resolve(join(options.root, path)) : path; + if(options.root && !fullpath.startsWith(resolve(options.root))) { this.status(403); return done(new Error('Forbidden')); } @@ -382,7 +382,7 @@ module.exports = class Response extends Writable { let stat = options._stat; if(!stat) { try { - stat = fs.statSync(fullpath); + stat = statSync(fullpath); } catch(err) { return done(err); } @@ -394,7 +394,7 @@ module.exports = class Response extends Writable { // headers if(!this.headers['content-type']) { - const m = mime.lookup(fullpath); + const m = lookup(fullpath); if(m) this.type(m); else this.type('application/octet-stream'); } @@ -487,7 +487,7 @@ module.exports = class Response extends Writable { opts.start = offset; opts.end = Math.max(offset, offset + len - 1); } - const file = fs.createReadStream(fullpath, opts); + const file = createReadStream(fullpath, opts); pipeStreamOverResponse(this, file, len, callback); } } @@ -513,7 +513,7 @@ module.exports = class Response extends Writable { opts = filename; } if(!name) { - name = Path.basename(path); + name = basename(path); } if(!opts.root && !isAbsolute(path)) { opts.root = process.cwd(); @@ -616,7 +616,7 @@ module.exports = class Response extends Writable { options.path = '/'; } - this.append('Set-Cookie', cookie.serialize(name, val, options)); + this.append('Set-Cookie', serialize(name, val, options)); return this; } clearCookie(name, options) { @@ -704,12 +704,12 @@ module.exports = class Response extends Writable { this.location(url); this.status(status); this.headers['content-type'] = 'text/plain; charset=utf-8'; - return this.send(`${statuses.message[status] ?? status}. Redirecting to ${url}`); + return this.send(`${message[status] ?? status}. Redirecting to ${url}`); } type(type) { let ct = type.indexOf('/') === -1 - ? (mime.contentType(type) || 'application/octet-stream') + ? (contentType(type) || 'application/octet-stream') : type; return this.set('content-type', ct); diff --git a/src/utils.js b/src/utils.js index 056a52a..0e76d78 100644 --- a/src/utils.js +++ b/src/utils.js @@ -14,11 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -const mime = require("mime-types"); -const path = require("path"); -const proxyaddr = require("proxy-addr"); -const qs = require("qs"); -const querystring = require("fast-querystring"); +const { lookup } = require("mime-types"); +const { join } = require("path"); +const { compile } = require("proxy-addr"); +const parseQs = require("qs").parse; +const parseFqs = require("fast-querystring").parse; const etag = require("etag"); const { Stats } = require("fs"); @@ -32,11 +32,11 @@ function fastQueryParse(query, options) { if(len <= 128) { if(!query.includes('[') && !query.includes('%5B') && !query.includes('.') && !query.includes('%2E')) { // [Object: null prototype] issue - return {...querystring.parse(query)}; + return {...parseFqs(query)}; } } // [Object: null prototype] issue - return {...qs.parse(query, options)}; + return {...parseQs(query, options)}; } function removeDuplicateSlashes(path) { @@ -141,7 +141,7 @@ function acceptParams(str) { function normalizeType(type) { return ~type.indexOf('/') ? acceptParams(type) : - { value: (mime.lookup(type) || 'application/octet-stream'), params: {} }; + { value: (lookup(type) || 'application/octet-stream'), params: {} }; } function stringify(value, replacer, spaces, escape) { @@ -176,7 +176,7 @@ const defaultSettings = { 'query parser fn': () => fastQueryParse, 'subdomain offset': 2, 'trust proxy': false, - 'views': () => path.join(process.cwd(), 'views'), + 'views': () => join(process.cwd(), 'views'), 'view cache': () => process.env.NODE_ENV === 'production', 'x-powered-by': true, 'case sensitive routing': true, @@ -202,7 +202,7 @@ function compileTrust(val) { .map(function (v) { return v.trim() }) } - return proxyaddr.compile(val || []); + return compile(val || []); } const shownWarnings = new Set(); diff --git a/src/worker.js b/src/worker.js index 705f72c..c8ff170 100644 --- a/src/worker.js +++ b/src/worker.js @@ -14,13 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -const fs = require("fs"); +const { readFileSync } = require("fs"); const { parentPort } = require("worker_threads"); parentPort.on('message', (message) => { if(message.type === 'readFile') { try { - const data = fs.readFileSync(message.path); + const data = readFileSync(message.path); const ab = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength); parentPort.postMessage({ key: message.key, data: ab }, [ab]); } catch(err) {