Skip to content

Commit 64063b5

Browse files
esprehnmhevery
authored andcommitted
Fix issue where directories don't have a slash on the end and allow specifying a different port
1 parent 833e0ae commit 64063b5

File tree

2 files changed

+99
-42
lines changed

2 files changed

+99
-42
lines changed

lib/nodeserver/server.js

Lines changed: 98 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ var sys = require('sys'),
44
url = require('url'),
55
events = require('events');
66

7-
function main() {
7+
var DEFAULT_PORT = 8000;
8+
9+
function main(argv) {
810
new HttpServer({
911
'GET': (function() {
1012
var servlet = new StaticServlet();
1113
return servlet.handleRequest.bind(servlet)
1214
})()
13-
}).start(8000);
15+
}).start(Number(argv[2]) || DEFAULT_PORT);
1416
}
1517

1618
function escapeHtml(value) {
@@ -44,11 +46,15 @@ HttpServer.prototype.parseUrl_ = function(urlString) {
4446
};
4547

4648
HttpServer.prototype.handleRequest_ = function(req, res) {
47-
sys.puts(req.method + ' ' + req.url);
49+
var logEntry = req.method + ' ' + req.url;
50+
if (req.headers['user-agent']) {
51+
logEntry += ' ' + req.headers['user-agent'];
52+
}
53+
sys.puts(logEntry);
4854
req.url = this.parseUrl_(req.url);
4955
var handler = this.handlers[req.method];
5056
if (!handler) {
51-
res.writeHead(501, 'Not Implemented');
57+
res.writeHead(501);
5258
res.end();
5359
} else {
5460
handler.call(this, req, res);
@@ -79,51 +85,79 @@ StaticServlet.prototype.handleRequest = function(req, res) {
7985
var path = ('./' + req.url.pathname).replace('//','/');
8086
var parts = path.split('/');
8187
if (parts[parts.length-1].charAt(0) === '.')
82-
return self.sendForbidden_(res, path);
88+
return self.sendForbidden_(req, res, path);
8389
fs.stat(path, function(err, stat) {
8490
if (err)
85-
return self.sendMissing_(res, path);
91+
return self.sendMissing_(req, res, path);
8692
if (stat.isDirectory())
87-
return self.sendDirectory_(res, path);
88-
return self.sendFile_(res, path);
93+
return self.sendDirectory_(req, res, path);
94+
return self.sendFile_(req, res, path);
8995
});
9096
}
9197

92-
StaticServlet.prototype.sendError_ = function(res, error) {
93-
res.writeHead(500, 'Internal Server Error', {
98+
StaticServlet.prototype.sendError_ = function(req, res, error) {
99+
res.writeHead(500, {
94100
'Content-Type': 'text/html'
95101
});
96102
res.write('<!doctype html>\n');
97103
res.write('<title>Internal Server Error</title>\n');
98-
res.write('<h1>500 Internal Server Error</h1>');
104+
res.write('<h1>Internal Server Error</h1>');
99105
res.write('<pre>' + escapeHtml(sys.inspect(error)) + '</pre>');
100106
sys.puts('500 Internal Server Error');
101107
sys.puts(sys.inspect(error));
102108
};
103109

104-
StaticServlet.prototype.sendMissing_ = function(res, path) {
105-
res.writeHead(404, 'Not Found', {
110+
StaticServlet.prototype.sendMissing_ = function(req, res, path) {
111+
path = path.substring(1);
112+
res.writeHead(404, {
106113
'Content-Type': 'text/html'
107114
});
108115
res.write('<!doctype html>\n');
109116
res.write('<title>404 Not Found</title>\n');
110-
res.write('<h1>404 Not Found</h1>');
117+
res.write('<h1>Not Found</h1>');
118+
res.write(
119+
'<p>The requested URL ' +
120+
escapeHtml(path) +
121+
' was not found on this server.</p>'
122+
);
111123
res.end();
112124
sys.puts('404 Not Found: ' + path);
113125
};
114126

115-
StaticServlet.prototype.sendForbidden_ = function(res, path) {
116-
res.writeHead(403, 'Forbidden', {
127+
StaticServlet.prototype.sendForbidden_ = function(req, res, path) {
128+
path = path.substring(1);
129+
res.writeHead(403, {
117130
'Content-Type': 'text/html'
118131
});
119132
res.write('<!doctype html>\n');
120133
res.write('<title>403 Forbidden</title>\n');
121-
res.write('<h1>403 Forbidden</h1>');
134+
res.write('<h1>Forbidden</h1>');
135+
res.write(
136+
'<p>You do not have permission to access ' +
137+
escapeHtml(path) + ' on this server.</p>'
138+
);
122139
res.end();
123140
sys.puts('403 Forbidden: ' + path);
124141
};
125142

126-
StaticServlet.prototype.sendFile_ = function(res, path) {
143+
StaticServlet.prototype.sendRedirect_ = function(req, res, redirectUrl) {
144+
res.writeHead(301, {
145+
'Content-Type': 'text/html',
146+
'Location': redirectUrl
147+
});
148+
res.write('<!doctype html>\n');
149+
res.write('<title>301 Moved Permanently</title>\n');
150+
res.write('<h1>Moved Permanently</h1>');
151+
res.write(
152+
'<p>The document has moved <a href="' +
153+
redirectUrl +
154+
'">here</a>.</p>'
155+
);
156+
res.end();
157+
sys.puts('401 Moved Permanently: ' + redirectUrl);
158+
};
159+
160+
StaticServlet.prototype.sendFile_ = function(req, res, path) {
127161
var self = this;
128162
var file = fs.createReadStream(path);
129163
res.writeHead(200, {
@@ -135,38 +169,61 @@ StaticServlet.prototype.sendFile_ = function(res, path) {
135169
res.end();
136170
});
137171
file.on('error', function(error) {
138-
self.sendError_(res, error);
172+
self.sendError_(req, res, error);
139173
});
140174
};
141175

142-
StaticServlet.prototype.sendDirectory_ = function(res, path) {
176+
StaticServlet.prototype.sendDirectory_ = function(req, res, path) {
143177
var self = this;
178+
if (path.match(/[^\/]$/)) {
179+
req.url.pathname += '/';
180+
var redirectUrl = url.format(url.parse(url.format(req.url)));
181+
return self.sendRedirect_(req, res, redirectUrl);
182+
}
144183
fs.readdir(path, function(err, files) {
145184
if (err)
146-
return self.sendError_(res, error);
147-
res.writeHead(200, {
148-
'Content-Type': 'text/html'
185+
return self.sendError_(req, res, error);
186+
187+
if (!files.length)
188+
return self.writeDirectoryIndex_(req, res, path, []);
189+
190+
var remaining = files.length;
191+
files.forEach(function(fileName, index) {
192+
fs.stat(path + '/' + fileName, function(err, stat) {
193+
if (err)
194+
return self.sendError_(req, res, err);
195+
if (stat.isDirectory()) {
196+
files[index] = fileName + '/';
197+
}
198+
if (!(--remaining))
199+
return self.writeDirectoryIndex_(req, res, path, files);
200+
});
149201
});
150-
path = path.substring(2);
151-
res.write('<!doctype html>\n');
152-
res.write('<title>' + escapeHtml(path) + '</title>\n');
153-
res.write('<style>\n');
154-
res.write(' ol { list-style-type: none; font-size: 1.2em; }\n');
155-
res.write('</style>\n');
156-
res.write('<h1>Directory: ' + escapeHtml(path) + '</h1>');
157-
res.write('<ol>');
158-
files.sort();
159-
for (var i=0; i < files.length; ++i) {
160-
if (files[i].charAt(0) !== '.') {
161-
res.write('<li><a href="' +
162-
escapeHtml(files[i]) + '">' +
163-
escapeHtml(files[i]) + '</a></li>');
164-
}
202+
});
203+
};
204+
205+
StaticServlet.prototype.writeDirectoryIndex_ = function(req, res, path, files) {
206+
path = path.substring(1);
207+
res.writeHead(200, {
208+
'Content-Type': 'text/html'
209+
});
210+
res.write('<!doctype html>\n');
211+
res.write('<title>' + escapeHtml(path) + '</title>\n');
212+
res.write('<style>\n');
213+
res.write(' ol { list-style-type: none; font-size: 1.2em; }\n');
214+
res.write('</style>\n');
215+
res.write('<h1>Directory: ' + escapeHtml(path) + '</h1>');
216+
res.write('<ol>');
217+
files.forEach(function(fileName) {
218+
if (fileName.charAt(0) !== '.') {
219+
res.write('<li><a href="' +
220+
escapeHtml(fileName) + '">' +
221+
escapeHtml(fileName) + '</a></li>');
165222
}
166-
res.write('</ol>');
167-
res.end();
168223
});
224+
res.write('</ol>');
225+
res.end();
169226
};
170227

171228
// Must be last,
172-
main();
229+
main(process.argv);

nodeserver.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
node lib/nodeserver/server.js
1+
node lib/nodeserver/server.js $1

0 commit comments

Comments
 (0)