/src/handler.js |
@@ -21,9 +21,9 @@ |
} |
|
// Serves files. |
function files(config, request, response, resource, callback) { |
function files(config, request, response, requestPath, callback) { |
// Check if the file is accessible. |
fs.access(resource, fs.constants.R_OK, (error) => { |
fs.access(requestPath, fs.constants.R_OK, (error) => { |
if (error) { |
response.statusCode = 403; |
response.end(); |
@@ -32,10 +32,10 @@ |
|
response.setHeader( |
'Content-Type', |
mime.lookup(resource) |
mime.lookup(requestPath) |
); |
|
var readStream = fs.createReadStream(resource) |
var readStream = fs.createReadStream(requestPath) |
.on('open', () => { |
response.statusCode = 200; |
readStream.pipe(response); |
@@ -49,43 +49,47 @@ |
} |
|
// Serves a directory listing or the document index in case it exists. |
function index(config, request, response, resource, root, callback) { |
const root = path.resolve(resource, config.site.index); |
function index(config, request, response, requestPath, requestURL, callback) { |
const root = path.resolve(requestPath, config.site.index); |
fs.stat(root, (error, stats) => { |
if (error && config.site.indexing |
.some((directory) => directory.toUpperCase() == resource.toUpperCase())) { |
fs.readdir(resource, (error, paths) => { |
if (error) { |
if (error) { |
if(config.site.indexing |
.some((directory) => |
directory.toUpperCase() === requestURL.toUpperCase())) { |
fs.readdir(requestPath, (error, paths) => { |
if (error) { |
process.nextTick(() => { |
callback('Could not list directory: ' + |
requestPath, |
module.exports.error.level.ERROR |
); |
}); |
response.statusCode = 500; |
response.end(); |
return; |
} |
process.nextTick(() => { |
callback('Could not list directory: ' + |
resource, |
module.exports.error.level.ERROR |
callback('Directory listing requested for: ' + |
requestPath, |
module.exports.error.level.INFO |
); |
}); |
response.statusCode = 500; |
response.statusCode = 200; |
response.write(JSON.stringify(paths)); |
response.end(); |
return; |
} |
process.nextTick(() => { |
callback('Directory listing requested for: ' + |
resource, |
module.exports.error.level.INFO |
); |
}); |
response.statusCode = 200; |
response.write(JSON.stringify(paths)); |
response.end(); |
}); |
|
return; |
return; |
} |
|
} |
|
// Serve the document index. |
fs.access(resource, fs.constants.R_OK, (error) => { |
fs.access(requestPath, fs.constants.R_OK, (error) => { |
if (error) { |
process.nextTick(() => { |
callback('The server was unable to access the filesystem path: ' + |
resource, |
requestPath, |
module.exports.error.level.WARN |
); |
}); |
@@ -114,9 +118,9 @@ |
}); |
} |
|
// Determines whether the requested resource is a directory or a file. |
function serve(config, request, response, resource, callback) { |
fs.stat(resource, (error, stats) => { |
// Determines whether the requested filesystem request path is a directory or a file. |
function serve(config, request, response, requestPath, requestURL, callback) { |
fs.stat(requestPath, (error, stats) => { |
// Document does not exist. |
if (error) { |
response.statusCode = 404; |
@@ -126,10 +130,10 @@ |
|
switch (stats.isDirectory()) { |
case true: // Directory is requested so provide directory indexes. |
index(config, request, response, resource, callback); |
index(config, request, response, requestPath, requestURL, callback); |
break; |
default: // Browser requesting file. |
files(config, request, response, resource, callback); |
files(config, request, response, requestPath, callback); |
break; |
} |
}); |
@@ -155,20 +159,20 @@ |
}); |
|
const requestAddress = request.socket.address(); |
const requestedURL = url.parse( |
const requestURL = url.parse( |
request.url, true |
); |
|
const trimmedPath = requestedURL |
const trimmedPath = requestURL |
.pathname |
.split('/') |
.filter(Boolean) |
.join('/'); |
const resource = trimmedPath === '/' ? |
const requestPath = trimmedPath === '/' ? |
path.join(root, trimmedPath) : |
path.resolve(root, trimmedPath); |
|
isRooted(resource, root, path.sep, (rooted) => { |
isRooted(requestPath, root, path.sep, (rooted) => { |
if (!rooted) { |
process.nextTick(() => { |
callback('Attempted path traversal: ' + |
@@ -175,7 +179,7 @@ |
requestAddress.address + ':' + |
requestAddress.port + |
' requesting: ' + |
requestedURL.pathname, |
requestURL.pathname, |
module.exports.error.level.WARN |
); |
}); |
@@ -186,7 +190,7 @@ |
|
// Check if the requested path requires authentication. |
switch (config.auth.locations.some( |
(authPath) => authPath.toUpperCase() === requestedURL.pathname.toUpperCase())) { |
(authPath) => authPath.toUpperCase() === requestURL.pathname.toUpperCase())) { |
case true: |
// Requested location requires authentication. |
authentication.check(request, response, (request, response) => { |
@@ -195,11 +199,17 @@ |
requestAddress.address + ':' + |
requestAddress.port + |
' accessing: ' + |
requestedURL.pathname, |
requestURL.pathname, |
module.exports.error.level.INFO |
); |
}); |
serve(config, request, response, resource, callback); |
serve(config, |
request, |
response, |
requestPath, |
requestURL.pathname, |
callback |
); |
}); |
break; |
default: |
@@ -208,11 +218,17 @@ |
requestAddress.address + ':' + |
requestAddress.port + |
' accessing: ' + |
requestedURL.pathname, |
requestURL.pathname, |
module.exports.error.level.INFO |
); |
}); |
serve(config, request, response, resource, callback); |
serve(config, |
request, |
response, |
requestPath, |
requestURL.pathname, |
callback |
); |
break; |
} |
}); |