Socket
Socket
Sign inDemoInstall

ecstatic

Package Overview
Dependencies
Maintainers
1
Versions
79
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ecstatic - npm Package Compare versions

Comparing version 0.0.0 to 0.0.1

example/core.js

5

example/express.js
var express = require('express');
var ecstatic = require('../')(__dirname + '/public');
var ecstatic = require('../lib/ecstatic');
var app = express.createServer();
app.use(ecstatic);
app.use(ecstatic(__dirname + '/public'));
app.use(ecstatic.showDir(__dirname + '/public'));
app.listen(8080);
console.log('Listening on :8080');
var union = require('union');
var ecstatic = require('../')(__dirname + '/public');
var ecstatic = require('../');
union.createServer({
before: [
ecstatic
ecstatic(__dirname + '/public'),
ecstatic.showDir(__dirname + '/public')
]

@@ -8,0 +9,0 @@ }).listen(8080);

126

lib/ecstatic.js

@@ -5,14 +5,12 @@ var path = require('path'),

mime = require('mime'),
showDir = require('./ecstatic/showdir');
showDir = require('./ecstatic/showdir'),
version = JSON.parse(
fs.readFileSync(__dirname + '/../package.json').toString()
).version,
status = require('./ecstatic/status-handlers'),
etag = require('./ecstatic/etag');
// TODO:
//
// * Server info (ecstatic-0.0.0)
var cache = 3600; // cache-ing time in seconds
exports.showDir = showDir;
module.exports = function (dir) {
var root = path.resolve(dir) + '/';
var ecstatic = module.exports = function (dir, opts) {
var root = path.resolve(dir) + '/',
cache = (opts && opts.cache) || 3600; // cache-ing time in seconds.

@@ -22,87 +20,75 @@ return function middleware (req, res, next) {

var parsed = url.parse(req.url),
pathname = decodeURI(parsed.pathname),
file = path.normalize(path.join(root, parsed.pathname));
// 403 if the path goes outside the root.
// Set common headers.
res.setHeader('server', 'ecstatic-'+version);
res.setHeader('date', (new Date()).toUTCString());
if (file.slice(0, root.length) !== root) {
if (next) {
next();
}
else {
res.statusCode = 403;
if (res.writable) {
res.setHeader('content-type', 'text/plain');
res.end('ACCESS DENIED');
}
}
return;
return status[403](res, next);
}
// Read in the file!
if (req.method && (req.method !== 'GET' && req.method !== 'HEAD' )) {
return status[405](res, next);
}
fs.stat(file, function (err, stat) {
if (err && err.code === 'ENOENT') {
if (typeof next === 'function') {
next();
}
else {
res.statusCode = 404;
if (res.writable) {
res.setHeader('content-type', 'text/plain');
// TODO: Make pluggable.
res.end('File not found. :(');
}
}
status[404](res, next);
}
else if (err) {
res.statusCode = 500;
// TODO: Don't share the error code with the user.
res.end(err.stack || err.toString());
status[500](res, next, { error: err });
}
else if (stat.isDirectory()) {
// Directory view!
var req_ = {
url : path.join(parsed.pathname, '/index.html')
};
// Pass the new url to our middleware.
// Use 'next' if it exists, otherwise our fancy-schmancy
// "showdir" middleware.
var handler = (typeof next === 'function')
? next
: function () {
showDir(file, parsed.pathname, res);
showDir(file, pathname, stat, cache)(req, res);
};
middleware(req_, res, handler);
middleware({
url: path.join(pathname, '/index.html')
}, res, handler);
}
else {
var etag = JSON.stringify([stat.ino, stat.size, stat.mtime].join('-'));
// TODO: Helper for this, with default headers.
res.setHeader('content-type', mime.lookup(file) || 'application/octet-stream');
res.setHeader('etag', etag);
res.setHeader('date', (new Date()).toUTCString());
res.setHeader('etag', etag(stat));
res.setHeader('last-modified', (new Date(stat.mtime)).toUTCString());
res.setHeader('cache-control', 'max-age='+cache);
res.setHeader('server', 'ecstatic-0.0.0');
// Return a 304 if necessary
if ( (req.headers['if-none-match'] === etag)
|| (Date.parse(req.headers['if-none-match']) >= stat.mtime ) ) {
res.statusCode = 304;
res.end();
if ( req.headers
&& ( (req.headers['if-none-match'] === etag)
|| (Date.parse(req.headers['if-none-match']) >= stat.mtime )
)
) {
status[304](res, next);
}
else {
// Serve it up!
var stream = fs.createReadStream(file);
res.setHeader(
'content-type',
mime.lookup(file) || 'application/octet-stream'
);
stream.pipe(res);
stream.on('error', function (err) {
res.statusCode = 500;
if (res.writable) {
res.end(err && err.stack || err.toString());
}
});
if (req.method === "HEAD") {
res.statusCode = 200;
res.end();
}
else {
var stream = fs.createReadStream(file);
stream.pipe(res);
stream.on('error', function (err) {
status['500'](res, next, { error: err });
});
stream.on('end', function () {
res.statusCode = 200;
res.end();
});
}
}

@@ -113,1 +99,5 @@ }

};
ecstatic.version = version;
ecstatic.showDir = showDir;

@@ -1,42 +0,113 @@

var fs = require('fs');
var path = require('path');
var ent = require('ent');
var ecstatic = require('../ecstatic'),
fs = require('fs'),
path = require('path'),
ent = require('ent'),
etag = require('./etag'),
url = require('url'),
status = require('./status-handlers');
module.exports = function (dir, pathname, res) {
fs.readdir(dir, function (err, xs) {
if (err) {
res.statusCode = 500;
res.end(err && err.stack || err.toString());
module.exports = function (dir, pathname, stat, cache) {
var root = path.resolve(dir) + '/';
return function (req, res, next) {
if (typeof pathname === 'undefined') {
pathname = url.parse(req.url).pathname;
}
else {
var pending = xs.length;
var dirs = [], files = [], errs = [];
function writeFile (file) {
var p = path.join(pathname, file);
res.write(
'<div><a href="' + encodeURI(p) + '">'
+ ent.encode(file) + '</a></div>'
);
if (typeof file === 'undefined') {
file = path.normalize(path.join(root, pathname));
}
if (typeof cache === 'undefined') {
cache = 3600*1000;
}
(function (cb) {
fs.stat(file, cb);
})(function (err, stat) {
if (err) {
return status[500](res, next, { error: err });
}
function finish () {
dirs.sort().forEach(function (file) {
writeFile(file + '/');
fs.readdir(dir + pathname, function (err, files) {
if (err) {
return status[500](res, next, { error: err });
}
res.setHeader('content-type', 'text/html');
res.setHeader('etag', etag(stat));
res.setHeader('last-modified', (new Date(stat.mtime)).toUTCString());
res.setHeader('cache-control', 'max-age='+cache);
var sortByIsDirectory = function (paths, cb) {
var pending = paths.length,
errs = [],
dirs = [],
files = [];
paths.forEach(function (file) {
fs.stat(dir + pathname + '/' + file, function (err, s) {
if (err) {
errs.push(err);
}
else if (s.isDirectory()) {
dirs.push(file);
}
else {
files.push(file);
}
if (--pending === 0) {
cb(errs, dirs, files);
}
});
});
}
sortByIsDirectory(files, function (errs, dirs, files) {
if (errs.length > 0) {
return status[500](res, next, { error: errs[0] });
}
// Lifted from nodejitsu's http server.
var html = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"\
"http://www.w3.org/TR/html4/loose.dtd">\
<html> \
<head> \
<title>Index of ' + pathname +'</title> \
</head> \
<body> \
<h1>Index of ' + pathname + '</h1>';
html += '<table>';
var writeRow = function (file, i) {
html += '<tr><td>' + '<a href="'
+ ent.encode(encodeURI(
((req.url == '/') ? '' : req.url)
+ '/'
+ file
)) + '">' + ent.encode(file) + '</a></td></tr>';
}
dirs.sort().forEach(writeRow);
files.sort().forEach(writeRow);
html += '</table>';
html += '<br><address>Node.js '
+ process.version
+ '/<a href="https://github.com/jesusabdullah/node-ecstatic">ecstatic</a>'
+ ' server running @ '
+ ent.encode(req.headers.host) + '</address>'
+ '</body></html>'
;
res.writeHead(200, { "Content-Type": "text/html" });
res.end(html);
});
files.sort().forEach(writeFile);
res.end();
}
xs.forEach(function (file) {
fs.stat(dir + '/' + file, function (err, s) {
if (err) errs.push(err)
else if (s.isDirectory()) dirs.push(file)
else files.push(file)
if (--pending === 0) finish()
});
});
}
});
});
}
};

@@ -5,3 +5,3 @@ {

"description": "A simple static file server middleware that works with both Express and Flatiron",
"version": "0.0.0",
"version": "0.0.1",
"homepage": "https://github.com/jesusabdullah/node-ecstatic",

@@ -21,3 +21,4 @@ "repository": {

"files",
"mime"
"mime",
"middleware"
],

@@ -36,8 +37,3 @@ "engines": {

"union" : "0.1.x"
},
"directories" : {
"test" : "test",
"example" : "example",
"lib" : "."
}
}

@@ -5,5 +5,5 @@ # Ecstatic

* simple directory listings
* show index.html files at directory roots when they exist
* use it with a raw http server, connect/express, or flatiron/union
* Built-in simple directory listings
* Shows index.html files at directory roots when they exist
* Use it with a raw http server, express/connect, or flatiron/union!

@@ -16,6 +16,7 @@ # Examples:

var express = require('express');
var ecstatic = require('../')(__dirname + '/public');
var ecstatic = require('../');;
var app = express.createServer();
app.use(ecstatic);
app.use(ecstatic(__dirname + '/public'));
app.use(ecstatic.showdir(__dirname + '/public'));
app.listen(8080);

@@ -30,7 +31,8 @@

var union = require('union');
var ecstatic = require('../')(__dirname + '/public');
var ecstatic = require('../');
union.createServer({
before: [
ecstatic
ecstatic(__dirname + '/public'),
ecstatic.showdir(__dirname + '/public')
]

@@ -48,6 +50,10 @@ }).listen(8080);

## middleware(req, res, next);
### middleware(req, res, next);
This works more or less as you'd expect.
## ecstatic.showdir(folder);
This returns another middleware which will attempt to show a directory view. At the moment, you must add this explicitly for union and connect middleware stacks, so that one may chose actions other than showing a directory view if desired.
# Tests:

@@ -59,8 +65,6 @@

This project's implementation is pretty much g2g (thanks @substack) but currently does not work in Union. This is because Union's response piping is currently broken.
This is still "beta" quality, and you may find bugs. Please give me a heads-up if you find any! Pull requests encouraged.
Once Union is fixed, this will work there as well.
# License:
MIT/X11.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc