ultimate-express
Version:
The Ultimate Express. Fastest http server with full Express compatibility, based on uWebSockets.
464 lines (416 loc) • 19.3 kB
JavaScript
const acorn = require("acorn");
const { stringify } = require("./utils.js");
const uWS = require("uWebSockets.js");
const parser = acorn.Parser;
const allowedResMethods = ['set', 'header', 'setHeader', 'status', 'send', 'end', 'append'];
const allowedIdentifiers = ['query', 'params', ...allowedResMethods];
const objKeyRegex = /[\s{\n]([A-Za-z-0-9_]+)(\s|\n)*?:/g;
function replaceSingleCharacter(str, index, char) {
return str.slice(0, index) + char + str.slice(index + 1);
}
// generates a declarative response from a callback
// uWS allows creating such responses and they are extremely fast
// since you don't even have to call into Node.js at all
// declarative response will only be created if callback is 'simple enough'
// simple enough means:
// - doesnt call external functions
// - doesnt create variables
// - only uses req.query and req.params
// basically, its only simple, static responses
module.exports = function compileDeclarative(cb, app) {
try {
let code = cb.toString();
// convert anonymous functions to named ones to make it valid code
if(code.startsWith("function") || code.startsWith("async function")) {
code = code.replace(/function *\(/, "function __cb(");
}
const tokens = [...acorn.tokenizer(code, { ecmaVersion: "latest" })];
if(tokens.some(token => ['throw', 'new', 'await', 'return'].includes(token.value))) {
return false;
}
const parsed = parser.parse(code, { ecmaVersion: "latest" }).body;
let fn = parsed[0];
if(fn.type === 'ExpressionStatement') {
fn = fn.expression;
}
// check if it is a function
if (fn.type !== 'FunctionDeclaration' && fn.type !== 'ArrowFunctionExpression') {
return false;
}
const args = fn.params.map(param => param.name);
if(args.length < 2) {
// invalid function? doesn't have (req, res) args
return false;
}
const [req, res] = args;
let queryName, paramsName, queries = [], params = [];
if(fn.params[0].type === 'ObjectPattern') {
let query = fn.params[0].properties.find(prop => prop.key.name === 'query');
let param = fn.params[0].properties.find(prop => prop.key.name === 'params');
if(query?.value?.type === 'Identifier') {
queryName = query.value.name;
} else if(query?.value?.type === 'ObjectPattern') {
for(let prop of query.value.properties) {
if(prop.value.type !== 'Identifier') {
return false;
}
queries.push(prop.value.name);
}
} else {
return false;
}
if(param?.value?.type === 'Identifier') {
paramsName = param.value.name;
} else if(param?.value?.type === 'ObjectPattern') {
for(let prop of param.value.properties) {
if(prop.value.type !== 'Identifier') {
return false;
}
params.push(prop.value.name);
}
} else {
return false;
}
}
// check if it calls any other function other than the one in `res`
const callExprs = filterNodes(fn, node => node.type === 'CallExpression');
const resCalls = [];
for(let expr of callExprs) {
let calleeName, propertyName;
// get propertyName
if(expr.type === 'MemberExpression') {
propertyName = expr.property.name;
} else if(expr.type === 'CallExpression') {
propertyName = expr.callee?.property?.name ?? expr.callee?.name;
}
// get calleeName
switch(expr.callee.type) {
case "Identifier":
calleeName = expr.callee.name;
break;
case "MemberExpression":
if(expr.callee.object.type === 'Identifier') {
calleeName = expr.callee.object.name;
} else if(expr.callee.object.type === 'CallExpression') {
// function call chaining
let callee = expr.callee;
while(callee.object.callee) {
callee = callee.object.callee;
}
if(callee.object.type !== 'Identifier') {
return false;
}
calleeName = callee.object.name;
}
break;
default:
return false;
}
// check if calleeName is res
if(calleeName !== res) {
return false;
}
const obj = { calleeName, propertyName };
expr.obj = obj;
resCalls.push(obj);
}
// check if res property being called are
// - set, header, setHeader
// - status
// - send
// - end
for(let call of resCalls) {
if(!allowedResMethods.includes(call.propertyName)) {
return false;
}
}
// check if all identifiers are allowed
const identifiers = filterNodes(fn, node => node.type === 'Identifier').slice(args.length).map(id => id.name);
if(identifiers[identifiers.length - 1] === '__cb') {
identifiers.pop();
}
if(!identifiers.every((id, i) =>
allowedIdentifiers.includes(id) ||
id === req ||
id === res ||
(identifiers[i - 2] === req && identifiers[i - 1] === 'params') ||
(identifiers[i - 2] === req && identifiers[i - 1] === 'query') ||
id === queryName ||
id === paramsName ||
queries.includes(id) ||
params.includes(id)
)) {
return false;
}
let statusCode = 200;
const headers = [];
const body = [];
// get statusCode
for(let call of callExprs) {
if(call.obj.propertyName === 'status') {
if(call.arguments[0].type !== 'Literal') {
return false;
}
statusCode = call.arguments[0].value;
}
}
// get headers
for(let call of callExprs) {
if(call.obj.propertyName === 'header' || call.obj.propertyName === 'setHeader' || call.obj.propertyName === 'set') {
if(call.arguments[0].type !== 'Literal' || call.arguments[1].type !== 'Literal') {
return false;
}
const sameHeader = headers.find(header => header[0].toLowerCase() === call.arguments[0].value.toLowerCase());
let [header, value] = [call.arguments[0].value, call.arguments[1].value];
if(call.obj.propertyName !== 'setHeader') {
if(value.includes('text/') && !value.includes('; charset=')) {
value += '; charset=utf-8';
}
}
if(sameHeader) {
sameHeader[1] = value;
} else {
headers.push([header, value]);
}
} else if(call.obj.propertyName === 'append') {
if(call.arguments[0].type !== 'Literal' || call.arguments[1].type !== 'Literal') {
return false;
}
headers.push([call.arguments[0].value, call.arguments[1].value]);
}
}
// get body
let sendUsed = false;
for(let call of callExprs) {
if(call.obj.propertyName === 'send' || call.obj.propertyName === 'end') {
if(sendUsed) {
return false;
}
if(call.obj.propertyName === 'send') {
const index = headers.findIndex(header => header[0].toLowerCase() === 'content-type');
if(index === -1) {
headers.push(['content-type', 'text/html; charset=utf-8']);
} else {
if(headers[index][1].includes('text/') && !headers[index][1].includes('; charset=')) {
headers[index][1] += '; charset=utf-8';
}
}
}
const arg = call.arguments[0];
if(arg) {
if(arg.type === 'Literal') {
if(typeof arg.value === 'number') { // status code
return false;
}
let val = arg.value;
if(val === null) {
val = '';
const index = headers.findIndex(header => header[0].toLowerCase() === 'content-type');
if(index !== -1) {
headers.splice(index, 1);
}
}
if(typeof val === 'boolean') {
if(!headers.some(header => header[0].toLowerCase() === 'content-type')) {
headers.push(['content-type', 'application/json; charset=utf-8']);
} else {
headers.find(header => header[0].toLowerCase() === 'content-type')[1] = 'application/json; charset=utf-8';
}
}
body.push({type: 'text', value: val});
} else if(arg.type === 'TemplateLiteral') {
const exprs = [...arg.quasis, ...arg.expressions].sort((a, b) => a.start - b.start);
for(let expr of exprs) {
if(expr.type === 'TemplateElement') {
body.push({type: 'text', value: expr.value.cooked});
} else if(expr.type === 'MemberExpression') {
const obj = expr.object;
let type;
if(obj.type === 'MemberExpression') {
if(obj.property.type !== 'Identifier') {
return false;
}
type = obj.property.name;
} else if(obj.type === 'Identifier') {
type = obj.name;
} else {
return false;
}
if(type !== 'params' && type !== 'query') {
return false;
}
body.push({type, value: expr.property.name});
} else if(expr.type === 'Identifier') {
if(queries.includes(expr.name)) {
body.push({type: 'query', value: expr.name});
} else if(params.includes(expr.name)) {
body.push({type: 'params', value: expr.name});
} else {
return false;
}
} else {
return false;
}
}
} else if(arg.type === 'MemberExpression') {
if(!arg.object.property) {
return false;
}
if(arg.object.property.type !== 'Identifier' || (arg.object.property.name !== 'query' && arg.object.property.name !== 'params')) {
return false;
}
body.push({type: arg.object.property.name, value: arg.property.name});
} else if(arg.type === 'BinaryExpression') {
let stuff = [];
function check(node) {
if(node.right.type === 'Literal') {
stuff.push({type: 'text', value: node.right.value});
} else if(node.right.type === 'MemberExpression') {
stuff.push({type: node.right.object.property.name, value: node.right.property.name});
} else return false;
if(node.left.type === 'Literal') {
stuff.push({type: 'text', value: node.left.value});
} else if(node.left.type === 'MemberExpression') {
stuff.push({type: node.left.object.property.name, value: node.left.property.name});
} else if(node.left.type === 'BinaryExpression') {
return check(node.left);
} else return false;
return true;
}
if(!check(arg)) {
return false;
}
body.push(...stuff.reverse());
} else if(arg.type === 'ObjectExpression') {
if(call.obj.propertyName === 'end') {
return false;
}
// only simple objects can be optimized
let objCode = code;
for(let property of arg.properties) {
if(property.key.type !== 'Identifier' && property.key.type !== 'Literal') {
return false;
}
if(property.value.raw.startsWith("'") && property.value.raw.endsWith("'") && !property.value.value.includes("'")) {
objCode = replaceSingleCharacter(objCode, property.value.start, '"');
objCode = replaceSingleCharacter(objCode, property.value.end - 1, '"');
}
if(property.value.type !== 'Literal') {
return false;
}
}
if(typeof app.get('json replacer') !== 'undefined' && typeof app.get('json replacer') !== 'string') {
return false;
}
if(!headers.some(header => header[0].toLowerCase() === 'content-type')) {
headers.push(['content-type', 'application/json; charset=utf-8']);
} else {
headers.find(header => header[0].toLowerCase() === 'content-type')[1] = 'application/json; charset=utf-8';
}
body.push({
type: 'text',
value:
stringify(
JSON.parse(objCode.slice(arg.start, arg.end).replace(objKeyRegex, '"$1":')),
app.get('json replacer'),
app.get('json spaces'),
app.get('json escape')
)
});
} else {
return false;
}
}
sendUsed = true;
}
}
// uws doesnt support status codes other than 200 currently
if(statusCode != 200) {
return false;
}
let decRes = new uWS.DeclarativeResponse();
for(let header of headers) {
if(header[0].toLowerCase() === 'content-length') {
return false;
}
decRes = decRes.writeHeader(header[0], header[1]);
}
if(app.get('etag') && !headers.some(header => header[0].toLowerCase() === 'etag')) {
if(body.some(part => part.type !== 'text')) {
return false;
} else {
decRes = decRes.writeHeader('ETag', app.get('etag fn')(body.map(part => part.value.toString()).join('')));
}
}
if(app.get('x-powered-by')) {
decRes = decRes.writeHeader('x-powered-by', 'UltimateExpress');
}
for(let bodyPart of body) {
if(bodyPart.type === 'text' && String(bodyPart.value).length) {
decRes = decRes.write(String(bodyPart.value));
} else if(bodyPart.type === 'params') {
decRes = decRes.writeParameterValue(bodyPart.value);
} else if(bodyPart.type === 'query') {
decRes = decRes.writeQueryValue(bodyPart.value);
}
}
return decRes.end();
} catch(e) {
return false;
}
}
function filterNodes(node, fn) {
const filtered = [];
if(fn(node)) {
filtered.push(node);
}
if(node.params) {
for(let param of node.params) {
filtered.push(...filterNodes(param, fn));
}
}
if(node.body) {
if(Array.isArray(node.body)) {
for(let child of node.body) {
filtered.push(...filterNodes(child, fn));
}
} else {
filtered.push(...filterNodes(node.body, fn));
}
}
if(node.declarations) {
for(let declaration of node.declarations) {
filtered.push(...filterNodes(declaration, fn));
}
}
if(node.expression) {
filtered.push(...filterNodes(node.expression, fn));
}
if(node.callee) {
filtered.push(...filterNodes(node.callee, fn));
}
if(node.object) {
filtered.push(...filterNodes(node.object, fn));
}
if(node.property) {
filtered.push(...filterNodes(node.property, fn));
}
if(node.id) {
filtered.push(...filterNodes(node.id, fn));
}
if(node.init) {
filtered.push(...filterNodes(node.init, fn));
}
if(node.left) {
filtered.push(...filterNodes(node.left, fn));
}
if(node.right) {
filtered.push(...filterNodes(node.right, fn));
}
if(node.arguments) {
for(let argument of node.arguments) {
filtered.push(...filterNodes(argument, fn));
}
}
return filtered;
}