lib/response.js JAVASCRIPT 1,051 lines View on github.com → Search inside
1/*!2 * express3 * Copyright(c) 2009-2013 TJ Holowaychuk4 * Copyright(c) 2014-2015 Douglas Christopher Wilson5 * MIT Licensed6 */78'use strict';910/**11 * Module dependencies.12 * @private13 */1415var contentDisposition = require('content-disposition');16var createError = require('http-errors')17var deprecate = require('depd')('express');18var encodeUrl = require('encodeurl');19var escapeHtml = require('escape-html');20var http = require('node:http');21var onFinished = require('on-finished');22var mime = require('mime-types')23var path = require('node:path');24var pathIsAbsolute = require('node:path').isAbsolute;25var statuses = require('statuses')26var sign = require('cookie-signature').sign;27var normalizeType = require('./utils').normalizeType;28var normalizeTypes = require('./utils').normalizeTypes;29var setCharset = require('./utils').setCharset;30var cookie = require('cookie');31var send = require('send');32var extname = path.extname;33var resolve = path.resolve;34var basename = path.basename;35var vary = require('vary');36const { Buffer } = require('node:buffer');3738/**39 * Response prototype.40 * @public41 */4243var res = Object.create(http.ServerResponse.prototype)4445/**46 * Module exports.47 * @public48 */4950module.exports = res5152/**53 * Set the HTTP status code for the response.54 *55 * Expects an integer value between 100 and 999 inclusive.56 * Throws an error if the provided status code is not an integer or if it's outside the allowable range.57 *58 * @param {number} code - The HTTP status code to set.59 * @return {ServerResponse} - Returns itself for chaining methods.60 * @throws {TypeError} If `code` is not an integer.61 * @throws {RangeError} If `code` is outside the range 100 to 999.62 * @public63 */6465res.status = function status(code) {66  // Check if the status code is not an integer67  if (!Number.isInteger(code)) {68    throw new TypeError(`Invalid status code: ${JSON.stringify(code)}. Status code must be an integer.`);69  }70  // Check if the status code is outside of Node's valid range71  if (code < 100 || code > 999) {72    throw new RangeError(`Invalid status code: ${JSON.stringify(code)}. Status code must be greater than 99 and less than 1000.`);73  }7475  this.statusCode = code;76  return this;77};7879/**80 * Set Link header field with the given `links`.81 *82 * Examples:83 *84 *    res.links({85 *      next: 'http://api.example.com/users?page=2',86 *      last: 'http://api.example.com/users?page=5',87 *      pages: [88 *        'http://api.example.com/users?page=1',89 *        'http://api.example.com/users?page=2'90 *      ]91 *    });92 *93 * @param {Object} links94 * @return {ServerResponse}95 * @public96 */9798res.links = function(links) {99  var link = this.get('Link') || '';100  if (link) link += ', ';101  return this.set('Link', link + Object.keys(links).map(function(rel) {102    // Allow multiple links if links[rel] is an array103    if (Array.isArray(links[rel])) {104      return links[rel].map(function (singleLink) {105        return `<${singleLink}>; rel="${rel}"`;106      }).join(', ');107    } else {108      return `<${links[rel]}>; rel="${rel}"`;109    }110  }).join(', '));111};112113/**114 * Send a response.115 *116 * Examples:117 *118 *     res.send(Buffer.from('wahoo'));119 *     res.send({ some: 'json' });120 *     res.send('<p>some html</p>');121 *122 * @param {string|number|boolean|object|Buffer} body123 * @public124 */125126res.send = function send(body) {127  var chunk = body;128  var encoding;129  var req = this.req;130131  // settings132  var app = this.app;133134  switch (typeof chunk) {135    // string defaulting to html136    case 'string':137      encoding = 'utf8';138      const type = this.get('Content-Type');139140      if (typeof type === 'string') {141        this.set('Content-Type', setCharset(type, 'utf-8'));142      } else {143        this.type('html');144      }145      break;146    case 'boolean':147    case 'number':148    case 'object':149      if (chunk === null) {150        chunk = '';151      } else if (ArrayBuffer.isView(chunk)) {152        if (!this.get('Content-Type')) {153          this.type('bin');154        }155      } else {156        return this.json(chunk);157      }158      break;159  }160161  // determine if ETag should be generated162  var etagFn = app.get('etag fn')163  var generateETag = !this.get('ETag') && typeof etagFn === 'function'164165  var len;166  if (chunk !== undefined) {167    if (Buffer.isBuffer(chunk)) {168      // get length of Buffer169      len = chunk.length170    } else if (!generateETag && chunk.length < 1000) {171      // just calculate length when no ETag + small chunk172      len = Buffer.byteLength(chunk, encoding)173    } else {174      // convert chunk to Buffer and calculate175      chunk = Buffer.from(chunk, encoding)176      encoding = undefined;177      len = chunk.length178    }179180    // Because Content-Length and Transfer-Encoding can't be present in the response headers together,181    // Content-Length should be added only if there is no Transfer-Encoding header182    if (!this.get('Transfer-Encoding')) {183      this.set('Content-Length', len);184    }185  }186187  // populate ETag188  var etag;189  if (generateETag && len !== undefined) {190    if ((etag = etagFn(chunk, encoding))) {191      this.set('ETag', etag);192    }193  }194195  // freshness196  if (req.fresh) this.status(304);197198  // strip irrelevant headers199  if (204 === this.statusCode || 304 === this.statusCode) {200    this.removeHeader('Content-Type');201    this.removeHeader('Content-Length');202    this.removeHeader('Transfer-Encoding');203    chunk = '';204  }205206  // alter headers for 205207  if (this.statusCode === 205) {208    this.set('Content-Length', '0')209    this.removeHeader('Transfer-Encoding')210    chunk = ''211  }212213  if (req.method === 'HEAD') {214    // skip body for HEAD215    this.end();216  } else {217    // respond218    this.end(chunk, encoding);219  }220221  return this;222};223224/**225 * Send JSON response.226 *227 * Examples:228 *229 *     res.json(null);230 *     res.json({ user: 'tj' });231 *232 * @param {string|number|boolean|object} obj233 * @public234 */235236res.json = function json(obj) {237  // settings238  var app = this.app;239  var escape = app.get('json escape')240  var replacer = app.get('json replacer');241  var spaces = app.get('json spaces');242  var body = stringify(obj, replacer, spaces, escape)243244  // content-type245  if (!this.get('Content-Type')) {246    this.set('Content-Type', 'application/json');247  }248249  return this.send(body);250};251252/**253 * Send JSON response with JSONP callback support.254 *255 * Examples:256 *257 *     res.jsonp(null);258 *     res.jsonp({ user: 'tj' });259 *260 * @param {string|number|boolean|object} obj261 * @public262 */263264res.jsonp = function jsonp(obj) {265  // settings266  var app = this.app;267  var escape = app.get('json escape')268  var replacer = app.get('json replacer');269  var spaces = app.get('json spaces');270  var body = stringify(obj, replacer, spaces, escape)271  var callback = this.req.query[app.get('jsonp callback name')];272273  // content-type274  if (!this.get('Content-Type')) {275    this.set('X-Content-Type-Options', 'nosniff');276    this.set('Content-Type', 'application/json');277  }278279  // fixup callback280  if (Array.isArray(callback)) {281    callback = callback[0];282  }283284  // jsonp285  if (typeof callback === 'string' && callback.length !== 0) {286    this.set('X-Content-Type-Options', 'nosniff');287    this.set('Content-Type', 'text/javascript');288289    // restrict callback charset290    callback = callback.replace(/[^\[\]\w$.]/g, '');291292    if (body === undefined) {293      // empty argument294      body = ''295    } else if (typeof body === 'string') {296      // replace chars not allowed in JavaScript that are in JSON297      body = body298        .replace(/\u2028/g, '\\u2028')299        .replace(/\u2029/g, '\\u2029')300    }301302    // the /**/ is a specific security mitigation for "Rosetta Flash JSONP abuse"303    // the typeof check is just to reduce client error noise304    body = '/**/ typeof ' + callback + ' === \'function\' && ' + callback + '(' + body + ');';305  }306307  return this.send(body);308};309310/**311 * Send given HTTP status code.312 *313 * Sets the response status to `statusCode` and the body of the314 * response to the standard description from node's http.STATUS_CODES315 * or the statusCode number if no description.316 *317 * Examples:318 *319 *     res.sendStatus(200);320 *321 * @param {number} statusCode322 * @public323 */324325res.sendStatus = function sendStatus(statusCode) {326  var body = statuses.message[statusCode] || String(statusCode)327328  this.status(statusCode);329  this.type('txt');330331  return this.send(body);332};333334/**335 * Transfer the file at the given `path`.336 *337 * Automatically sets the _Content-Type_ response header field.338 * The callback `callback(err)` is invoked when the transfer is complete339 * or when an error occurs. Be sure to check `res.headersSent`340 * if you wish to attempt responding, as the header and some data341 * may have already been transferred.342 *343 * Options:344 *345 *   - `maxAge`   defaulting to 0 (can be string converted by `ms`)346 *   - `root`     root directory for relative filenames347 *   - `headers`  object of headers to serve with file348 *   - `dotfiles` serve dotfiles, defaulting to false; can be `"allow"` to send them349 *350 * Other options are passed along to `send`.351 *352 * Examples:353 *354 *  The following example illustrates how `res.sendFile()` may355 *  be used as an alternative for the `static()` middleware for356 *  dynamic situations. The code backing `res.sendFile()` is actually357 *  the same code, so HTTP cache support etc is identical.358 *359 *     app.get('/user/:uid/photos/:file', function(req, res){360 *       var uid = req.params.uid361 *         , file = req.params.file;362 *363 *       req.user.mayViewFilesFrom(uid, function(yes){364 *         if (yes) {365 *           res.sendFile('/uploads/' + uid + '/' + file);366 *         } else {367 *           res.send(403, 'Sorry! you can\'t see that.');368 *         }369 *       });370 *     });371 *372 * @public373 */374375res.sendFile = function sendFile(path, options, callback) {376  var done = callback;377  var req = this.req;378  var res = this;379  var next = req.next;380  var opts = options || {};381382  if (!path) {383    throw new TypeError('path argument is required to res.sendFile');384  }385386  if (typeof path !== 'string') {387    throw new TypeError('path must be a string to res.sendFile')388  }389390  // support function as second arg391  if (typeof options === 'function') {392    done = options;393    opts = {};394  }395396  if (!opts.root && !pathIsAbsolute(path)) {397    throw new TypeError('path must be absolute or specify root to res.sendFile');398  }399400  // create file stream401  var pathname = encodeURI(path);402403  // wire application etag option to send404  opts.etag = this.app.enabled('etag');405  var file = send(req, pathname, opts);406407  // transfer408  sendfile(res, file, opts, function (err) {409    if (done) return done(err);410    if (err && err.code === 'EISDIR') return next();411412    // next() all but write errors413    if (err && err.code !== 'ECONNABORTED' && err.syscall !== 'write') {414      next(err);415    }416  });417};418419/**420 * Transfer the file at the given `path` as an attachment.421 *422 * Optionally providing an alternate attachment `filename`,423 * and optional callback `callback(err)`. The callback is invoked424 * when the data transfer is complete, or when an error has425 * occurred. Be sure to check `res.headersSent` if you plan to respond.426 *427 * Optionally providing an `options` object to use with `res.sendFile()`.428 * This function will set the `Content-Disposition` header, overriding429 * any `Content-Disposition` header passed as header options in order430 * to set the attachment and filename.431 *432 * This method uses `res.sendFile()`.433 *434 * @public435 */436437res.download = function download (path, filename, options, callback) {438  var done = callback;439  var name = filename;440  var opts = options || null441442  // support function as second or third arg443  if (typeof filename === 'function') {444    done = filename;445    name = null;446    opts = null447  } else if (typeof options === 'function') {448    done = options449    opts = null450  }451452  // support optional filename, where options may be in its place453  if (typeof filename === 'object' &&454    (typeof options === 'function' || options === undefined)) {455    name = null456    opts = filename457  }458459  // set Content-Disposition when file is sent460  var headers = {461    'Content-Disposition': contentDisposition.create(basename(name || path))462  };463464  // merge user-provided headers465  if (opts && opts.headers) {466    var keys = Object.keys(opts.headers)467    for (var i = 0; i < keys.length; i++) {468      var key = keys[i]469      if (key.toLowerCase() !== 'content-disposition') {470        headers[key] = opts.headers[key]471      }472    }473  }474475  // merge user-provided options476  opts = Object.create(opts)477  opts.headers = headers478479  // Resolve the full path for sendFile480  var fullPath = !opts.root481    ? resolve(path)482    : path483484  // send file485  return this.sendFile(fullPath, opts, done)486};487488/**489 * Set _Content-Type_ response header with `type` through `mime.contentType()`490 * when it does not contain "/", or set the Content-Type to `type` otherwise.491 * When no mapping is found through `mime.contentType()`, the type is set to492 * "application/octet-stream".493 *494 * Examples:495 *496 *     res.type('.html');497 *     res.type('html');498 *     res.type('json');499 *     res.type('application/json');500 *     res.type('png');501 *502 * @param {String} type503 * @return {ServerResponse} for chaining504 * @public505 */506507res.contentType =508res.type = function contentType(type) {509  var ct = type.indexOf('/') === -1510    ? (mime.contentType(type) || 'application/octet-stream')511    : type;512513  return this.set('Content-Type', ct);514};515516/**517 * Respond to the Acceptable formats using an `obj`518 * of mime-type callbacks.519 *520 * This method uses `req.accepts()`, which returns the521 * best match from the acceptable types ordered by522 * their quality values.523 * When "Accept" is not present the _first_ callback524 * is invoked, otherwise the first match is used. When525 * no match is performed the server responds with526 * 406 "Not Acceptable".527 *528 * Content-Type is set for you, however if you choose529 * you may alter this within the callback using `res.type()`530 * or `res.set('Content-Type', ...)`.531 *532 *    res.format({533 *      'text/plain': function(){534 *        res.send('hey');535 *      },536 *537 *      'text/html': function(){538 *        res.send('<p>hey</p>');539 *      },540 *541 *      'application/json': function () {542 *        res.send({ message: 'hey' });543 *      }544 *    });545 *546 * In addition to canonicalized MIME types you may547 * also use extnames mapped to these types:548 *549 *    res.format({550 *      text: function(){551 *        res.send('hey');552 *      },553 *554 *      html: function(){555 *        res.send('<p>hey</p>');556 *      },557 *558 *      json: function(){559 *        res.send({ message: 'hey' });560 *      }561 *    });562 *563 * By default Express passes an `Error`564 * with a `.status` of 406 to `next(err)`565 * if a match is not made. If you provide566 * a `.default` callback it will be invoked567 * instead.568 *569 * @param {Object} obj570 * @return {ServerResponse} for chaining571 * @public572 */573574res.format = function(obj){575  var req = this.req;576  var next = req.next;577578  var keys = Object.keys(obj)579    .filter(function (v) { return v !== 'default' })580581  var key = keys.length > 0582    ? req.accepts(keys)583    : false;584585  this.vary("Accept");586587  if (key) {588    this.set('Content-Type', normalizeType(key).value);589    obj[key](req, this, next);590  } else if (obj.default) {591    obj.default(req, this, next)592  } else {593    next(createError(406, {594      types: normalizeTypes(keys).map(function (o) { return o.value })595    }))596  }597598  return this;599};600601/**602 * Set _Content-Disposition_ header to _attachment_ with optional `filename`.603 *604 * @param {String} filename605 * @return {ServerResponse}606 * @public607 */608609res.attachment = function attachment(filename) {610  const name = filename !== undefined ? basename(filename) : undefined;611  if (name) {612    this.type(extname(name));613  }614615  this.set('Content-Disposition', contentDisposition.create(name));616617  return this;618};619620/**621 * Append additional header `field` with value `val`.622 *623 * Example:624 *625 *    res.append('Link', ['<http://localhost/>', '<http://localhost:3000/>']);626 *    res.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly');627 *    res.append('Warning', '199 Miscellaneous warning');628 *629 * @param {String} field630 * @param {String|Array} val631 * @return {ServerResponse} for chaining632 * @public633 */634635res.append = function append(field, val) {636  var prev = this.get(field);637  var value = val;638639  if (prev) {640    // concat the new and prev vals641    value = Array.isArray(prev) ? prev.concat(val)642      : Array.isArray(val) ? [prev].concat(val)643        : [prev, val]644  }645646  return this.set(field, value);647};648649/**650 * Set header `field` to `val`, or pass651 * an object of header fields.652 *653 * Examples:654 *655 *    res.set('Foo', ['bar', 'baz']);656 *    res.set('Accept', 'application/json');657 *    res.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' });658 *659 * Aliased as `res.header()`.660 *661 * When the set header is "Content-Type", the type is expanded to include662 * the charset if not present using `mime.contentType()`.663 *664 * @param {String|Object} field665 * @param {String|Array} val666 * @return {ServerResponse} for chaining667 * @public668 */669670res.set =671res.header = function header(field, val) {672  if (arguments.length === 2) {673    var value = Array.isArray(val)674      ? val.map(String)675      : String(val);676677    // add charset to content-type678    if (field.toLowerCase() === 'content-type') {679      if (Array.isArray(value)) {680        throw new TypeError('Content-Type cannot be set to an Array');681      }682      value = mime.contentType(value)683    }684685    this.setHeader(field, value);686  } else {687    for (var key in field) {688      this.set(key, field[key]);689    }690  }691  return this;692};693694/**695 * Get value for header `field`.696 *697 * @param {String} field698 * @return {String}699 * @public700 */701702res.get = function(field){703  return this.getHeader(field);704};705706/**707 * Clear cookie `name`.708 *709 * @param {String} name710 * @param {Object} [options]711 * @return {ServerResponse} for chaining712 * @public713 */714715res.clearCookie = function clearCookie(name, options) {716  // Force cookie expiration by setting expires to the past717  const opts = { path: '/', ...options, expires: new Date(1)};718  // ensure maxAge is not passed719  delete opts.maxAge720721  return this.cookie(name, '', opts);722};723724/**725 * Set cookie `name` to `value`, with the given `options`.726 *727 * Options:728 *729 *    - `maxAge`   max-age in milliseconds, converted to `expires`730 *    - `signed`   sign the cookie731 *    - `path`     defaults to "/"732 *733 * Examples:734 *735 *    // "Remember Me" for 15 minutes736 *    res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true });737 *738 *    // same as above739 *    res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })740 *741 * @param {String} name742 * @param {String|Object} value743 * @param {Object} [options]744 * @return {ServerResponse} for chaining745 * @public746 */747748res.cookie = function (name, value, options) {749  var opts = { ...options };750  var secret = this.req.secret;751  var signed = opts.signed;752753  if (signed && !secret) {754    throw new Error('cookieParser("secret") required for signed cookies');755  }756757  var val = typeof value === 'object'758    ? 'j:' + JSON.stringify(value)759    : String(value);760761  if (signed) {762    val = 's:' + sign(val, secret);763  }764765  if (opts.maxAge != null) {766    var maxAge = opts.maxAge - 0767768    if (!isNaN(maxAge)) {769      opts.expires = new Date(Date.now() + maxAge)770      opts.maxAge = Math.floor(maxAge / 1000)771    }772  }773774  if (opts.path == null) {775    opts.path = '/';776  }777778  this.append('Set-Cookie', cookie.serialize(name, String(val), opts));779780  return this;781};782783/**784 * Set the location header to `url`.785 *786 * Examples:787 *788 *    res.location('/foo/bar');789 *    res.location('http://example.com');790 *    res.location('../login');791 *792 * @param {String} url793 * @return {ServerResponse} for chaining794 * @public795 */796797res.location = function location(url) {798  return this.set('Location', encodeUrl(url));799};800801/**802 * Redirect to the given `url` with optional response `status`803 * defaulting to 302.804 *805 * Examples:806 *807 *    res.redirect('/foo/bar');808 *    res.redirect('http://example.com');809 *    res.redirect(301, 'http://example.com');810 *    res.redirect('../login'); // /blog/post/1 -> /blog/login811 *812 * @public813 */814815res.redirect = function redirect(url) {816  var address = url;817  var body;818  var status = 302;819820  // allow status / url821  if (arguments.length === 2) {822    status = arguments[0]823    address = arguments[1]824  }825826  if (!address) {827    deprecate('Provide a url argument');828  }829830  if (typeof address !== 'string') {831    deprecate('Url must be a string');832  }833834  if (typeof status !== 'number') {835    deprecate('Status must be a number');836  }837838  // Set location header839  address = this.location(address).get('Location');840841  // Support text/{plain,html} by default842  this.format({843    text: function(){844      body = statuses.message[status] + '. Redirecting to ' + address845    },846847    html: function(){848      var u = escapeHtml(address);849      body = '<!DOCTYPE html><head><title>' + statuses.message[status] + '</title></head>'850       + '<body><p>' + statuses.message[status] + '. Redirecting to ' + u + '</p></body>'851    },852853    default: function(){854      body = '';855    }856  });857858  // Respond859  this.status(status);860  this.set('Content-Length', Buffer.byteLength(body));861862  if (this.req.method === 'HEAD') {863    this.end();864  } else {865    this.end(body);866  }867};868869/**870 * Add `field` to Vary. If already present in the Vary set, then871 * this call is simply ignored.872 *873 * @param {Array|String} field874 * @return {ServerResponse} for chaining875 * @public876 */877878res.vary = function(field){879  vary(this, field);880881  return this;882};883884/**885 * Render `view` with the given `options` and optional callback `fn`.886 * When a callback function is given a response will _not_ be made887 * automatically, otherwise a response of _200_ and _text/html_ is given.888 *889 * Options:890 *891 *  - `cache`     boolean hinting to the engine it should cache892 *  - `filename`  filename of the view being rendered893 *894 * @public895 */896897res.render = function render(view, options, callback) {898  var app = this.req.app;899  var done = callback;900  var opts = options || {};901  var req = this.req;902  var self = this;903904  // support callback function as second arg905  if (typeof options === 'function') {906    done = options;907    opts = {};908  }909910  // merge res.locals911  opts._locals = self.locals;912913  // default callback to respond914  done = done || function (err, str) {915    if (err) return req.next(err);916    self.send(str);917  };918919  // render920  app.render(view, opts, done);921};922923// pipe the send file stream924function sendfile(res, file, options, callback) {925  var done = false;926  var streaming;927928  // request aborted929  function onaborted() {930    if (done) return;931    done = true;932933    var err = new Error('Request aborted');934    err.code = 'ECONNABORTED';935    callback(err);936  }937938  // directory939  function ondirectory() {940    if (done) return;941    done = true;942943    var err = new Error('EISDIR, read');944    err.code = 'EISDIR';945    callback(err);946  }947948  // errors949  function onerror(err) {950    if (done) return;951    done = true;952    callback(err);953  }954955  // ended956  function onend() {957    if (done) return;958    done = true;959    callback();960  }961962  // file963  function onfile() {964    streaming = false;965  }966967  // finished968  function onfinish(err) {969    if (err && err.code === 'ECONNRESET') return onaborted();970    if (err) return onerror(err);971    if (done) return;972973    setImmediate(function () {974      if (streaming !== false && !done) {975        onaborted();976        return;977      }978979      if (done) return;980      done = true;981      callback();982    });983  }984985  // streaming986  function onstream() {987    streaming = true;988  }989990  file.on('directory', ondirectory);991  file.on('end', onend);992  file.on('error', onerror);993  file.on('file', onfile);994  file.on('stream', onstream);995  onFinished(res, onfinish);996997  if (options.headers) {998    // set headers on successful transfer999    file.on('headers', function headers(res) {1000      var obj = options.headers;1001      var keys = Object.keys(obj);10021003      for (var i = 0; i < keys.length; i++) {1004        var k = keys[i];1005        res.setHeader(k, obj[k]);1006      }1007    });1008  }10091010  // pipe1011  file.pipe(res);1012}10131014/**1015 * Stringify JSON, like JSON.stringify, but v8 optimized, with the1016 * ability to escape characters that can trigger HTML sniffing.1017 *1018 * @param {*} value1019 * @param {function} replacer1020 * @param {number} spaces1021 * @param {boolean} escape1022 * @returns {string}1023 * @private1024 */10251026function stringify (value, replacer, spaces, escape) {1027  // v8 checks arguments.length for optimizing simple call1028  // https://bugs.chromium.org/p/v8/issues/detail?id=47301029  var json = replacer || spaces1030    ? JSON.stringify(value, replacer, spaces)1031    : JSON.stringify(value);10321033  if (escape && typeof json === 'string') {1034    json = json.replace(/[<>&]/g, function (c) {1035      switch (c.charCodeAt(0)) {1036        case 0x3c:1037          return '\\u003c'1038        case 0x3e:1039          return '\\u003e'1040        case 0x26:1041          return '\\u0026'1042        /* istanbul ignore next: unreachable default */1043        default:1044          return c1045      }1046    })1047  }10481049  return json1050}

Code quality findings 95

Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var contentDisposition = require('content-disposition');
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var createError = require('http-errors')
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var deprecate = require('depd')('express');
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var encodeUrl = require('encodeurl');
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var escapeHtml = require('escape-html');
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var http = require('node:http');
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var onFinished = require('on-finished');
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var mime = require('mime-types')
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var path = require('node:path');
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var pathIsAbsolute = require('node:path').isAbsolute;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var statuses = require('statuses')
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var sign = require('cookie-signature').sign;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var normalizeType = require('./utils').normalizeType;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var normalizeTypes = require('./utils').normalizeTypes;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var setCharset = require('./utils').setCharset;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var cookie = require('cookie');
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var send = require('send');
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var extname = path.extname;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var resolve = path.resolve;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var basename = path.basename;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var vary = require('vary');
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var res = Object.create(http.ServerResponse.prototype)
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var link = this.get('Link') || '';
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var chunk = body;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var encoding;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var req = this.req;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var app = this.app;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var etagFn = app.get('etag fn')
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var generateETag = !this.get('ETag') && typeof etagFn === 'function'
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var len;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var etag;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var app = this.app;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var escape = app.get('json escape')
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var replacer = app.get('json replacer');
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var spaces = app.get('json spaces');
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var body = stringify(obj, replacer, spaces, escape)
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var app = this.app;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var escape = app.get('json escape')
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var replacer = app.get('json replacer');
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var spaces = app.get('json spaces');
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var body = stringify(obj, replacer, spaces, escape)
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var callback = this.req.query[app.get('jsonp callback name')];
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var body = statuses.message[statusCode] || String(statusCode)
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var done = callback;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var req = this.req;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var res = this;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var next = req.next;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var opts = options || {};
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var pathname = encodeURI(path);
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var file = send(req, pathname, opts);
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var done = callback;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var name = filename;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var opts = options || null
typeof x === 'object' is also true for null; check x !== null as well
info correctness typeof-pitfall
if (typeof filename === 'object' &&
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var headers = {
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var keys = Object.keys(opts.headers)
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
for (var i = 0; i < keys.length; i++) {
Use let instead of var in loops to avoid scope issues
info correctness var-in-loop
for (var i = 0; i < keys.length; i++) {
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var key = keys[i]
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var fullPath = !opts.root
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var ct = type.indexOf('/') === -1
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var req = this.req;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var next = req.next;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var keys = Object.keys(obj)
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var key = keys.length > 0
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var prev = this.get(field);
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var value = val;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var value = Array.isArray(val)
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
for (var key in field) {
Use let instead of var in loops to avoid scope issues
info correctness var-in-loop
for (var key in field) {
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var opts = { ...options };
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var secret = this.req.secret;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var signed = opts.signed;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var val = typeof value === 'object'
typeof x === 'object' is also true for null; check x !== null as well
info correctness typeof-pitfall
var val = typeof value === 'object'
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var maxAge = opts.maxAge - 0
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var address = url;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var body;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var status = 302;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var u = escapeHtml(address);
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var app = this.req.app;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var done = callback;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var opts = options || {};
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var req = this.req;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var self = this;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var done = false;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var streaming;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var err = new Error('Request aborted');
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var err = new Error('EISDIR, read');
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var obj = options.headers;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var keys = Object.keys(obj);
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
for (var i = 0; i < keys.length; i++) {
Use let instead of var in loops to avoid scope issues
info correctness var-in-loop
for (var i = 0; i < keys.length; i++) {
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var k = keys[i];
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var json = replacer || spaces

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.

Generated by searchcode.com · powered by code_get_file + code_get_findings