Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions lib/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ var methods = require('./utils').methods;
var compileETag = require('./utils').compileETag;
var compileQueryParser = require('./utils').compileQueryParser;
var compileTrust = require('./utils').compileTrust;
var errors = require('./errors');
var codes = errors.codes;
var resolve = require('node:path').resolve;
var once = require('once')
var Router = require('router');
Expand Down Expand Up @@ -210,7 +212,10 @@ app.use = function use(fn) {
var fns = flatten.call(slice.call(arguments, offset), Infinity);

if (fns.length === 0) {
throw new TypeError('app.use() requires a middleware function')
throw errors.createTypeError(
codes.ERR_MIDDLEWARE_REQUIRED,
'app.use() requires a middleware function'
);
}

// get router
Expand Down Expand Up @@ -293,7 +298,10 @@ app.route = function route(path) {

app.engine = function engine(ext, fn) {
if (typeof fn !== 'function') {
throw new Error('callback function required');
throw errors.createError(
codes.ERR_ENGINE_CALLBACK_REQUIRED,
'callback function required'
);
}

// get file extension
Expand Down
111 changes: 111 additions & 0 deletions lib/errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/

"use strict";

/**
* Error codes for Express errors.
*
* These codes provide a stable contract for error handling,
* allowing developers to rely on error codes rather than error messages.
*
* @public
*/

var codes = {
// Response errors
ERR_INVALID_STATUS_CODE: "ERR_INVALID_STATUS_CODE",
ERR_STATUS_CODE_OUT_OF_RANGE: "ERR_STATUS_CODE_OUT_OF_RANGE",
ERR_SENDFILE_PATH_REQUIRED: "ERR_SENDFILE_PATH_REQUIRED",
ERR_SENDFILE_PATH_NOT_STRING: "ERR_SENDFILE_PATH_NOT_STRING",
ERR_SENDFILE_PATH_NOT_ABSOLUTE: "ERR_SENDFILE_PATH_NOT_ABSOLUTE",
ERR_CONTENT_TYPE_ARRAY: "ERR_CONTENT_TYPE_ARRAY",
ERR_COOKIE_SECRET_REQUIRED: "ERR_COOKIE_SECRET_REQUIRED",

// Application/middleware errors
ERR_MIDDLEWARE_REQUIRED: "ERR_MIDDLEWARE_REQUIRED",
ERR_ENGINE_CALLBACK_REQUIRED: "ERR_ENGINE_CALLBACK_REQUIRED",

// Request errors
ERR_HEADER_NAME_REQUIRED: "ERR_HEADER_NAME_REQUIRED",
ERR_HEADER_NAME_NOT_STRING: "ERR_HEADER_NAME_NOT_STRING",

// View errors
ERR_NO_DEFAULT_ENGINE: "ERR_NO_DEFAULT_ENGINE",
ERR_VIEW_ENGINE_NOT_FOUND: "ERR_VIEW_ENGINE_NOT_FOUND",

// Configuration errors
ERR_INVALID_ETAG_OPTION: "ERR_INVALID_ETAG_OPTION",
ERR_INVALID_QUERY_PARSER_OPTION: "ERR_INVALID_QUERY_PARSER_OPTION",
};

/**
* Create a TypeError with an error code.
*
* @param {string} code - The error code
* @param {string} message - The error message
* @return {TypeError}
* @private
*/

function createTypeError(code, message) {
var error = new TypeError(message);
error.code = code;
if (Error.captureStackTrace) {
Error.captureStackTrace(error, createTypeError);
}
return error;
}

/**
* Create a RangeError with an error code.
*
* @param {string} code - The error code
* @param {string} message - The error message
* @return {RangeError}
* @private
*/

function createRangeError(code, message) {
var error = new RangeError(message);
error.code = code;
if (Error.captureStackTrace) {
Error.captureStackTrace(error, createRangeError);
}
return error;
}

/**
* Create an Error with an error code.
*
* @param {string} code - The error code
* @param {string} message - The error message
* @return {Error}
* @private
*/

function createError(code, message) {
var error = new Error(message);
error.code = code;
if (Error.captureStackTrace) {
Error.captureStackTrace(error, createError);
}
return error;
}

/**
* Module exports.
* @public
*/

module.exports = {
codes: Object.freeze(codes),
createTypeError: createTypeError,
createRangeError: createRangeError,
createError: createError,
};
6 changes: 6 additions & 0 deletions lib/express.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,9 @@ exports.raw = bodyParser.raw
exports.static = require('serve-static');
exports.text = bodyParser.text
exports.urlencoded = bodyParser.urlencoded

/**
* Expose error codes for programmatic error handling.
*/

exports.errorCodes = require('./errors').codes
12 changes: 10 additions & 2 deletions lib/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ var fresh = require('fresh');
var parseRange = require('range-parser');
var parse = require('parseurl');
var proxyaddr = require('proxy-addr');
var errors = require('./errors');
var codes = errors.codes;

/**
* Request prototype.
Expand Down Expand Up @@ -63,11 +65,17 @@ module.exports = req
req.get =
req.header = function header(name) {
if (!name) {
throw new TypeError('name argument is required to req.get');
throw errors.createTypeError(
codes.ERR_HEADER_NAME_REQUIRED,
'name argument is required to req.get'
);
}

if (typeof name !== 'string') {
throw new TypeError('name must be a string to req.get');
throw errors.createTypeError(
codes.ERR_HEADER_NAME_NOT_STRING,
'name must be a string to req.get'
);
}

var lc = name.toLowerCase();
Expand Down
37 changes: 30 additions & 7 deletions lib/response.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ var sign = require('cookie-signature').sign;
var normalizeType = require('./utils').normalizeType;
var normalizeTypes = require('./utils').normalizeTypes;
var setCharset = require('./utils').setCharset;
var errors = require('./errors');
var codes = errors.codes;
var cookie = require('cookie');
var send = require('send');
var extname = path.extname;
Expand Down Expand Up @@ -64,11 +66,17 @@ module.exports = res
res.status = function status(code) {
// Check if the status code is not an integer
if (!Number.isInteger(code)) {
throw new TypeError(`Invalid status code: ${JSON.stringify(code)}. Status code must be an integer.`);
throw errors.createTypeError(
codes.ERR_INVALID_STATUS_CODE,
`Invalid status code: ${JSON.stringify(code)}. Status code must be an integer.`
);
}
// Check if the status code is outside of Node's valid range
if (code < 100 || code > 999) {
throw new RangeError(`Invalid status code: ${JSON.stringify(code)}. Status code must be greater than 99 and less than 1000.`);
throw errors.createRangeError(
codes.ERR_STATUS_CODE_OUT_OF_RANGE,
`Invalid status code: ${JSON.stringify(code)}. Status code must be greater than 99 and less than 1000.`
);
}

this.statusCode = code;
Expand Down Expand Up @@ -383,11 +391,17 @@ res.sendFile = function sendFile(path, options, callback) {
var opts = options || {};

if (!path) {
throw new TypeError('path argument is required to res.sendFile');
throw errors.createTypeError(
codes.ERR_SENDFILE_PATH_REQUIRED,
'path argument is required to res.sendFile'
);
}

if (typeof path !== 'string') {
throw new TypeError('path must be a string to res.sendFile')
throw errors.createTypeError(
codes.ERR_SENDFILE_PATH_NOT_STRING,
'path must be a string to res.sendFile'
);
}

// support function as second arg
Expand All @@ -397,7 +411,10 @@ res.sendFile = function sendFile(path, options, callback) {
}

if (!opts.root && !pathIsAbsolute(path)) {
throw new TypeError('path must be absolute or specify root to res.sendFile');
throw errors.createTypeError(
codes.ERR_SENDFILE_PATH_NOT_ABSOLUTE,
'path must be absolute or specify root to res.sendFile'
);
}

// create file stream
Expand Down Expand Up @@ -678,7 +695,10 @@ res.header = function header(field, val) {
// add charset to content-type
if (field.toLowerCase() === 'content-type') {
if (Array.isArray(value)) {
throw new TypeError('Content-Type cannot be set to an Array');
throw errors.createTypeError(
codes.ERR_CONTENT_TYPE_ARRAY,
'Content-Type cannot be set to an Array'
);
}
value = mime.contentType(value)
}
Expand Down Expand Up @@ -752,7 +772,10 @@ res.cookie = function (name, value, options) {
var signed = opts.signed;

if (signed && !secret) {
throw new Error('cookieParser("secret") required for signed cookies');
throw errors.createError(
codes.ERR_COOKIE_SECRET_REQUIRED,
'cookieParser("secret") required for signed cookies'
);
}

var val = typeof value === 'object'
Expand Down
12 changes: 10 additions & 2 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ var proxyaddr = require('proxy-addr');
var qs = require('qs');
var querystring = require('node:querystring');
const { Buffer } = require('node:buffer');
var errors = require('./errors');
var codes = errors.codes;


/**
Expand Down Expand Up @@ -145,7 +147,10 @@ exports.compileETag = function(val) {
fn = exports.etag;
break;
default:
throw new TypeError('unknown value for etag function: ' + val);
throw errors.createTypeError(
codes.ERR_INVALID_ETAG_OPTION,
'unknown value for etag function: ' + val
);
}

return fn;
Expand Down Expand Up @@ -177,7 +182,10 @@ exports.compileQueryParser = function compileQueryParser(val) {
fn = parseExtendedQueryString;
break;
default:
throw new TypeError('unknown value for query parser function: ' + val);
throw errors.createTypeError(
codes.ERR_INVALID_QUERY_PARSER_OPTION,
'unknown value for query parser function: ' + val
);
}

return fn;
Expand Down
12 changes: 10 additions & 2 deletions lib/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
var debug = require('debug')('express:view');
var path = require('node:path');
var fs = require('node:fs');
var errors = require('./errors');
var codes = errors.codes;

/**
* Module variables.
Expand Down Expand Up @@ -58,7 +60,10 @@ function View(name, options) {
this.root = opts.root;

if (!this.ext && !this.defaultEngine) {
throw new Error('No default engine was specified and no extension was provided.');
throw errors.createError(
codes.ERR_NO_DEFAULT_ENGINE,
'No default engine was specified and no extension was provided.'
);
}

var fileName = name;
Expand All @@ -81,7 +86,10 @@ function View(name, options) {
var fn = require(mod).__express

if (typeof fn !== 'function') {
throw new Error('Module "' + mod + '" does not provide a view engine.')
throw errors.createError(
codes.ERR_VIEW_ENGINE_NOT_FOUND,
'Module "' + mod + '" does not provide a view engine.'
);
}

opts.engines[this.ext] = fn
Expand Down
Loading