serve-handler
Advanced tools
Comparing version 6.0.3 to 6.1.0
{ | ||
"name": "serve-handler", | ||
"version": "6.0.3", | ||
"version": "6.1.0", | ||
"description": "The routing foundation of `serve` and static deployments on Now", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
@@ -50,14 +50,15 @@ # serve-handler | ||
| Property | Description | | ||
|------------------------------------------------------|-----------------------------------------------------------| | ||
| [`public`](#public-string) | Set a sub directory to be served | | ||
| [`cleanUrls`](#cleanurls-booleanarray) | Have the `.html` extension stripped from paths | | ||
| [`rewrites`](#rewrites-array) | Rewrite paths to different paths | | ||
| [`redirects`](#redirects-array) | Forward paths to different paths or external URLs | | ||
| [`headers`](#headers-array) | Set custom headers for specific paths | | ||
| [`directoryListing`](#directorylisting-booleanarray) | Disable directory listing or restrict it to certain paths | | ||
| [`unlisted`](#unlisted-array) | Exclude paths from the directory listing | | ||
| [`trailingSlash`](#trailingslash-boolean) | Remove or add trailing slashes to all paths | | ||
| [`renderSingle`](#rendersingle-boolean) | If a directory only contains one file, render it | | ||
| [`symlinks`](#symlinks-boolean) | Resolve symlinks instead of rendering a 404 error | | ||
| Property | Description | | ||
|------------------------------------------------------|-----------------------------------------------------------------------| | ||
| [`public`](#public-string) | Set a sub directory to be served | | ||
| [`cleanUrls`](#cleanurls-booleanarray) | Have the `.html` extension stripped from paths | | ||
| [`rewrites`](#rewrites-array) | Rewrite paths to different paths | | ||
| [`redirects`](#redirects-array) | Forward paths to different paths or external URLs | | ||
| [`headers`](#headers-array) | Set custom headers for specific paths | | ||
| [`directoryListing`](#directorylisting-booleanarray) | Disable directory listing or restrict it to certain paths | | ||
| [`unlisted`](#unlisted-array) | Exclude paths from the directory listing | | ||
| [`trailingSlash`](#trailingslash-boolean) | Remove or add trailing slashes to all paths | | ||
| [`renderSingle`](#rendersingle-boolean) | If a directory only contains one file, render it | | ||
| [`symlinks`](#symlinks-boolean) | Resolve symlinks instead of rendering a 404 error | | ||
| [`etag`](#etag-boolean) | Calculate a strong `ETag` response header, instead of `Last-Modified` | | ||
@@ -278,2 +279,14 @@ ### public (String) | ||
### etag (Boolean) | ||
HTTP response headers will contain a strong [`ETag`][etag] response header, instead of a [`Last-Modified`][last-modified] header. Opt-in because calculating the hash value may be computationally expensive for large files. | ||
Sending an `ETag` header is disabled by default and can be enabled like this: | ||
```js | ||
{ | ||
"etag": true | ||
} | ||
``` | ||
## Error templates | ||
@@ -322,1 +335,5 @@ | ||
Leo Lamprecht ([@notquiteleo](https://twitter.com/notquiteleo)) - [ZEIT](https://zeit.co) | ||
[etag]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag | ||
[last-modified]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified |
// Native | ||
const {promisify} = require('util'); | ||
const path = require('path'); | ||
const {createHash} = require('crypto'); | ||
const {realpath, lstat, createReadStream, readdir} = require('fs'); | ||
@@ -21,2 +22,16 @@ | ||
const etags = new Map(); | ||
const calculateSha = (handlers, absolutePath) => | ||
new Promise((resolve, reject) => { | ||
const hash = createHash('sha1'); | ||
const rs = handlers.createReadStream(absolutePath); | ||
rs.on('error', reject); | ||
rs.on('data', buf => hash.update(buf)); | ||
rs.on('end', () => { | ||
const sha = hash.digest('hex'); | ||
resolve(sha); | ||
}); | ||
}); | ||
const sourceMatches = (source, requestPath, allowSegments) => { | ||
@@ -181,3 +196,4 @@ const keys = []; | ||
const getHeaders = async (customHeaders = [], current, absolutePath, stats) => { | ||
const getHeaders = async (handlers, config, current, absolutePath, stats) => { | ||
const {headers: customHeaders = [], etag = false} = config; | ||
const related = {}; | ||
@@ -204,3 +220,2 @@ const {base} = path.parse(absolutePath); | ||
defaultHeaders = { | ||
'Last-Modified': stats.mtime.toUTCString(), | ||
'Content-Length': stats.size, | ||
@@ -216,2 +231,13 @@ // Default to "inline", which always tries to render in the browser, | ||
if (etag) { | ||
let [mtime, sha] = etags.get(absolutePath) || []; | ||
if (Number(mtime) !== Number(stats.mtime)) { | ||
sha = await calculateSha(handlers, absolutePath); | ||
etags.set(absolutePath, [stats.mtime, sha]); | ||
} | ||
defaultHeaders['ETag'] = `"${sha}"`; | ||
} else { | ||
defaultHeaders['Last-Modified'] = stats.mtime.toUTCString(); | ||
} | ||
const contentType = mime.contentType(base); | ||
@@ -486,3 +512,3 @@ | ||
const headers = await getHeaders(config.headers, current, errorPage, stats); | ||
const headers = await getHeaders(handlers, config, current, errorPage, stats); | ||
@@ -498,3 +524,3 @@ response.writeHead(statusCode, headers); | ||
const headers = await getHeaders(config.headers, current, absolutePath, null); | ||
const headers = await getHeaders(handlers, config, current, absolutePath, null); | ||
headers['Content-Type'] = 'text/html; charset=utf-8'; | ||
@@ -713,3 +739,3 @@ | ||
const headers = await getHeaders(config.headers, current, absolutePath, stats); | ||
const headers = await getHeaders(handlers, config, current, absolutePath, stats); | ||
@@ -716,0 +742,0 @@ // eslint-disable-next-line no-undefined |
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
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
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
43255
651
337
1