UNPKG

stick

Version:

JSGI based webapp framework

85 lines (80 loc) 2.4 kB
/** * @fileOverview Middleware for conditional HTTP GET request based on * response body message digests. * * The response body must implement a digest() method for this middleware to work. */ var COMMON_NODE = global.process; var md5 = require('common-utils/md5').md5; var Headers = require('../utils/http').Headers; var ByteString = require('binary').ByteString; var digest = function() { if (COMMON_NODE) { var crypto = require('crypto'); return function(body) { var r = crypto.createHash('md5'); body.forEach(function(part) { r.update(part.buffer); }); return r.digest('hex'); }; } else { return function(body) { var b = []; body.forEach(function(part) { b.push(part.toArray()); }); return md5(Array.prototype.concat.apply([], b)).toLowerCase(); }; } }(); /** * Middleware for conditional HTTP GET request based on * response body message digests. * @param {Function} next the wrapped middleware chain * @param {Object} app the Stick Application object * @returns {Function} a JSGI middleware function */ exports.middleware = function etag(next, app) { return function etag(request) { var res = next(request); var body = res.body; if (res.status === 200) { var code; // if body provides a digest() method use that if (typeof body.digest === "function") { code = body.digest(); } else { // we can't rely on body having map(), so we fake it with forEach() var binBody = []; var length = 0; body.forEach(function(part) { part = part.toByteString(); binBody.push(part); length += part.length; }); if (length) { code = digest(binBody); binBody.digest = function() { return code; }; } } if (code) { var etag = '"' + code + '"'; var headers = Headers(res.headers); headers.set('ETag', etag); if (~(request.headers["if-none-match"] || []).indexOf(etag)) { // return not-modified response headers.unset('Content-Length'); return {status:304, headers:headers, body:[]}; } } if (binBody) { // body has been converted to ByteStrings as a byproduct of digest() res.body = binBody; } } return res; }; };