Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 12 additions & 25 deletions lib/paperboy.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,10 @@ var
path = require('path');

exports.filepath = function (webroot, url) {
// Unescape URL to prevent security holes
url = decodeURIComponent(url);
// Append index.html if path ends with '/'
fp = path.normalize(path.join(webroot, (url.match(/\/$/)=='/') ? url+'index.html' : url));
// Sanitize input, make sure people can't use .. to get above webroot
if (webroot[webroot.length - 1] !== '/') webroot += '/';
if (fp.substr(0, webroot.length) != webroot)
fp = path.normalize(path.join(webroot, (url === '/') ? 'index.html' : url));
//console.log('\nfilepath: ', fp, '\nsubstr: ', fp.substr(0,webroot.length + 1), '\n');
//Sanitize input, make sure people can't use .. to get above webroot
if (fp.substr(0,webroot.length + 1) != path.normalize(webroot + '/'))
return(['Permission Denied', null]);
else
return([null, fp]);
Expand All @@ -20,16 +17,17 @@ exports.filepath = function (webroot, url) {
exports.streamFile = function (filepath, headerFields, stat, res, req, emitter) {
var
emitter = new events.EventEmitter(),
extension = filepath.split('.').pop(),
extension = filepath.split('.').slice(-1),
contentType = exports.contentTypes[extension] || 'application/octet-stream',
charset = exports.charsets[contentType];

process.nextTick( function() {

if (charset)
contentType += '; charset=' + charset;
headerFields['Content-Type'] = contentType;

var etag = '"' + stat.ino + '-' + stat.size + '-' + Date.parse(stat.mtime) +'"';
etag = '"' + stat.ino + '-' + stat.size + '-' + Date.parse(stat.mtime) +'"';
headerFields['ETag'] = etag;

var statCode;
Expand All @@ -50,7 +48,7 @@ exports.streamFile = function (filepath, headerFields, stat, res, req, emitter)
res.writeHead(statCode, headerFields);

//If we sent a 304, skip sending a body
if (statCode == 304 || req.method === 'HEAD') {
if (statCode == 304) {
res.end();
emitter.emit("success", statCode);
}
Expand Down Expand Up @@ -110,22 +108,14 @@ exports.deliver = function (webroot, req, res) {
};

process.nextTick(function() {
// Create default error and otherwise callbacks if none were given.
errorCallback = errorCallback || function(statCode) {
res.writeHead(statCode, {'Content-Type': 'text/html'});
res.end("<h1>HTTP " + statCode + "</h1>");
};
otherwiseCallback = otherwiseCallback || function() {
res.writeHead(404, {'Content-Type': 'text/html'});
res.end("<h1>HTTP 404 File not found</h1>");
};

//console.log('fpRes: ', fpRes, '\nfpErr: ', fpErr, '\nwebroot: ', webroot);
//If file is in a directory outside of the webroot, deny the request
if (fpErr) {
statCode = 403;
if (beforeCallback)
beforeCallback();
errorCallback(403, 'Forbidden');
if (errorCallback)
errorCallback(403, 'Forbidden');
}
else {
fs.stat(filepath, function (err, stat) {
Expand All @@ -137,7 +127,7 @@ exports.deliver = function (webroot, req, res) {
otherwiseCallback(exactErr);
} else {
//The before callback can abort the transfer by returning false
var cancel = beforeCallback && (beforeCallback() === false);
cancel = beforeCallback && (beforeCallback() === false);
if (cancel && otherwiseCallback) {
otherwiseCallback();
}
Expand Down Expand Up @@ -194,7 +184,6 @@ exports.contentTypes = {
"hqx": "application/mac-binhex40",
"html": "text/html",
"ice": "x-conference/x-cooltalk",
"ico": "image/x-icon",
"ief": "image/ief",
"igs": "model/iges",
"ips": "application/x-ipscript",
Expand All @@ -211,7 +200,6 @@ exports.contentTypes = {
"m": "text/plain",
"m3u": "audio/x-mpegurl",
"man": "application/x-troff-man",
"manifest": "text/cache-manifest",
"me": "application/x-troff-me",
"midi": "audio/midi",
"mif": "application/x-mif",
Expand Down Expand Up @@ -263,7 +251,6 @@ exports.contentTypes = {
"stp": "application/STEP",
"sv4cpio": "application/x-sv4cpio",
"sv4crc": "application/x-sv4crc",
"svg": "image/svg+xml",
"swf": "application/x-shockwave-flash",
"tar": "application/x-tar",
"tcl": "application/x-tcl",
Expand Down