1+ /*!
2+ * Connect - errorHandler
3+ * Copyright(c) 2010 Sencha Inc.
4+ * Copyright(c) 2011 TJ Holowaychuk
5+ * MIT Licensed
6+ */
7+
8+ /**
9+ * Module dependencies.
10+ */
11+
12+ var fs ;
13+ try {
14+ fs = require ( 'graceful-fs' ) ;
15+ } catch ( _ ) {
16+ fs = require ( 'fs' ) ;
17+ }
18+
19+ // environment
20+
21+ var env = process . env . NODE_ENV || 'development' ;
22+
23+ /**
24+ * Error handler:
25+ *
26+ * Development error handler, providing stack traces
27+ * and error message responses for requests accepting text, html,
28+ * or json.
29+ *
30+ * Text:
31+ *
32+ * By default, and when _text/plain_ is accepted a simple stack trace
33+ * or error message will be returned.
34+ *
35+ * JSON:
36+ *
37+ * When _application/json_ is accepted, connect will respond with
38+ * an object in the form of `{ "error": error }`.
39+ *
40+ * HTML:
41+ *
42+ * When accepted connect will output a nice html stack trace.
43+ *
44+ * @return {Function }
45+ * @api public
46+ */
47+
48+ exports = module . exports = function errorHandler ( ) {
49+ return function errorHandler ( err , req , res , next ) {
50+ if ( err . status ) res . statusCode = err . status ;
51+ if ( res . statusCode < 400 ) res . statusCode = 500 ;
52+ if ( 'test' != env ) console . error ( err . stack ) ;
53+ var accept = req . headers . accept || '' ;
54+ // html
55+ if ( ~ accept . indexOf ( 'html' ) ) {
56+ fs . readFile ( __dirname + '/public/style.css' , 'utf8' , function ( e , style ) {
57+ fs . readFile ( __dirname + '/public/error.html' , 'utf8' , function ( e , html ) {
58+ var stack = ( err . stack || '' )
59+ . split ( '\n' ) . slice ( 1 )
60+ . map ( function ( v ) { return '<li>' + v + '</li>' ; } ) . join ( '' ) ;
61+ html = html
62+ . replace ( '{style}' , style )
63+ . replace ( '{stack}' , stack )
64+ . replace ( '{title}' , exports . title )
65+ . replace ( '{statusCode}' , res . statusCode )
66+ . replace ( / \{ e r r o r \} / g, escapeHTML ( err . toString ( ) . replace ( / \n / g, '<br/>' ) ) ) ;
67+ res . setHeader ( 'Content-Type' , 'text/html; charset=utf-8' ) ;
68+ res . end ( html ) ;
69+ } ) ;
70+ } ) ;
71+ // json
72+ } else if ( ~ accept . indexOf ( 'json' ) ) {
73+ var error = { message : err . message , stack : err . stack } ;
74+ for ( var prop in err ) error [ prop ] = err [ prop ] ;
75+ var json = JSON . stringify ( { error : error } ) ;
76+ res . setHeader ( 'Content-Type' , 'application/json' ) ;
77+ res . end ( json ) ;
78+ // plain text
79+ } else {
80+ res . setHeader ( 'Content-Type' , 'text/plain' ) ;
81+ res . end ( err . stack ) ;
82+ }
83+ } ;
84+ } ;
85+
86+ /**
87+ * Template title, framework authors may override this value.
88+ */
89+
90+ exports . title = 'Connect' ;
91+
92+
93+ /**
94+ * Escape the given string of `html`.
95+ *
96+ * @param {String } html
97+ * @return {String }
98+ * @api private
99+ */
100+
101+ function escapeHTML ( html ) {
102+ return String ( html )
103+ . replace ( / & (? ! \w + ; ) / g, '&' )
104+ . replace ( / < / g, '<' )
105+ . replace ( / > / g, '>' )
106+ . replace ( / " / g, '"' ) ;
107+ } ;
0 commit comments