UNPKG

@zkochan/pnpm

Version:

A fast implementation of npm install

155 lines (133 loc) 4.32 kB
/** * Copyright 2015 Google Inc. All Rights Reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file or at * https://github.com/firebase/superstatic/blob/master/LICENSE */ 'use strict'; var RSVP = require('rsvp'); var _ = require('lodash'); var mime = require('mime-types'); var path = require('path'); var awaitFinished = RSVP.denodeify(require('on-finished')); var destroy = require('destroy'); var compress = require('compression')(); var Responder = function(req, res, options) { this.req = req; this.res = res; this.provider = options.provider; this.config = options.config || {}; this.gzip = options.gzip; }; Responder.prototype.isNotModified = function(stats) { if (stats.etag && stats.etag === this.req.headers['if-none-match']) { return true; } var reqModified = this.req.headers['if-modified-since']; if (reqModified) { reqModified = new Date(reqModified).getTime(); } if (stats.modified && reqModified && stats.modified < reqModified) { return true; } return false; }; Responder.prototype.handle = function(item, next) { var self = this; return this._handle(item).then(function(responded) { if (!responded && next) { next(); } return responded; }).catch(function(err) { return self.handleError(err); }); }; Responder.prototype._handle = function(item) { if (_.isArray(item)) { return this.handleStack(item); } else if (_.isString(item)) { return this.handleFile({file: item}); } else if (_.isObject(item)) { if (item.file) { return this.handleFile(item); } else if (item.redirect) { return this.handleRedirect(item); } else if (item.data) { return this.handleData(item); } } return RSVP.reject(new Error(JSON.stringify(item) + ' is not a recognized responder directive')); }; Responder.prototype.handleError = function(err) { this.res.statusCode = 500; console.log(err.stack); this.res.end('Unexpected error occurred.'); }; Responder.prototype.handleStack = function(stack) { var self = this; if (stack.length) { return this._handle(stack.shift()).then(function(responded) { return responded ? true : self.handleStack(stack); }); } return RSVP.resolve(false); }; Responder.prototype.handleFile = function(file) { var self = this; return this.provider(this.req, file.file).then(function(result) { if (!result) { return false; } if (self.isNotModified(result)) { return self.handleNotModified(result); } return self.handleFileStream(file, result); }); }; Responder.prototype.handleFileStream = function(file, result) { var self = this; this.streamedFile = file; this.res.statusCode = file.status || 200; if (this.res.statusCode === 200 && file.file === this.config.errorPage) { this.res.statusCode = 404; } this.res.setHeader('Content-Type', result.contentType || mime.contentType(path.extname(file.file))); if (result.size) { this.res.setHeader('Content-Length', result.size); } if (result.etag) { this.res.setHeader('ETag', result.etag); } if (result.modified) { this.res.setHeader('Last-Modified', new Date(result.modified).toUTCString()); } if (this.gzip) { compress(this.req, this.res, function() { result.stream.pipe(self.res); }); } else { result.stream.pipe(self.res); } return awaitFinished(this.res).then(function() { destroy(result.stream); return true; }); }; Responder.prototype.handleNotModified = function() { this.res.statusCode = 304; this.res.removeHeader('Content-Type'); this.res.removeHeader('Content-Length'); this.res.removeHeader('Transfer-Encoding'); this.res.end(); }; Responder.prototype.handleRedirect = function(redirect) { this.res.statusCode = redirect.status || 301; this.res.setHeader('Location', redirect.redirect); this.res.setHeader('Content-Type', 'text/html; charset=utf-8'); this.res.end('Redirecting to ' + redirect.redirect); return RSVP.resolve(true); }; Responder.prototype.handleData = function(data) { this.res.statusCode = data.status || 200; this.res.setHeader('Content-Type', data.contentType || 'text/html; charset=utf-8'); this.res.end(data.data); return RSVP.resolve(true); }; module.exports = Responder;