Coder Social home page Coder Social logo

finalhandler's Introduction

finalhandler

NPM Version NPM Downloads Node.js Version Build Status Test Coverage

Node.js function to invoke as the final step to respond to HTTP request.

Installation

This is a Node.js module available through the npm registry. Installation is done using the npm install command:

$ npm install finalhandler

API

var finalhandler = require('finalhandler')

finalhandler(req, res, [options])

Returns function to be invoked as the final step for the given req and res. This function is to be invoked as fn(err). If err is falsy, the handler will write out a 404 response to the res. If it is truthy, an error response will be written out to the res or res will be terminated if a response has already started.

When an error is written, the following information is added to the response:

  • The res.statusCode is set from err.status (or err.statusCode). If this value is outside the 4xx or 5xx range, it will be set to 500.
  • The res.statusMessage is set according to the status code.
  • The body will be the HTML of the status code message if env is 'production', otherwise will be err.stack.
  • Any headers specified in an err.headers object.

The final handler will also unpipe anything from req when it is invoked.

options.env

By default, the environment is determined by NODE_ENV variable, but it can be overridden by this option.

options.onerror

Provide a function to be called with the err when it exists. Can be used for writing errors to a central location without excessive function generation. Called as onerror(err, req, res).

Examples

always 404

var finalhandler = require('finalhandler')
var http = require('http')

var server = http.createServer(function (req, res) {
  var done = finalhandler(req, res)
  done()
})

server.listen(3000)

perform simple action

var finalhandler = require('finalhandler')
var fs = require('fs')
var http = require('http')

var server = http.createServer(function (req, res) {
  var done = finalhandler(req, res)

  fs.readFile('index.html', function (err, buf) {
    if (err) return done(err)
    res.setHeader('Content-Type', 'text/html')
    res.end(buf)
  })
})

server.listen(3000)

use with middleware-style functions

var finalhandler = require('finalhandler')
var http = require('http')
var serveStatic = require('serve-static')

var serve = serveStatic('public')

var server = http.createServer(function (req, res) {
  var done = finalhandler(req, res)
  serve(req, res, done)
})

server.listen(3000)

keep log of all errors

var finalhandler = require('finalhandler')
var fs = require('fs')
var http = require('http')

var server = http.createServer(function (req, res) {
  var done = finalhandler(req, res, { onerror: logerror })

  fs.readFile('index.html', function (err, buf) {
    if (err) return done(err)
    res.setHeader('Content-Type', 'text/html')
    res.end(buf)
  })
})

server.listen(3000)

function logerror (err) {
  console.error(err.stack || err.toString())
}

License

MIT

finalhandler's People

Contributors

dougwilson avatar mcollina avatar nook-scheel avatar ronperris avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

finalhandler's Issues

npm audit security advisory 836

                       === npm audit security report ===

┌──────────────────────────────────────────────────────────────────────────────┐
│                                Manual Review                                 │
│            Some vulnerabilities require your attention to resolve            │
│                                                                              │
│         Visit https://go.npm.me/audit-guide for additional guidance          │
└──────────────────────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low           │ Insecure Default Configuration                               │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ finalhandler                                                 │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ No patch available                                           │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ express                                                      │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ express > finalhandler                                       │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/836                       │
└───────────────┴──────────────────────────────────────────────────────────────┘
found 1 low severity vulnerability in 851073 scanned packages
  1 vulnerability requires manual review. See the full report for details.

Print causes when outputting error stacks

In getErrorMessage, which is used to create a pretty error messages that is both logged and returned to clients in non-production environments, the error message is found by simply taking err.stack.

Errors now support the cause option (not really well-documented in Node.js documentation, but it's on MDN), which allows listing originating causes for an error (for example, if an error is thrown as the result of a different error).

err.stack does not print this, but for example browser consoles show the causes nicely:

image

Would you be interested in a PR adding the cause chain to the output of getErrorMessage? I think this would be a nice addition, and I would personally find it useful 😄

Content-Security-Policy should use default-src 'none'.

What I expected

The Content Security Policy would deny loading resources by default.

What I experienced

The Content-Security-Policy uses 'self', which is more permissive than 'none'.

Why does this matter?

The Content-Security-Policy currently sets the following directives to permit loading from self.

child-src
connect-src
font-src
frame-src
img-src
manifest-src
media-src
object-src
prefetch-src
script-src
style-src
worker-src

There is no reason to allow all this functionality since the error page doesn't use any of these browser features. The current input validation and escaping code prevent tampering with the page contents, but if a bypass was found the Content Security Policy is needlessly permissive, IMHO. Set the default-src directive to 'none' and the page will continue to function and another layer of defense will be enabled.

npm security vulnerability

As reported here:

cd my-app
npm i karma
npm audit
                       === npm audit security report ===                        
                                                                                
┌──────────────────────────────────────────────────────────────────────────────┐
│                                Manual Review                                 │
│            Some vulnerabilities require your attention to resolve            │
│                                                                              │
│         Visit https://go.npm.me/audit-guide for additional guidance          │
└──────────────────────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low           │ Insecure Default Configuration                               │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ finalhandler                                                 │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ No patch available                                           │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ karma                                                        │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ karma > connect > finalhandler                               │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://npmjs.com/advisories/836                             │
└───────────────┴──────────────────────────────────────────────────────────────┘
found 1 low severity vulnerability in 2518 scanned packages
  1 vulnerability requires manual review. See the full report for details.

Respect `expose` on thrown errors

https://www.npmjs.com/package/http-errors

When we're extracting the message out of a thrown error, we should consider respecting the expose property on it so that we provide consumers some way of exposing information to the client in the event that they want to return something like an HTTP 400 by using throw BadRequest('You must include an Id') from http-errors or a similar lib.

Cannot read property 'headersSent' of undefined

I keep getting this error and from the log I can see that Express is using this module, and I have no clue on how to solve it.

/home/sentinel/Gitlab/stormcms-engine-v2/node_modules/finalhandler/index.js:239
[1]   return typeof res.headersSent !== 'boolean'
[1]                     ^
[1] 
[1] TypeError: Cannot read property 'headersSent' of undefined
[1]     at headersSent (/home/sentinel/Gitlab/stormcms-engine-v2/node_modules/finalhandler/index.js:239:21)
[1]     at /home/sentinel/Gitlab/stormcms-engine-v2/node_modules/finalhandler/index.js:92:17
[1]     at /home/sentinel/Gitlab/stormcms-engine-v2/node_modules/express/lib/router/index.js:635:15
[1]     at next (/home/sentinel/Gitlab/stormcms-engine-v2/node_modules/express/lib/router/index.js:210:14)
[1]     at Function.handle (/home/sentinel/Gitlab/stormcms-engine-v2/node_modules/express/lib/router/index.js:174:3)
[1]     at Function.handle (/home/sentinel/Gitlab/stormcms-engine-v2/node_modules/express/lib/application.js:174:10)
[1]     at app (/home/sentinel/Gitlab/stormcms-engine-v2/node_modules/express/lib/express.js:39:9)
[1]     at Object.<anonymous> (/home/sentinel/Gitlab/stormcms-engine-v2/src/server.js:104:1)
[1]     at Module._compile (module.js:635:30)
[1]     at loader (/home/sentinel/Gitlab/stormcms-engine-v2/node_modules/babel-register/lib/node.js:144:5)
[1]     at Object.require.extensions.(anonymous function) [as .js] (/home/sentinel/Gitlab/stormcms-engine-v2/node_modules/babel-register/lib/node.js:154:7)
[1]     at Module.load (module.js:554:32)
[1]     at tryModuleLoad (module.js:497:12)
[1]     at Module._load (module.js:489:3)
[1]     at Function.module._load (/home/sentinel/Gitlab/stormcms-engine-v2/node_modules/piping/lib/piping.js:218:16)
[1]     at Module.require (module.js:579:17)

TypeError: Cannot read property 'headersSent' of undefined

home/bienfait/nodejs/Node-Express/node_modules/finalhandler/index.js:256
  return typeof res.headersSent !== 'boolean'
                    ^

TypeError: Cannot read property 'headersSent' of undefined
    at headersSent (/home/bienfait/nodejs/Node-Express/node_modules/finalhandler/index.js:256:21)
    at /home/bienfait/nodejs/Node-Express/node_modules/finalhandler/index.js:92:17
    at Function.handle (/home/bienfait/nodejs/Node-Express/node_modules/express/lib/application.js:170:5)
    at app (/home/bienfait/nodejs/Node-Express/node_modules/express/lib/express.js:39:9)
    at Object.<anonymous> (/home/bienfait/nodejs/Node-Express/index.js:11:1)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)

Any reason for awaiting complete requests before sending responses?

Hi, I have a question about this part of the code. Is there any (specific) reason for awaiting a complete request before sending a response?

finalhandler/index.js

Lines 300 to 310 in 15e78ca

if (isFinished(req)) {
write()
return
}
// unpipe everything from the request
unpipe(req)
// flush the request
onFinished(req, write)
req.resume()

I think this would be a potential risk in some edge case, for example from the README:

var finalhandler = require('finalhandler')
var http = require('http')

var server = http.createServer(function (req, res) {
  var done = finalhandler(req, res)
  done()
})

server.listen(3000)

This should always return 404 immediately for any requests, but the following request can cause the server to be hung up:

curl -X$ANY_METHOD http://localhost:3000 -H content-length:1

I know this hardly happens and is the clients' fault unless an intentional attack; plus, we can set a timeout for general requests.

However, I think there is no need to await the body or a complete request for the requests that we don't expect (such as 404) in order to return error responses immediately without being hung up by omitting to do that.

Content type is html instead of text/plain

Hello,

Took me a while to track this down from express to here ;-)
When my express app has an unhandled route or a server error this middleware will respond to the request with a 404 or 500 and a very simple message. (Cannot GET /foo)
However; the content type is explicitly set to text/html but the actual content is not HTML but plain text. (text/plain).

I did not want to submit a pull request right away but wanted to check first with you if there is a reason behind this. And in the case that this middelware will not change; is it possible to overrule this or should I define my own "catch all" route to do this?

Thanks! :)

UnsupportedWarning: Status message is not supported by HTTP/2 (RFC7540 8.1.2.4)

The following line triggers an UnsupportedWarning when using Http2SecureServer from module http2.

res.statusMessage = statuses[status]

What can be done to avoid this when using the HTTP2 protocol?

(node:1002309) UnsupportedWarning: Status message is not supported by HTTP/2 (RFC7540 8.1.2.4)
    at statusMessageWarn (internal/http2/compat.js:100:13)
    at Http2ServerResponse.set statusMessage [as statusMessage] (internal/http2/compat.js:628:5)
    at Array.write (/home/project/node_modules/finalhandler/index.js:279:23)
    at listener (/home/project/node_modules/on-finished/index.js:169:15)
    at onFinish (/home/project/node_modules/on-finished/index.js:100:5)
    at callback (/home/project/node_modules/ee-first/index.js:55:10)
    at Http2ServerRequest.onevent (/home/project/node_modules/ee-first/index.js:93:5)
    at Http2ServerRequest.emit (events.js:400:28)
    at Http2ServerRequest.emit (domain.js:470:12)
    at endReadableNT (internal/streams/readable.js:1317:12)

req.socket.destroy is not a function

We're occasionally seeing this error in our logs. Since the stack trace starts from node:internal, it's very hard to tell where it's coming from. It's unclear how to reproduce this issue since it only periodically happens. Can you give any hints on how to track down what is causing this? We're using [email protected]

TypeError: req.socket.destroy is not a function
    at Immediate.<anonymous> (/app/node_modules/finalhandler/index.js:36:10)
    at Immediate.<anonymous> (/app/node_modules/express/lib/router/index.js:36:10)
    at processImmediate (node:internal/timers:36:10)
    at process.topLevelDomainCallback (node:domain:36:10)
    at process.callbackTrampoline (node:internal/async_hooks:36:24)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.