Comparing version 0.8.0 to 1.0.0
@@ -0,1 +1,9 @@ | ||
2015/09/14 Version 1.0.0 | ||
- Optional support for weak Etags and weak Etag *comparison*, useful for cases | ||
where one is running ecstatic with gzip behind an nginx proxy (these will | ||
likely be turned ON by default in a following major version) | ||
- As a bin, respects process.env.PORT when binding to a port | ||
- Directory listings encode pathnames, etc | ||
- Default status pages return html instead of text/plain | ||
2015/05/22 Version 0.8.0 | ||
@@ -2,0 +10,0 @@ - Add ability to define custom mime-types, inline or with Apache .types file |
@@ -5,6 +5,14 @@ # Contributing Guidelines | ||
This is a pretty small project and it hasn't been a problem yet. However, to | ||
be clear: Everyone needs to be nice to each other. Sexist/racist/etc behavior | ||
won't be tolerated. | ||
This is probably way overkill, but this is by far my most active project in | ||
terms of contributions, and somewhere along the way I was convinced that it | ||
was a good idea to have this in place sooner rather than later: | ||
I want to provide a safe, healthy environment for all contributors/participants | ||
regardless of gender, sexual orientation, disability, race, religion, etc. | ||
As such, I don't tolerate harassment of participants in any form. In particular | ||
this applies to my issues tracker, but also to any other means of communication | ||
associated with this project that might come up. Anyone who violates these | ||
basic rules may be sanctioned/banned/have-their-comments-deleted/etc by my | ||
discretion. | ||
Glad we cleared that up. | ||
@@ -59,2 +67,4 @@ | ||
[![dependencies status](https://david-dm.org/jfhbrook/node-ecstatic.svg)](https://david-dm.org/jfhbrook/node-ecstatic) | ||
4. Please add yourself to CONTRIBUTORS.md if you haven't done so! Fill in as | ||
much as makes you comfortable. | ||
@@ -61,0 +71,0 @@ ## Pull Request |
@@ -29,3 +29,4 @@ #! /usr/bin/env node | ||
handleError = opts.handleError, | ||
serverHeader = opts.serverHeader; | ||
serverHeader = opts.serverHeader, | ||
weakEtags = opts.weakEtags; | ||
@@ -216,3 +217,3 @@ opts.root = dir; | ||
// TODO: Helper for this, with default headers. | ||
res.setHeader('etag', etag(stat)); | ||
res.setHeader('etag', etag(stat, weakEtags)); | ||
res.setHeader('last-modified', (new Date(stat.mtime)).toUTCString()); | ||
@@ -222,8 +223,3 @@ res.setHeader('cache-control', cache); | ||
// Return a 304 if necessary | ||
if ( req.headers | ||
&& ( | ||
(req.headers['if-none-match'] === etag(stat)) | ||
|| (new Date(Date.parse(req.headers['if-modified-since'])) >= stat.mtime) | ||
) | ||
) { | ||
if (shouldReturn304(req, stat)) { | ||
return status[304](res, next); | ||
@@ -251,2 +247,35 @@ } | ||
} | ||
// Do a strong or weak etag comparison based on setting | ||
// https://www.ietf.org/rfc/rfc2616.txt Section 13.3.3 | ||
function shouldReturn304(req, stat) { | ||
if (!req || !req.headers) { | ||
return false; | ||
} | ||
var modifiedSince = req.headers['if-modified-since'], | ||
clientEtag = req.headers['if-none-match'], | ||
serverEtag = etag(stat, opts.weakEtags); | ||
if (!modifiedSince && !clientEtag) { | ||
// Client did not provide any conditional caching headers | ||
return false; | ||
} | ||
// If any of the headers provided don't match, then don't return 304 | ||
if (modifiedSince && (new Date(Date.parse(modifiedSince))) < stat.mtime) { | ||
return false; | ||
} | ||
if (clientEtag) { | ||
if (opts.weakCompare && clientEtag !== serverEtag | ||
&& clientEtag !== ('W/' + serverEtag) && ('W/' + clientEtag) !== serverEtag) { | ||
return false; | ||
} else if (!opts.weakCompare && (clientEtag !== serverEtag || clientEtag.indexOf('W/') === 0)) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
}; | ||
@@ -289,3 +318,4 @@ }; | ||
opts = require('minimist')(process.argv.slice(2)), | ||
port = opts.port || opts.p || 8000, | ||
envPORT = parseInt(process.env.PORT, 10), | ||
port = envPORT > 1024 && envPORT <= 65536 ? envPORT : opts.port || opts.p || 8000, | ||
dir = opts.root || opts._[0] || process.cwd(); | ||
@@ -292,0 +322,0 @@ |
@@ -1,3 +0,7 @@ | ||
module.exports = function (stat) { | ||
return JSON.stringify([stat.ino, stat.size, stat.mtime].join('-')); | ||
module.exports = function (stat, weakEtag) { | ||
var etag = JSON.stringify([stat.ino, stat.size, stat.mtime].join('-')); | ||
if (weakEtag) { | ||
etag = 'W/' + etag; | ||
} | ||
return etag; | ||
} |
@@ -15,3 +15,5 @@ // This is so you can have options aliasing and defaults in one place. | ||
contentType = 'application/octet-stream', | ||
mimeTypes; | ||
mimeTypes, | ||
weakEtags = false, | ||
weakCompare = false; | ||
@@ -129,2 +131,24 @@ function isDeclared(k) { | ||
[ | ||
'weakEtags', | ||
'weaketags', | ||
'weak-etags' | ||
].some(function (k) { | ||
if (isDeclared(k)) { | ||
weakEtags = opts[k]; | ||
return true; | ||
} | ||
}); | ||
[ | ||
'weakcompare', | ||
'weakCompare', | ||
'weak-compare', | ||
'weak-Compare', | ||
].some(function (k) { | ||
if (isDeclared(k)) { | ||
weakCompare = opts[k]; | ||
return true; | ||
} | ||
}); | ||
} | ||
@@ -144,4 +168,6 @@ | ||
contentType: contentType, | ||
mimeTypes: mimeTypes | ||
mimeTypes: mimeTypes, | ||
weakEtags: weakEtags, | ||
weakCompare: weakCompare | ||
}; | ||
}; |
@@ -16,3 +16,4 @@ var ecstatic = require('../ecstatic'), | ||
handleError = opts.handleError, | ||
si = opts.si; | ||
si = opts.si, | ||
weakEtags = opts.weakEtags; | ||
@@ -44,3 +45,3 @@ return function middleware (req, res, next) { | ||
res.setHeader('content-type', 'text/html'); | ||
res.setHeader('etag', etag(stat)); | ||
res.setHeader('etag', etag(stat, weakEtags)); | ||
res.setHeader('last-modified', (new Date(stat.mtime)).toUTCString()); | ||
@@ -113,6 +114,6 @@ res.setHeader('cache-control', cache); | ||
' <meta name="viewport" content="width=device-width">', | ||
' <title>Index of ' + pathname +'</title>', | ||
' <title>Index of ' + he.encode(pathname) +'</title>', | ||
' </head>', | ||
' <body>', | ||
'<h1>Index of ' + pathname + '</h1>' | ||
'<h1>Index of ' + he.encode(pathname) + '</h1>' | ||
].join('\n') + '\n'; | ||
@@ -130,3 +131,3 @@ | ||
if (isDir) { | ||
href += '/' + ((parsed.search)? parsed.search:''); | ||
href += '/' + he.encode((parsed.search)? parsed.search:''); | ||
} | ||
@@ -133,0 +134,0 @@ |
@@ -0,1 +1,3 @@ | ||
var he = require('he'); | ||
// not modified | ||
@@ -63,4 +65,19 @@ exports['304'] = function (res, next) { | ||
res.statusCode = 500; | ||
res.setHeader('content-type', 'text/plain'); | ||
res.end(opts.error.stack || opts.error.toString() || "No specified error"); | ||
res.setHeader('content-type', 'text/html'); | ||
var error = String(opts.error.stack || opts.error || "No specified error"), | ||
html = [ | ||
'<!doctype html>', | ||
'<html>', | ||
' <head>', | ||
' <meta charset="utf-8">', | ||
' <title>500 Internal Server Error</title>', | ||
' </head>', | ||
' <body>', | ||
' <p>', | ||
' ' + he.encode(error), | ||
' </p>', | ||
' </body>', | ||
'</html>' | ||
].join('\n') + '\n'; | ||
res.end(html); | ||
}; | ||
@@ -71,4 +88,19 @@ | ||
res.statusCode = 400; | ||
res.setHeader('content-type', 'text/plain'); | ||
res.end(opts && opts.error ? String(opts.error) : 'Malformed request.'); | ||
res.setHeader('content-type', 'text/html'); | ||
var error = opts && opts.error ? String(opts.error) : 'Malformed request.', | ||
html = [ | ||
'<!doctype html>', | ||
'<html>', | ||
' <head>', | ||
' <meta charset="utf-8">', | ||
' <title>400 Bad Request</title>', | ||
' </head>', | ||
' <body>', | ||
' <p>', | ||
' ' + he.encode(error), | ||
' </p>', | ||
' </body>', | ||
'</html>' | ||
].join('\n') + '\n'; | ||
res.end(html); | ||
}; |
The MIT License (MIT) | ||
Copyright (c) 2013 Joshua Holbrook | ||
Copyright (c) 2013-2015 Joshua Holbrook and contributors | ||
@@ -5,0 +5,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy |
@@ -5,3 +5,3 @@ { | ||
"description": "A simple static file server middleware that works with both Express and Flatiron", | ||
"version": "0.8.0", | ||
"version": "1.0.0", | ||
"homepage": "https://github.com/jfhbrook/node-ecstatic", | ||
@@ -8,0 +8,0 @@ "repository": { |
@@ -155,2 +155,11 @@ # Ecstatic [![build status](https://secure.travis-ci.org/jfhbrook/node-ecstatic.png)](http://travis-ci.org/jfhbrook/node-ecstatic) | ||
### `opts.weakEtags` | ||
Set `opts.weakEtags` to true in order to generate weak etags instead of strong etags. Defaults to **false**. See `opts.weakCompare` as well. | ||
### `opts.weakCompare` | ||
Turn **on** weakCompare to allow the weak comparison function for etag validation. Defaults to **false**. | ||
See https://www.ietf.org/rfc/rfc2616.txt Section 13.3.3 for more details. | ||
## middleware(req, res, next); | ||
@@ -170,3 +179,3 @@ | ||
`port` defaults to `8000`. If a `dir` or `--root dir` argument is not passed, ecsatic will | ||
serve the current dir. | ||
serve the current dir. Ecstatic also respects the PORT environment variable. | ||
@@ -189,2 +198,2 @@ # Tests: | ||
MIT. | ||
MIT. See LICENSE.txt. For contributors, see CONTRIBUTORS.md |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
234845
21
749
0
197
3