Skip to content

Commit 64be4fb

Browse files
committed
2 parents 7ea3e9d + 9349c1b commit 64be4fb

20 files changed

Lines changed: 239 additions & 67 deletions

File tree

bin/ldnode.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@ var argv = require('nomnom')
8484
help: 'Suffix for SSE files (default: \'.events\')',
8585
abbr: 'sE'
8686
})
87+
.option('noErrorPages', {
88+
full: 'no-error-pages',
89+
flag: true,
90+
help: 'Disable custom error pages (use Node.js default pages instead)'
91+
})
92+
.option('errorPages', {
93+
full: 'error-pages',
94+
help: 'Folder from which to look for custom error pages files (files must be named <error-code>.html -- eg. 500.html)'
95+
})
8796
.parse();
8897

8998
// Print version and leave

index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ var putHandler = require('./lib/handlers/put.js');
3232
var deleteHandler = require('./lib/handlers/delete.js');
3333
var patchHandler = require('./lib/handlers/patch.js');
3434

35+
// Error page handler
36+
var errorHandler = require('./lib/handlers/error.js');
37+
3538
// Setting up cors
3639
var corsSettings = cors({
3740
methods: [
@@ -191,6 +194,9 @@ function routes () {
191194
router.delete('/*', deleteHandler.handler);
192195
router.post('/*', postHandler.handler);
193196
router.patch('/*', patchHandler.handler);
197+
198+
//Error handling
199+
router.use(errorHandler.handler);
194200
return router;
195201
}
196202

lib/acl.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -230,13 +230,12 @@ ACL.prototype.allowMode = function (mode, userId, aclGraph, accessType, pathUri,
230230
return callback(allowed);
231231
});
232232
};
233+
233234
/**
234235
* Callback used by allowMode.
235236
* @callback ACL~allowMode_cb
236237
* @param {Boolean} result Found valid ACL statement
237238
*/
238-
239-
240239
ACL.prototype.allowControl = function (mode, userId, aclGraph, accessType, pathUri, callback) {
241240
var acl = this;
242241

@@ -257,12 +256,12 @@ ACL.prototype.allowControl = function (mode, userId, aclGraph, accessType, pathU
257256

258257
}, callback);
259258
};
259+
260260
/**
261261
* Callback used by allowControl.
262262
* @callback ACL~allowControl_cb
263263
* @param {Boolean} result Found valid ACL statement
264264
*/
265-
266265
ACL.prototype.allow = function(mode, address, callback) {
267266
var ldp = this.ldp;
268267
var acl = this;
@@ -384,7 +383,7 @@ ACL.prototype.fetchDocument = function(uri, callback) {
384383
// return an empty body to be parsed
385384
return cb(null, '');
386385
}
387-
386+
388387
return ldp.readFile(documentPath, cb);
389388
});
390389
},
@@ -510,7 +509,7 @@ function allow(mode, req, res, next) {
510509
var reqPath = res && res.locals && res.locals.path ? res.locals.path : req.path;
511510
var acl = reqToACL(req);
512511
acl.allow(mode, reqPath, function(err) {
513-
next(err);
512+
return next(err);
514513
});
515514
}
516515

@@ -540,7 +539,7 @@ exports.allowAppendThenWriteHandler = function(req, res, next) {
540539
}
541540
// Append failed, maybe user can write
542541
allow("Write", req, res, function(err) {
543-
next(err);
542+
return next(err);
544543
});
545544
});
546545

@@ -549,4 +548,4 @@ exports.allowAppendThenWriteHandler = function(req, res, next) {
549548

550549
exports.allowControlHandler = function(req, res, next) {
551550
allowIfACLEnabled("Control", req, res, next);
552-
};
551+
};

lib/handlers/delete.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ var utils = require('../utils.js');
77
var metadata = require('../metadata.js');
88

99
// Delete a container or resource
10-
function handler(req, res) {
10+
function handler(req, res, next) {
1111
debug('DELETE -- ' + req.originalUrl);
1212

1313
var ldp = req.app.locals.ldp;
@@ -16,9 +16,7 @@ function handler(req, res) {
1616
ldp.delete(filename, function(err) {
1717
if (err) {
1818
debug("DELETE -- error: " + err);
19-
return res
20-
.status(err.status)
21-
.send(err.message);
19+
return next(err);
2220
}
2321

2422
debug("DELETE -- Ok.");

lib/handlers/error.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*jslint node: true*/
2+
"use strict";
3+
4+
var fs = require('fs');
5+
6+
function errorPageHandler(err, req, res, next) {
7+
var ldp = req.app.locals.ldp;
8+
if (!ldp.noErrorPages) {
9+
var errorPage = ldp.errorPages +
10+
err.status.toString() + '.html';
11+
fs.readFile(errorPage, 'utf8', function(readErr, text) {
12+
if (readErr) {
13+
defaultErrorHandler(err, res);
14+
} else {
15+
res.status(err.status);
16+
res.send(text);
17+
}
18+
});
19+
} else {
20+
defaultErrorHandler(err, res);
21+
}
22+
}
23+
24+
function defaultErrorHandler(err, res) {
25+
res.status(err.status);
26+
res.send(err.message);
27+
}
28+
29+
exports.handler = errorPageHandler;

lib/handlers/get.js

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ var turtleExtension = '.ttl';
2323
// this should be moved to options
2424
var browseSkin = 'https://linkeddata.github.io/warp/#/list/';
2525

26-
function get(req, res, includeBody) {
26+
function get(req, res, next, includeBody) {
2727
var ldp = req.app.locals.ldp;
2828
var uri = utils.uriBase(req);
2929
var filename = utils.uriToFilename(req.path, ldp.root);
@@ -63,15 +63,13 @@ function get(req, res, includeBody) {
6363
// This should be implemented in LDP.prototype.get
6464
if (err && err.status === 404 && glob.hasMagic(filename)) {
6565
debug("GET/HEAD -- Glob request");
66-
return globHandler(req, res);
66+
return globHandler(req, res, next);
6767
}
6868

6969

7070
if (err) {
7171
debug('GET/HEAD -- Read error: ' + err.status + ' ' + err.message);
72-
return res
73-
.status(err.status)
74-
.send(err.message);
72+
return next(err);
7573
}
7674

7775
// Just return that file exists
@@ -108,11 +106,11 @@ function get(req, res, includeBody) {
108106

109107
// TODO this should be added as a middleware in the routes
110108
res.locals.turtleData = data;
111-
return parseLinkedData(req, res);
109+
return parseLinkedData(req, res, next);
112110
});
113111
}
114112

115-
function globHandler(req, res) {
113+
function globHandler(req, res, next) {
116114
var ldp = req.app.locals.ldp;
117115
var filename = utils.uriToFilename(req.path, ldp.root);
118116
var uri = utils.uriBase(req);
@@ -125,7 +123,10 @@ function globHandler(req, res) {
125123
glob(filename, globOptions, function(err, matches) {
126124
if (err || matches.length === 0) {
127125
debug("GET/HEAD -- No files matching the pattern");
128-
return res.sendStatus(404);
126+
var globErr = new Error();
127+
globErr.status = 404;
128+
globErr.message = "No files matching glob pattern";
129+
return next(globErr);
129130
}
130131

131132
// Matches found
@@ -162,7 +163,7 @@ function globHandler(req, res) {
162163
'text/turtle');
163164
// TODO this should be added as a middleware in the routes
164165
res.locals.turtleData = data;
165-
return parseLinkedData(req, res);
166+
return parseLinkedData(req, res, next);
166167
});
167168
});
168169
}
@@ -181,7 +182,7 @@ function aclAllow(match, req, res, callback) {
181182
});
182183
}
183184

184-
function parseLinkedData(req, res) {
185+
function parseLinkedData(req, res, next) {
185186
var ldp = req.app.locals.ldp;
186187
var filename = utils.uriToFilename(req.path, ldp.root);
187188
var uri = utils.uriBase(req);
@@ -206,16 +207,20 @@ function parseLinkedData(req, res) {
206207
$rdf.parse(turtleData, resourceGraph, baseUri, 'text/turtle');
207208
} catch (err) {
208209
debug("GET/HEAD -- Error parsing data: " + err);
209-
return res
210-
.status(500)
211-
.send(err);
210+
var parseErr = new Error();
211+
parseErr.status = 500;
212+
parseErr.message = err.message;
213+
return next(parseErr);
212214
}
213215

214216
// Graph to `accept` type
215217
$rdf.serialize(undefined, resourceGraph, null, accept, function(err, result) {
216218
if (result === undefined || err) {
217219
debug("GET/HEAD -- Serialization error: " + err);
218-
return res.sendStatus(500);
220+
var serializeErr = new Error();
221+
serializeErr.status = 500;
222+
serializeErr.message = err.message;
223+
return next(serializeErr);
219224
}
220225

221226
return res
@@ -225,12 +230,12 @@ function parseLinkedData(req, res) {
225230
});
226231
}
227232

228-
function getHandler(req, res) {
229-
get(req, res, true);
233+
function getHandler(req, res, next) {
234+
get(req, res, next, true);
230235
}
231236

232-
function headHandler(req, res) {
233-
get(req, res, false);
237+
function headHandler(req, res, next) {
238+
get(req, res, next, false);
234239
}
235240

236241
exports.handler = getHandler;

lib/handlers/patch.js

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ var debug = require('../logging').handlers;
99
var utils = require('../utils.js');
1010
var subscription = require('../subscription.js');
1111

12-
function handler(req, res) {
12+
function handler(req, res, next) {
1313
var ldp = req.app.locals.ldp;
1414
debug('PATCH -- ' + req.originalUrl);
1515
debug('PATCH -- text length: ' + (req.text ? req.text.length : 'undefined2'));
@@ -26,9 +26,7 @@ function handler(req, res) {
2626
if (patchContentType === 'application/sparql') {
2727
sparql(filename, targetURI, req.text, function(err, result) {
2828
if (err) {
29-
return res
30-
.status(err.status)
31-
.send(err.message);
29+
next(err);
3230
}
3331

3432
return res.json(result);
@@ -37,9 +35,7 @@ function handler(req, res) {
3735
if (patchContentType === 'application/sparql-update') {
3836
return sparqlUpdate(filename, targetURI, req.text, function (err, patchKB) {
3937
if (err) {
40-
return res
41-
.status(err.status)
42-
.send(err.message);
38+
return next(err);
4339
}
4440

4541
if (ldp.live) {
@@ -49,9 +45,11 @@ function handler(req, res) {
4945
res.send("Patch applied OK\n");
5046
});
5147
} else {
52-
return res
53-
.status(400)
54-
.send("Sorry unknowm patch content type: " + patchContentType);
48+
var contentErr = new Error();
49+
contentErr.status = 400;
50+
contentErr.message = "Sorry unknowm patch content type: " +
51+
patchContentType;
52+
next(contentErr);
5553
}
5654
} // postOrPatch
5755

lib/handlers/post.js

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ var patch = require('./patch.js');
1414
var ldpVocab = require('../vocab/ldp.js');
1515
var rdfVocab = require('../vocab/rdf.js');
1616

17-
function handler(req, res) {
17+
function handler(req, res, next) {
1818
var ldp = req.app.locals.ldp;
1919
var contentType = req.get('content-type');
2020

@@ -38,9 +38,10 @@ function handler(req, res) {
3838
contentType != 'application/nquads' &&
3939
contentType != 'application/n-quads') {
4040
debug("POST -- Invalid Content Type: " + contentType);
41-
return res
42-
.status(415)
43-
.send("Invalid Content Type");
41+
var contentErr = new Error();
42+
contentErr.status = 415;
43+
contentErr.message = "Invalid Content Type";
44+
return next(contentErr);
4445
}
4546

4647

@@ -50,9 +51,11 @@ function handler(req, res) {
5051
// Not a container
5152
if (containerPath[containerPath.length - 1] != '/') {
5253
debug("POST -- Requested resource is not a container");
53-
return res
54-
.set('Allow', 'GET,HEAD,PUT,DELETE')
55-
.sendStatus(405);
54+
res.set('Allow', 'GET,HEAD,PUT,DELETE');
55+
var allowErr = new Error();
56+
allowErr.status = 405;
57+
allowErr.message = "Requested resource is not a container";
58+
return next(allowErr);
5659
}
5760

5861
debug("POST -- Content Type: " + contentType);
@@ -69,7 +72,10 @@ function handler(req, res) {
6972
if (resourcePath === null) {
7073
ldp.releaseResourceUri(resourcePath);
7174
debug("POST -- URI already exists or in use");
72-
return res.sendStatus(400);
75+
var resourceErr = new Error();
76+
resourceErr.status = 400;
77+
resourceErr.message = "URI already exists or in use";
78+
return next(resourceErr);
7379
}
7480

7581
// Creating a graph and add the req text
@@ -90,7 +96,8 @@ function handler(req, res) {
9096
} catch (parseErr) {
9197
debug("POST -- Error parsing resource: " + parseErr);
9298
ldp.releaseResourceUri(resourcePath);
93-
return res.sendStatus(400);
99+
parseErr.status = 400;
100+
return next(parseErr);
94101
}
95102

96103
// Add header link to the resource
@@ -116,7 +123,10 @@ function handler(req, res) {
116123
function containerCallback(err) {
117124
if (err) {
118125
debug("POST -- Error creating new container: " + err);
119-
return res.sendStatus(500);
126+
var createErr = new Error();
127+
createErr.status = 500;
128+
createErr.message = "Cannot create new container";
129+
return next(createErr);
120130
}
121131
debug("POST -- Created new container " + resourceBaseUri);
122132
res.set('Location', resourceBaseUri);
@@ -126,7 +136,10 @@ function handler(req, res) {
126136
function resourceCallback(err) {
127137
if (err) {
128138
debug("POST -- Error creating resource: " + err);
129-
return res.sendStatus(500);
139+
var createErr = new Error();
140+
createErr.status = 500;
141+
createErr.message = "Cannot create new container";
142+
return next(createErr);
130143
}
131144
res.set('Location', resourceBaseUri);
132145
return res.sendStatus(201);

0 commit comments

Comments
 (0)