serve-handler
Advanced tools
Comparing version 3.1.2 to 3.2.0
{ | ||
"name": "serve-handler", | ||
"version": "3.1.2", | ||
"version": "3.2.0", | ||
"description": "The routing foundation of `serve` and static deployments on Now", | ||
@@ -25,3 +25,4 @@ "main": "src/index.js", | ||
"src/index.js", | ||
"src/directory.js" | ||
"src/directory.js", | ||
"src/error.js" | ||
], | ||
@@ -52,2 +53,3 @@ "devDependencies": { | ||
"src/directory.js", | ||
"src/error.js", | ||
"test/*" | ||
@@ -57,2 +59,3 @@ ] | ||
"eslintIgnore": [ | ||
"error.js", | ||
"directory.js", | ||
@@ -59,0 +62,0 @@ "coverage" |
171
src/index.js
@@ -17,3 +17,4 @@ // Native | ||
// Other | ||
const template = require('./directory'); | ||
const directoryTemplate = require('./directory'); | ||
const errorTemplate = require('./error'); | ||
@@ -420,3 +421,3 @@ const getHandlers = methods => Object.assign({ | ||
const output = acceptsJSON ? JSON.stringify(spec) : template(spec); | ||
const output = acceptsJSON ? JSON.stringify(spec) : directoryTemplate(spec); | ||
@@ -426,2 +427,65 @@ return {directory: output}; | ||
const sendError = async (response, acceptsJSON, current, handlers, config, spec) => { | ||
const {err: original, message, code, statusCode} = spec; | ||
if (original) { | ||
console.error(original); | ||
} | ||
response.statusCode = statusCode; | ||
if (acceptsJSON) { | ||
response.setHeader('Content-Type', 'application/json; charset=utf-8'); | ||
response.end(JSON.stringify({ | ||
error: { | ||
code, | ||
message | ||
} | ||
})); | ||
return; | ||
} | ||
let stats = null; | ||
const errorPage = path.join(current, `${statusCode}.html`); | ||
try { | ||
stats = await handlers.stat(errorPage); | ||
} catch (err) { | ||
if (err.code !== 'ENOENT') { | ||
// eslint-disable-next-line no-use-before-define | ||
return internalError(response, acceptsJSON, current, handlers, config, err); | ||
} | ||
} | ||
if (stats) { | ||
const headers = await getHeaders(config.headers, current, errorPage, stats); | ||
const stream = await handlers.createReadStream(errorPage); | ||
response.writeHead(statusCode, headers); | ||
stream.pipe(response); | ||
return; | ||
} | ||
response.setHeader('Content-Type', 'text/html; charset=utf-8'); | ||
response.end(errorTemplate({statusCode, message})); | ||
}; | ||
const internalError = async (...args) => { | ||
const lastIndex = args.length - 1; | ||
const err = args[lastIndex]; | ||
args[lastIndex] = { | ||
statusCode: 500, | ||
code: 'internal_server_error', | ||
message: 'A server error has occurred', | ||
err | ||
}; | ||
return sendError(...args); | ||
}; | ||
module.exports = async (request, response, config = {}, methods = {}) => { | ||
@@ -434,10 +498,16 @@ const cwd = process.cwd(); | ||
let absolutePath = path.join(current, relativePath); | ||
let acceptsJSON = null; | ||
if (request.headers.accept) { | ||
acceptsJSON = request.headers.accept.includes('application/json'); | ||
} | ||
// Prevent path traversal vulnerabilities. We could do this | ||
// by ourselves, but using the package covers all the edge cases. | ||
if (!isPathInside(absolutePath, current)) { | ||
response.statusCode = 400; | ||
response.end('Bad Request'); | ||
return; | ||
return sendError(response, acceptsJSON, current, handlers, config, { | ||
statusCode: 400, | ||
code: 'bad_request', | ||
message: 'Bad Request' | ||
}); | ||
} | ||
@@ -476,8 +546,3 @@ | ||
if (err.code !== 'ENOENT') { | ||
console.error(err); | ||
response.statusCode = 500; | ||
response.end(err.message); | ||
return; | ||
return internalError(response, acceptsJSON, current, handlers, config, err); | ||
} | ||
@@ -498,8 +563,3 @@ } | ||
if (err.code !== 'ENOENT') { | ||
console.error(err); | ||
response.statusCode = 500; | ||
response.end(err.message); | ||
return; | ||
return internalError(response, acceptsJSON, current, handlers, config, err); | ||
} | ||
@@ -514,8 +574,3 @@ } | ||
if (err.code !== 'ENOENT') { | ||
console.error(err); | ||
response.statusCode = 500; | ||
response.end(err.message); | ||
return; | ||
return internalError(response, acceptsJSON, current, handlers, config, err); | ||
} | ||
@@ -525,12 +580,2 @@ } | ||
let acceptsJSON = null; | ||
if (request.headers.accept) { | ||
acceptsJSON = request.headers.accept.includes('application/json'); | ||
} | ||
if (((stats && stats.isDirectory()) || !stats) && acceptsJSON) { | ||
response.setHeader('Content-Type', 'application/json; charset=utf-8'); | ||
} | ||
if (stats && stats.isDirectory()) { | ||
@@ -552,19 +597,14 @@ let directory = null; | ||
} catch (err) { | ||
console.error(err); | ||
response.statusCode = 500; | ||
response.end(err.message); | ||
return; | ||
if (err.code !== 'ENOENT') { | ||
return internalError(response, acceptsJSON, current, handlers, config, err); | ||
} | ||
} | ||
if (directory) { | ||
const contentType = acceptsJSON ? 'application/json; charset=utf-8' : 'text/html; charset=utf-8'; | ||
response.statusCode = 200; | ||
response.setHeader('Content-Type', contentType); | ||
response.end(directory); | ||
// When JSON is accepted, we already set the header before | ||
if (!response.getHeader('Content-Type')) { | ||
response.setHeader('Content-Type', 'text/html; charset=utf-8'); | ||
} | ||
response.end(directory); | ||
return; | ||
@@ -581,36 +621,7 @@ } | ||
if (!stats) { | ||
response.statusCode = 404; | ||
if (acceptsJSON) { | ||
response.end(JSON.stringify({ | ||
error: { | ||
code: 'not_found', | ||
message: 'Not Found' | ||
} | ||
})); | ||
return; | ||
} | ||
const errorPage = path.join(current, '404.html'); | ||
try { | ||
stats = await handlers.stat(errorPage); | ||
} catch (err) { | ||
if (err.code !== 'ENOENT') { | ||
console.error(err); | ||
response.statusCode = 500; | ||
response.end(err.message); | ||
return; | ||
} | ||
} | ||
if (!stats) { | ||
response.end('Not Found'); | ||
return; | ||
} | ||
absolutePath = errorPage; | ||
return sendError(response, acceptsJSON, current, handlers, config, { | ||
statusCode: 404, | ||
code: 'not_found', | ||
message: 'The requested path could not be found' | ||
}); | ||
} | ||
@@ -617,0 +628,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
37834
6
537