UNPKG

3.46 kBJavaScriptView Raw
1/*
2 * pub-server handle-errors.js
3 * NOTE:
4 * - this should be the last handler loaded by the server
5 * - depends on serve-pages being invoked before this
6 *
7 * copyright 2015-2020, Jürgen Leschner - github.com/jldec - MIT license
8 */
9
10/*eslint no-unused-vars: "off"*/
11
12var debug = require('debug')('pub:server');
13var path = require('path');
14var ppath = path.posix || path;
15var u = require('pub-util');
16
17module.exports = function handleErrors(server) {
18
19 // sugar
20 var opts = server.opts;
21 var log = opts.log;
22 var app = server.app;
23 var generator = server.generator;
24
25 app.use('/server/echo', testEcho);
26
27 // dev/test routes
28 if (!opts.production) {
29 app.use('/admin/testthrow', testThrow);
30 app.use('/admin/testerr', testErr);
31 app.use('/admin/testpost', testPost);
32 app.use('/admin/testget', testGet);
33 }
34
35 // mount 404 and 500 handlers
36 app.use(notFound);
37 app.use(errHandler);
38
39 return;
40
41 //--//--//--//--//--//--//--//--//--//--//
42
43 // return 404 except for html pages
44 function notFound(req, res) {
45
46 var ext = ppath.extname(req.path);
47 if ((!ext || /\.htm|\.html/i.test(ext)) && !u.size(req.query)) return error(404, req, res);
48
49 debug('404 %s', req.originalUrl);
50 res.status(404).end();
51 }
52
53 // error handler middleware - must have 4 parameters
54 // body-parser returns err.status = 400 on POST with invalid json (application/json content-type)
55 //
56 function errHandler(err, req, res, next) {
57 // if (!err.status) { log(err); }
58 log(err);
59 error(err.status || 500, req, res, u.str(err));
60 }
61
62 // general purpose error response
63 function error(status, req, res, msg) {
64 debug('%s %s', status, req.originalUrl);
65 msg = msg || '';
66
67 var page = generator.page$['/' + status];
68
69 // 404 with no matching status page => redirect to home
70 if (!page && status === 404) {
71 if (generator.home) return res.redirect(302, '/');
72 if (server.statics.defaultFile) return res.redirect(302, server.statics.defaultFile);
73 }
74
75 // avoid exposing error pages unless authorized
76 if (page) {
77 if (!server.isPageAuthorized || !server.isPageAuthorized(req, page)) {
78 if (server.login) return server.login(req, res);
79 else page = null;
80 }
81 }
82
83 if (!page) return res.status(status).send(u.escape(msg));
84
85 res.status(status).send(
86 generator.renderDoc(page)
87 .replace(/%s/g, u.escape(msg)) // TODO - replace with humane.js or proper template
88 .replace('<body', '<body data-err-status="' + status + '"' + (msg ? ' data-err-msg="' + u.escape(msg) + '"' : ''))
89 );
90 }
91
92 function testThrow() {
93 throw new Error('test throw');
94 }
95
96 function testErr(req, res) {
97 log(new Error('test err')); // will throw if no on('error') handler - see session.log
98 error(403, req, res, '/admin/testerr'); // forbidden
99 }
100
101 function testPost(req, res) {
102 log('/admin/testpost', req.body);
103 res.status(200).send('OK');
104 }
105
106 function testGet(req, res) {
107 log('/admin/testget', req.query);
108 res.status(200).send('OK');
109 }
110
111 function testEcho(req, res) {
112 res.send(echoreq(req));
113 }
114
115 function echoreq(req) {
116 return {
117 ip: req.ip,
118 method: req.method,
119 url: req.originalUrl,
120 headers: req.headers,
121 query: req.query,
122 params: req.params,
123 body: req.body,
124 now: Date(),
125 user: req.user,
126 sessionID: req.sessionID,
127 session: req.session
128 };
129 }
130};