servie-send
Advanced tools
Comparing version
@@ -40,4 +40,4 @@ /// <reference types="node" /> | ||
/** | ||
* Create an ETag of the payload body. | ||
* Create an entity tag for cache identification. | ||
*/ | ||
export declare function entityTag(body: string | Buffer): string; |
@@ -8,3 +8,3 @@ "use strict"; | ||
const TOKEN_LIST_REGEXP = / *, */; | ||
const ZERO_LENGTH_ENTITY_TAG = createEntityTag(''); | ||
const ZERO_LENGTH_ENTITY_TAG = entityTag(''); | ||
/** | ||
@@ -54,6 +54,8 @@ * Create an empty response. | ||
function send(req, payload, options = {}) { | ||
const headers = servie_1.createHeaders(options.headers); | ||
let statusCode = options.statusCode || 200; | ||
let body = req.method === 'HEAD' ? undefined : node_1.createBody(payload); | ||
if (fresh(req, options.etag, options.mtime)) { | ||
const headers = servie_1.createHeaders(options.headers); | ||
const { mtime, contentType, contentLength, skipEtag } = options; | ||
const etag = options.etag || (skipEtag ? undefined : toEntityTag(payload)); | ||
if (fresh(req, etag, mtime)) { | ||
statusCode = 304; | ||
@@ -63,17 +65,11 @@ body = undefined; | ||
else { | ||
if (options.contentType) | ||
headers.set('Content-Type', options.contentType); | ||
if (options.contentLength) | ||
headers.set('Content-Length', String(options.contentLength)); | ||
if (contentType) | ||
headers.set('Content-Type', contentType); | ||
if (contentLength) | ||
headers.set('Content-Length', String(contentLength)); | ||
} | ||
if (options.mtime) | ||
headers.set('Last-Modified', options.mtime.toUTCString()); | ||
if (options.etag) { | ||
headers.set('ETag', options.etag); | ||
} | ||
else if (!options.skipEtag) { | ||
if (typeof payload === 'string' || Buffer.isBuffer(payload)) { | ||
headers.set('ETag', entityTag(payload)); | ||
} | ||
} | ||
if (etag) | ||
headers.set('ETag', etag); | ||
if (mtime) | ||
headers.set('Last-Modified', mtime.toUTCString()); | ||
return new servie_1.Response({ statusCode, headers, body }); | ||
@@ -83,15 +79,17 @@ } | ||
/** | ||
* Create an ETag of the payload body. | ||
* Create an ETag from the payload body. | ||
*/ | ||
function entityTag(body) { | ||
return body.length === 0 ? ZERO_LENGTH_ENTITY_TAG : createEntityTag(body); | ||
function toEntityTag(body) { | ||
if (typeof body === 'string' || Buffer.isBuffer(body)) { | ||
return body.length === 0 ? ZERO_LENGTH_ENTITY_TAG : entityTag(body); | ||
} | ||
} | ||
exports.entityTag = entityTag; | ||
/** | ||
* Create an entity tag for cache identification. | ||
*/ | ||
function createEntityTag(body) { | ||
function entityTag(body) { | ||
const hash = crypto_1.createHash('sha256').update(body).digest('base64'); | ||
return `"${hash}"`; | ||
} | ||
exports.entityTag = entityTag; | ||
/** | ||
@@ -102,6 +100,6 @@ * Check if a request is fresh. | ||
*/ | ||
function fresh(req, etag, lastModified) { | ||
const noneMatch = req.headers.get('if-none-match'); | ||
const modifiedSince = req.headers.get('if-modified-since'); | ||
if (!noneMatch && !modifiedSince) | ||
function fresh(req, etag, mtime) { | ||
const ifNoneMatch = req.headers.get('if-none-match'); | ||
const ifModifiedSince = req.headers.get('if-modified-since'); | ||
if (!ifNoneMatch && !ifModifiedSince) | ||
return false; | ||
@@ -112,4 +110,4 @@ const cacheControl = req.headers.get('cache-control'); | ||
} | ||
if (noneMatch && etag) { | ||
const isStale = noneMatch.split(TOKEN_LIST_REGEXP).every(match => { | ||
if (ifNoneMatch && etag) { | ||
const isStale = ifNoneMatch.split(TOKEN_LIST_REGEXP).every(match => { | ||
return match !== etag; | ||
@@ -120,4 +118,4 @@ }); | ||
} | ||
if (modifiedSince && lastModified) { | ||
const isStale = lastModified.getTime() > Date.parse(modifiedSince); | ||
if (ifModifiedSince && mtime) { | ||
const isStale = mtime.getTime() > Date.parse(ifModifiedSince); | ||
if (isStale) | ||
@@ -124,0 +122,0 @@ return false; |
@@ -64,3 +64,16 @@ "use strict"; | ||
})); | ||
it('should send 200 with changed etag', () => __awaiter(this, void 0, void 0, function* () { | ||
const req = new servie_1.Request({ | ||
url: '/', | ||
headers: servie_1.createHeaders({ | ||
'If-None-Match': index_1.entityTag('content') | ||
}), | ||
body: node_1.createBody('') | ||
}); | ||
const res = index_1.sendText(req, ''); | ||
expect(res.statusCode).toEqual(200); | ||
expect(res.allHeaders).toMatchSnapshot(); | ||
expect(yield res.body.text()).toEqual(''); | ||
})); | ||
}); | ||
//# sourceMappingURL=index.spec.js.map |
{ | ||
"name": "servie-send", | ||
"version": "1.1.0", | ||
"version": "1.1.1", | ||
"description": "Generate a HTTP response with client-side cache support", | ||
@@ -40,12 +40,12 @@ "main": "dist/index.js", | ||
"devDependencies": { | ||
"@types/jest": "^22.2.2", | ||
"@types/node": "^9.6.5", | ||
"jest": "^22.4.3", | ||
"@types/jest": "^23.3.2", | ||
"@types/node": "^10.9.4", | ||
"jest": "^23.6.0", | ||
"rimraf": "^2.5.4", | ||
"servie": "^3.0.0", | ||
"throwback": "^2.0.0", | ||
"ts-jest": "^22.4.2", | ||
"throwback": "^3.0.0", | ||
"ts-jest": "^23.1.4", | ||
"tslint": "^5.9.1", | ||
"tslint-config-standard": "^7.0.0", | ||
"typescript": "^2.8.1" | ||
"tslint-config-standard": "^8.0.1", | ||
"typescript": "^3.0.3" | ||
}, | ||
@@ -52,0 +52,0 @@ "peerDependencies": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
25740
5.86%238
4.85%