Skip to content

Commit c3d46bf

Browse files
author
Kit Goncharov
committed
Extract the code for creating a new server from the command line into a simple executable. Add support for using servedir as a module.
1 parent 5f941ef commit c3d46bf

4 files changed

Lines changed: 189 additions & 166 deletions

File tree

bin/servedir

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/usr/bin/env node
2+
3+
var path = require('path'), fs = require('fs');
4+
5+
fs.realpath(__filename, function(error, script) {
6+
var servedir, root, port;
7+
if (error) throw error;
8+
9+
// Load `servedir`.
10+
servedir = require(path.join(path.dirname(script), '../lib/servedir'));
11+
12+
// Configure the root directory and port.
13+
root = process.argv[2];
14+
port = process.argv[3];
15+
16+
if (!port) {
17+
// Port specified as the first argument; root directory omitted.
18+
if ((port = Math.ceil(root)) > -1) {
19+
root = null;
20+
} else {
21+
// Use the default port if the port was omitted.
22+
port = servedir.defaultPort;
23+
}
24+
}
25+
26+
// Use the default directory if the root directory was omitted.
27+
if (!root) root = '.';
28+
29+
// Create a new server.
30+
servedir(root, port);
31+
32+
console.log('Serving %s on port %d...', root, port);
33+
});

lib/servedir.js

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// servedir HTTP Server
2+
// https://github.com/rem/servedir
3+
4+
// Copyright 2011, Remy Sharp
5+
// http://remysharp.com
6+
7+
// Convenience aliases.
8+
var createServer = require('http').createServer, parse = require('url').parse, path = require('path'), fs = require('fs'), types,
9+
10+
// Matches control characters in URLs.
11+
escapable = /[\x00-\x1f\x7f"'&?$\x20+,:;=@<>#%{}|\\\^~\[\]`]/g,
12+
13+
// Escape sequences and entities for control characters.
14+
escapes = {
15+
'&': '&amp;',
16+
'<': '&lt;',
17+
'>': '&gt;',
18+
'"': '&quot;',
19+
'\'': '&apos;'
20+
},
21+
22+
// The `servedir` function creates a new simple HTTP server.
23+
servedir = module.exports = function(root, port) {
24+
if (typeof root != 'string') root = servedir.defaultRoot;
25+
if (typeof port != 'number') port = servedir.defaultPort;
26+
// Create a new HTTP server.
27+
var server = createServer(function(req, res) {
28+
// Resolve the path to the requested file or folder.
29+
var pathname = parse(decodeURIComponent(req.url)).pathname, file = path.join(root, pathname);
30+
path.exists(file, function(exists) {
31+
if (!exists) {
32+
res.writeHead(404, {'Content-Type': 'text/plain'});
33+
res.end('The file ' + file + ' was not found.');
34+
} else {
35+
// Serve files and directories.
36+
fs.stat(file, function(err, stats) {
37+
if (err) {
38+
// Internal server error; avoid throwing an exception.
39+
res.writeHeader(500, {'Content-Type': 'text/plain'});
40+
res.end('An internal server error occurred: ' + err);
41+
} else if (stats.isFile()) {
42+
// Read and serve files.
43+
fs.readFile(file, 'binary', function(err, contents) {
44+
if (err) {
45+
// Internal server error; avoid throwing an exception.
46+
res.writeHeader(500, {'Content-Type': 'text/plain'});
47+
res.write('An internal server error occurred: ' + err);
48+
} else {
49+
// Set the correct MIME type using the extension.
50+
res.writeHead(200, {'Content-Type': types[path.extname(file).slice(1)] || servedir.defaultType});
51+
res.write(contents, 'binary');
52+
}
53+
// Close the connection.
54+
res.end();
55+
});
56+
} else {
57+
// Automatically append a trailing slash for directories.
58+
if (pathname.charAt(pathname.length - 1) != '/') pathname += '/';
59+
fs.readdir(file, function(err, files) {
60+
if (err) {
61+
res.writeHeader(500, {'Content-Type': 'text/plain'});
62+
res.write('An internal server error occurred: ' + err);
63+
} else {
64+
// Create a basic directory listing.
65+
files = files.map(function(name) {
66+
// URL-encode the path to each file or directory.
67+
return '<a href="' + (pathname + name).replace(escapable, function(match) {
68+
// Cache escape sequences not already in the escapes hash.
69+
return escapes[match] || (escapes[match] = '%' + match.charCodeAt(0).toString(16));
70+
}) + '">' + name + '</a>';
71+
});
72+
// Add a link to the root directory.
73+
if (pathname != '/') files.unshift('<a href="..">..</a>');
74+
res.writeHead(200, {'Content-Type': 'text/html'});
75+
res.write('<!DOCTYPE html><meta charset=utf-8><title>[dir] ' + file + '</title><ul><li>' + files.join('<li>') + '</ul>');
76+
}
77+
res.end();
78+
});
79+
}
80+
});
81+
}
82+
});
83+
});
84+
server.listen(port);
85+
return server;
86+
};
87+
88+
// The current version of `servedir`. Keep in sync with `package.json`.
89+
servedir.version = '0.1.5';
90+
91+
// The default MIME type, root directory, and port.
92+
servedir.defaultType = 'application/octet-stream';
93+
servedir.defaultRoot = '.';
94+
servedir.defaultPort = 8000;
95+
96+
// Common MIME types.
97+
servedir.types = types = {
98+
'aiff': 'audio/x-aiff',
99+
'appcache': 'text/cache-manifest',
100+
'atom': 'application/atom+xml',
101+
'bmp': 'image/bmp',
102+
'crx': 'application/x-chrome-extension',
103+
'css': 'text/css',
104+
'eot': 'application/vnd.ms-fontobject',
105+
'gif': 'image/gif',
106+
'htc': 'text/x-component',
107+
'html': 'text/html',
108+
'ico': 'image/vnd.microsoft.icon',
109+
'ics': 'text/calendar',
110+
'jpeg': 'image/jpeg',
111+
'js': 'text/javascript',
112+
'json': 'application/json',
113+
'mathml': 'application/mathml+xml',
114+
'midi': 'audio/midi',
115+
'mov': 'video/quicktime',
116+
'mp3': 'audio/mpeg',
117+
'mp4': 'video/mp4',
118+
'mpeg': 'video/mpeg',
119+
'ogg': 'video/ogg',
120+
'otf': 'font/opentype',
121+
'pdf': 'application/pdf',
122+
'png': 'image/png',
123+
'rtf': 'application/rtf',
124+
'sh': 'application/x-sh',
125+
'svg': 'image/svg+xml',
126+
'swf': 'application/x-shockwave-flash',
127+
'tar': 'application/x-tar',
128+
'tiff': 'image/tiff',
129+
'ttf': 'font/truetype',
130+
'txt': 'text/plain',
131+
'wav': 'audio/x-wav',
132+
'webm': 'video/webm',
133+
'webp': 'image/webp',
134+
'woff': 'font/woff',
135+
'xhtml': 'application/xhtml+xml',
136+
'xml': 'text/xml',
137+
'xsl': 'application/xml',
138+
'xslt': 'application/xslt+xml',
139+
'zip': 'application/zip'
140+
};
141+
142+
// MIME type aliases for different extensions.
143+
types.aif = types.aiff;
144+
types.htm = types.html;
145+
types.jpe = types.jpg = types.jpeg;
146+
types.jsonp = types.js;
147+
types.manifest = types.appcache;
148+
types.mid = types.midi;
149+
types.mpg = types.mpeg;
150+
types.ogv = types.ogg;
151+
types.rb = types.txt;
152+
types.svgz = types.svg;
153+
types.tif = types.tiff;
154+
types.xht = types.xhtml;

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"version": "0.1.5",
44
"description": "Creates a simple web server for a directory",
55
"homepage": "https://github.com/remy/servedir",
6-
"main": "servedir",
6+
"main": "./lib/servedir",
77
"keywords": ["development", "web", "server", "terminal"],
88
"author": {
99
"name": "Remy Sharp",
@@ -14,6 +14,6 @@
1414
"url": "https://github.com/remy/servedir.git"
1515
},
1616
"bin": {
17-
"servedir": "./servedir.js"
17+
"servedir": "./bin/servedir"
1818
}
1919
}

servedir.js

Lines changed: 0 additions & 164 deletions
This file was deleted.

0 commit comments

Comments
 (0)