Exemple #1
0
export function sendHTML (req, res, html, method, { dev, generateEtags }) {
  if (isResSent(res)) return
  const etag = generateEtags && generateETag(html)

  if (fresh(req.headers, { etag })) {
    res.statusCode = 304
    res.end()
    return
  }

  if (dev) {
    // In dev, we should not cache pages for any reason.
    // That's why we do this.
    res.setHeader('Cache-Control', 'no-store, must-revalidate')
  }

  if (etag) {
    res.setHeader('ETag', etag)
  }

  if (!res.getHeader('Content-Type')) {
    res.setHeader('Content-Type', 'text/html; charset=utf-8')
  }
  res.setHeader('Content-Length', Buffer.byteLength(html))
  res.end(method === 'HEAD' ? null : html)
}
/**
 * Middleware that is returned with public expiry call.
 * Looks up incoming request url in lookup hash and, if found, 
 * sets cache headers according to settings
 *
 * @api private
 */
function middleware(req, res, next) {
  var headerInfo = expiry.assetCache[req.url]
    , options = expiry.options;

  if (headerInfo) {
    var cacheControl = (options.cacheControl === 'cookieless' && 
      (req.get('cookie') || req.get('authorization'))) ?
          'private' : options.cacheControl || '';

    if (options.unconditional === 'both' || options.unconditional === 'max-age') {
      if (cacheControl.length) cacheControl += ', ';
      cacheControl += 'max-age=' + options.duration;
    }
    if (options.unconditional === 'both' || options.unconditional === 'expires') {
      var now = new Date();
      now.setSeconds(now.getSeconds() + options.duration);
      res.set({ 'Expires' : now.toUTCString() });
    }
    if (options.conditional === 'both' || options.conditional === 'etag') {
      res.set({ 'ETag' : '"' + headerInfo.etag + '"' });
    }
    if (options.conditional === 'both' || options.conditional === 'last-modified') {
      res.set({ 'Last-Modified' : headerInfo.lastModified });
    }
    if (cacheControl.length) res.set({ 'Cache-Control' : cacheControl });

    if (fresh(req, res)) return res.send(304);

    req.originalUrl = req.url;
    req.url = headerInfo.assetUrl;
  }

  next();
};
Exemple #3
0
function send(req, res, icon){
  var _fresh = fresh(req.headers, icon.headers);
  var buf = _fresh ? '' : icon.body;
  var status = _fresh ? 304 : 200;

  res.writeHead(status, icon.headers);
  res.end(buf);
}
Exemple #4
0
function respondFromCache(req, res, cacheEntry) {
  _$jscoverage['middleware/staticCache.js'][152]++;
  var status = cacheEntry[0], headers = utils.merge({}, cacheEntry[1]), content = cacheEntry.slice(2);
  _$jscoverage['middleware/staticCache.js'][156]++;
  headers.age = (new Date() - new Date(headers.date)) / 1000 || 0;
  _$jscoverage['middleware/staticCache.js'][158]++;
  switch (req.method) {
  case "HEAD":
    _$jscoverage['middleware/staticCache.js'][160]++;
    res.writeHead(status, headers);
    _$jscoverage['middleware/staticCache.js'][161]++;
    res.end();
    _$jscoverage['middleware/staticCache.js'][162]++;
    break;
  case "GET":
    _$jscoverage['middleware/staticCache.js'][164]++;
    if (utils.conditionalGET(req) && fresh(req.headers, headers)) {
      _$jscoverage['middleware/staticCache.js'][165]++;
      headers["content-length"] = 0;
      _$jscoverage['middleware/staticCache.js'][166]++;
      res.writeHead(304, headers);
      _$jscoverage['middleware/staticCache.js'][167]++;
      res.end();
    }
    else {
      _$jscoverage['middleware/staticCache.js'][169]++;
      res.writeHead(status, headers);
      _$jscoverage['middleware/staticCache.js'][171]++;
      function write() {
        _$jscoverage['middleware/staticCache.js'][172]++;
        while (content.length) {
          _$jscoverage['middleware/staticCache.js'][173]++;
          if (false === res.write(content.shift())) {
            _$jscoverage['middleware/staticCache.js'][174]++;
            res.once("drain", write);
            _$jscoverage['middleware/staticCache.js'][175]++;
            return;
          }
}
        _$jscoverage['middleware/staticCache.js'][178]++;
        res.end();
}
      _$jscoverage['middleware/staticCache.js'][181]++;
      write();
    }
    _$jscoverage['middleware/staticCache.js'][183]++;
    break;
  default:
    _$jscoverage['middleware/staticCache.js'][186]++;
    res.writeHead(500, "");
    _$jscoverage['middleware/staticCache.js'][187]++;
    res.end();
  }
}
defineGetter(req, 'fresh', function(){
  var method = this.method;
  var statusCode = this.res.statusCode;

  if (method !== 'GET' && method !== 'HEAD') {
    return false;
  }

  if ((statusCode >= 200 && statusCode < 300) || statusCode === 304) {
    return fresh(this.headers, (this.res._headers || {}));
  }

  return false;
});
Exemple #6
0
var isFresh = function(req, etag){
  if( req.headers['if-none-match'] || req.headers['if-modified-since'] ) {
    return fresh({
      'if-modified-since': req.headers['if-modified-since'],
      'if-none-match': req.headers['if-none-match'],
      'last-modified': req.headers['last-modified'],
      'cache-control': req.headers['cache-control']
    }, {
      'etag': etag
    });
  }
  
  return false;
};
Exemple #7
0
defineGetter(req, 'fresh', function(){
  var method = this.method;
  var s = this.res.statusCode;

  // GET or HEAD for weak freshness validation only
  if ('GET' != method && 'HEAD' != method) return false;

  // 2xx or 304 as per rfc2616 14.26
  if ((s >= 200 && s < 300) || 304 == s) {
    return fresh(this.headers, (this.res._headers || {}));
  }

  return false;
});
Exemple #8
0
/**
 * Set etag and last-modified from mongo id
 *
 * @param {Number} id
 * @param {Object} req
 * @param {Object} res
 * @return {Boolean}
 */
function setCacheFromIdAndVerifyFreshness(id, req, res) {
	var id = mongoose.Types.ObjectId(id);
	var headers = {
		'etag': id.toString(),
		'last-modified': id.getTimestamp().toUTCString()
	}
	for (var key in headers) {
		res.setHeader(key, headers[key]);
	}
	// Cache is stale
	if (!fresh(req.headers, headers)) {
		return false;
	}
	// Freshness!
	connect.utils.notModified(res);
	return true;
}
Exemple #9
0
defineGetter(req, 'fresh', function(){
  var method = this.method;
  var res = this.res
  var status = res.statusCode

  // GET or HEAD for weak freshness validation only
  if ('GET' !== method && 'HEAD' !== method) return false;

  // 2xx or 304 as per rfc2616 14.26
  if ((status >= 200 && status < 300) || 304 === status) {
    return fresh(this.headers, {
      'etag': res.get('ETag'),
      'last-modified': res.get('Last-Modified')
    })
  }

  return false;
});
    getFromCache(headersCacheKey).then(function(headersData) {

      log('retrieved %s from cache', headersCacheKey);

      _.assign(req.cache, headersData);

      var cachedEtag = _.get(headersData, 'headers.etag');
      var isFresh = fresh(req.headers, {
        'etag': cachedEtag
      });

      // TODO abstract `isFresh` as one of many validators
      // before returning `304` directly
      if (isFresh) {
        res.sendStatus(304);
        return reqComplete;
      }

      return headersData;

    }).then(function(headersData) {
Exemple #11
0
function send(req, res, icon) {
  var headers = icon.headers;

  // Set headers
  var keys = Object.keys(headers);
  for (var i = 0; i < keys.length; i++) {
    var key = keys[i];
    res.setHeader(key, headers[key]);
  }

  if (fresh(req.headers, res._headers)) {
    res.statusCode = 304;
    res.end();
    return;
  }

  res.statusCode = 200;
  res.setHeader('Content-Length', icon.body.length);
  res.setHeader('Content-Type', 'image/x-icon');
  res.end(icon.body);
}
Exemple #12
0
	validatePublicCache: function(request, response, stat, callback) {
		var self = this;
		var headers;

		if (connect_utils.conditionalGET(request)) {
			if (stat) {
				headers = { "etag": connect_utils.etag(stat), "last-modified": stat.mtime };
			} else {
				headers = { "etag": response.getHeader("etag"), "last-modified": response.getHeader("last-modified") };
			}

			// check if the cache is still fresh
			if (fresh(request.headers, headers)) {
				return connect_utils.notModified(response);
			}	else {
				return callback();
			}
		} else {
			return callback();
		}
	},
Exemple #13
0
function respondFromCache(req, res, cacheEntry) {
  var status = cacheEntry[0]
    , headers = utils.merge({}, cacheEntry[1])
    , content = cacheEntry.slice(2);

  headers.age = (new Date - new Date(headers.date)) / 1000 || 0;

  switch (req.method) {
    case 'HEAD':
      res.writeHead(status, headers);
      res.end();
      break;
    case 'GET':
      if (fresh(req.headers, headers)) {
        headers['content-length'] = 0;
        res.writeHead(304, headers);
        res.end();
      } else {
        res.writeHead(status, headers);

        function write() {
          while (content.length) {
            if (false === res.write(content.shift())) {
              res.once('drain', write);
              return;
            }
          }
          res.end();
        }

        write();
      }
      break;
    default:
      // This should never happen.
      res.writeHead(500, '');
      res.end();
  }
}
Exemple #14
0
module.exports = async function nuxtMiddleware(req, res, next) {
  // Get context
  const context = getContext(req, res)

  res.statusCode = 200
  try {
    const result = await this.renderRoute(req.url, context)
    await this.nuxt.callHook('render:route', req.url, result)
    const { html, error, redirected, getPreloadFiles } = result

    if (redirected) {
      return html
    }
    if (error) {
      res.statusCode = context.nuxt.error.statusCode || 500
    }

    // Add ETag header
    if (!error && this.options.render.etag) {
      const etag = generateETag(html, this.options.render.etag)
      if (fresh(req.headers, { etag })) {
        res.statusCode = 304
        res.end()
        return
      }
      res.setHeader('ETag', etag)
    }

    // HTTP2 push headers for preload assets
    if (!error && this.options.render.http2.push) {
      // Parse resourceHints to extract HTTP.2 prefetch/push headers
      // https://w3c.github.io/preload/#server-push-http-2
      const pushAssets = []
      const preloadFiles = getPreloadFiles()
      const { shouldPush } = this.options.render.http2
      const { publicPath } = this.resources.clientManifest

      preloadFiles.forEach(({ file, asType, fileWithoutQuery, extension }) => {
        // By default, we only preload scripts or css
        /* istanbul ignore if */
        if (!shouldPush && asType !== 'script' && asType !== 'style') {
          return
        }

        // User wants to explicitly control what to preload
        if (shouldPush && !shouldPush(fileWithoutQuery, asType)) {
          return
        }

        pushAssets.push(`<${publicPath}${file}>; rel=preload; as=${asType}`)
      })

      // Pass with single Link header
      // https://preloadFilesblog.cloudflare.com/http-2-server-push-with-multiple-assets-per-link-header
      // https://www.w3.org/Protocols/9707-link-header.html
      res.setHeader('Link', pushAssets.join(','))
    }

    // Send response
    res.setHeader('Content-Type', 'text/html; charset=utf-8')
    res.setHeader('Content-Length', Buffer.byteLength(html))
    res.end(html, 'utf8')
    return html
  } catch (err) {
    /* istanbul ignore if */
    if (context && context.redirected) {
      console.error(err) // eslint-disable-line no-console
      return err
    }

    next(err)
  }
}
exports = module.exports = function(body){
  var req = this.req
    , method = req.method
    , len;

  // allow status / body
  if (2 == arguments.length) {
    // res.send(body, status) backwards compat
    if ('number' != typeof body && 'number' == typeof arguments[1]) {
      this.statusCode = arguments[1];
    } else {
      this.statusCode = body;
      body = arguments[1];
    }
  }

  // null
  if (null == body) body = '';

  // convert primitives
  body = body.valueOf();

  switch (typeof body) {
    // response status
    case 'number':
      if (!this.getHeader('Content-Type')) this.setHeader('Content-Type', 'text/plain');
      this.statusCode = body;
      body = http.STATUS_CODES[body];
      break;
    // string defaulting to html
    case 'string':
      if (!this.getHeader('Content-Type')) {
        this.charset = this.charset || 'utf-8';
        this.setHeader('Content-Type', 'text/html');
      }
      break;
    case 'boolean':
    case 'object':
      if (null == body) {
        body = '';
      } else if (Buffer.isBuffer(body)) {
        if (!this.getHeader('Content-Type')) this.setHeader('Content-Type', 'application/octet-stream');
      } else {
        return this.json(body);
      }
      break;
  }

  // populate Content-Length
  if (undefined !== body && !this.getHeader('Content-Length')) {
    this.setHeader('Content-Length', len = Buffer.isBuffer(body)
      ? body.length
      : Buffer.byteLength(body));
  }

  // ETag support
  // TODO: W/ support
  if (len > 1024) {
    var etag = String(Buffer.isBuffer(body)
      ? crc.buffer.crc32(body)
      : crc.crc32(body));
    if (!this.getHeader('ETag')) this.setHeader('ETag', etag);
  }

  // determine if it's cacheable
  var cache = 'GET' == method || 'HEAD' == method;
  if (cache) cache = (this.statusCode >= 200 && this.statusCode < 300) || 304 == this.statusCode;

  // freshness
  if (fresh(req.headers, this._headers) && cache) {
    this.statusCode = 304;
  }

  // strip irrelevant headers
  if (204 == this.statusCode || 304 == this.statusCode) {
    this.removeHeader('Content-Type');
    this.removeHeader('Content-Length');
    body = '';
  }

  // respond
  this.end('HEAD' == method ? null : body);
  return this;
};
Exemple #16
0
   * still match.
   *
   * @return {Boolean}
   * @api public
   */

  get fresh() {
    var method = this.method;
    var s = this.ctx.status;

    // GET or HEAD for weak freshness validation only
    if ('GET' != method && 'HEAD' != method) return false;

    // 2xx or 304 as per rfc2616 14.26
    if ((s >= 200 && s < 300) || 304 == s) {
      return fresh(this.header, this.ctx.response.header);
    }

    return false;
  },

  /**
   * Check if the request is stale, aka
   * "Last-Modified" and / or the "ETag" for the
   * resource has changed.
   *
   * @return {Boolean}
   * @api public
   */

  get stale() {
"use strict";function defineGetter(e,r,t){Object.defineProperty(e,r,{configurable:!0,enumerable:!0,get:t})}var accepts=require("accepts"),deprecate=require("depd")("express"),isIP=require("net").isIP,typeis=require("type-is"),http=require("http"),fresh=require("fresh"),parseRange=require("range-parser"),parse=require("parseurl"),proxyaddr=require("proxy-addr"),req=exports=module.exports={__proto__:http.IncomingMessage.prototype};req.get=req.header=function(e){var r=e.toLowerCase();switch(r){case"referer":case"referrer":return this.headers.referrer||this.headers.referer;default:return this.headers[r]}},req.accepts=function(){var e=accepts(this);return e.types.apply(e,arguments)},req.acceptsEncodings=function(){var e=accepts(this);return e.encodings.apply(e,arguments)},req.acceptsEncoding=deprecate.function(req.acceptsEncodings,"req.acceptsEncoding: Use acceptsEncodings instead"),req.acceptsCharsets=function(){var e=accepts(this);return e.charsets.apply(e,arguments)},req.acceptsCharset=deprecate.function(req.acceptsCharsets,"req.acceptsCharset: Use acceptsCharsets instead"),req.acceptsLanguages=function(){var e=accepts(this);return e.languages.apply(e,arguments)},req.acceptsLanguage=deprecate.function(req.acceptsLanguages,"req.acceptsLanguage: Use acceptsLanguages instead"),req.range=function(e){var r=this.get("Range");if(r)return parseRange(e,r)},req.param=function(e,r){var t=this.params||{},s=this.body||{},n=this.query||{},a=1===arguments.length?"name":"name, default";return deprecate("req.param("+a+"): Use req.params, req.body, or req.query instead"),null!=t[e]&&t.hasOwnProperty(e)?t[e]:null!=s[e]?s[e]:null!=n[e]?n[e]:r},req.is=function(e){var r=e;if(!Array.isArray(e)){r=new Array(arguments.length);for(var t=0;t<r.length;t++)r[t]=arguments[t]}return typeis(this,r)},defineGetter(req,"protocol",function(){var e=this.connection.encrypted?"https":"http",r=this.app.get("trust proxy fn");return r(this.connection.remoteAddress,0)?(e=this.get("X-Forwarded-Proto")||e,e.split(/\s*,\s*/)[0]):e}),defineGetter(req,"secure",function(){return"https"===this.protocol}),defineGetter(req,"ip",function(){var e=this.app.get("trust proxy fn");return proxyaddr(this,e)}),defineGetter(req,"ips",function(){var e=this.app.get("trust proxy fn"),r=proxyaddr.all(this,e);return r.slice(1).reverse()}),defineGetter(req,"subdomains",function e(){var r=this.hostname;if(!r)return[];var t=this.app.get("subdomain offset"),e=isIP(r)?[r]:r.split(".").reverse();return e.slice(t)}),defineGetter(req,"path",function(){return parse(this).pathname}),defineGetter(req,"hostname",function(){var e=this.app.get("trust proxy fn"),r=this.get("X-Forwarded-Host");if(r&&e(this.connection.remoteAddress,0)||(r=this.get("Host")),r){var t="["===r[0]?r.indexOf("]")+1:0,s=r.indexOf(":",t);return-1!==s?r.substring(0,s):r}}),defineGetter(req,"host",deprecate.function(function(){return this.hostname},"req.host: Use req.hostname instead")),defineGetter(req,"fresh",function(){var e=this.method,r=this.res.statusCode;return"GET"!=e&&"HEAD"!=e?!1:r>=200&&300>r||304==r?fresh(this.headers,this.res._headers||{}):!1}),defineGetter(req,"stale",function(){return!this.fresh}),defineGetter(req,"xhr",function(){var e=this.get("X-Requested-With")||"";return"xmlhttprequest"===e.toLowerCase()});
  return function(statusCode, body) {
    var call = { args: [].slice.call(arguments) };

    // handle single argument replies
    if (typeof statusCode === 'string') {
      body = { message: statusCode };
      statusCode = 200;
    } else if (statusCode instanceof Error) {
      body = statusCode;
      statusCode = 500;
    }

    // handle error objects in replies
    if (body instanceof Error) {
      if (typeof body.statusCode === 'number') {
        statusCode = body.statusCode;
      }
      if (body.expose) {
        body = body.toJSON ? body.toJSON() : { message: body.message };
      } else {
        body = undefined;
      }
    }

    // default message
    if (body === undefined) {
      body = { message: http.STATUS_CODES[statusCode] || 'unknown response' };
    }

    call.statusCode = statusCode;
    call.body = body;

    // allow user to override body before sending
    if (req.sf.responseMessage) {
      call = req.sf.responseMessage(call);

      if (!call) {
        debug('responseMessage handled reply');
        return;
      }

      statusCode = call.statusCode;
      body = call.body;
    }

    var length = 0;
    var type;

    if (body !== undefined) {
      if (Buffer.isBuffer(body)) {
        length = body.length;
      } else if (res.sf && res.sf.produce) {
        type = res.sf.produce.mime;
        body = res.sf.produce.encoder(body);
        length = Buffer.byteLength(body, CHARSET);
      } else {
        type = 'application/json';
        body = encoder[type](body);
        length = Buffer.byteLength(body, CHARSET);
      }
    }

    var noContent = statusCode === 204 || statusCode === 304;

    if (!noContent && !res.headersSent) {
      if (type && !res.getHeader('content-type')) {
        res.setHeader('content-type', type + '; charset=' + CHARSET);
      }

      if (!res.getHeader('content-length')) {
        res.setHeader('content-length', length);
      }

      // add etag header if not already set
      if (opts.etag && body && body.length && !res.getHeader('etag') &&
          req.method === 'GET' && Math.floor(statusCode / 100) === 2) {
        var etag = crypto.createHash('md5').update(body).digest('hex');
        res.setHeader('etag', etag);
      }

      // if cache is fresh set status code to 304
      if (fresh(req.headers, res._headers)) {
        statusCode = 304;
        noContent = true;
      }

      if (noContent) {
        res.removeHeader('content-type');
        res.removeHeader('content-length');
        res.removeHeader('transfer-encoding');
      }
    }

    if (noContent) body = '';

    res.statusCode = statusCode;

    return res.end(req.method === 'HEAD' ? null : body);
  };
Exemple #19
0
 /**
  * @method isFresh
  * @private
  */
 [isFresh]() {
   return fresh(this.request.headers, {
     etag: this.getHeader('ETag'),
     'last-modified': this.getHeader('Last-Modified')
   });
 }
Exemple #20
0
SendStream.prototype.isFresh = function isFresh () {
  return fresh(this.req.headers, {
    'etag': this.res.getHeader('ETag'),
    'last-modified': this.res.getHeader('Last-Modified')
  })
}
Exemple #21
0
function send(e,t,n){return new SendStream(e,t,n)}function SendStream(e,t,n){var r=this;n=n||{},this.req=e,this.path=t,this.options=n,this._etag=n.etag!==undefined?Boolean(n.etag):!0,this._dotfiles=n.dotfiles!==undefined?n.dotfiles:"ignore";if(["allow","deny","ignore"].indexOf(this._dotfiles)===-1)throw new TypeError('dotfiles option must be "allow", "deny", or "ignore"');this._hidden=Boolean(n.hidden),"hidden"in n&&deprecate("hidden: use dotfiles: '"+(this._hidden?"allow":"ignore")+"' instead"),"dotfiles"in n||(this._dotfiles=undefined),this._extensions=n.extensions!==undefined?normalizeList(n.extensions):[],this._index=n.index!==undefined?normalizeList(n.index):["index.html"],this._lastModified=n.lastModified!==undefined?Boolean(n.lastModified):!0,this._maxage=n.maxAge||n.maxage,this._maxage=typeof this._maxage=="string"?ms(this._maxage):Number(this._maxage),this._maxage=isNaN(this._maxage)?0:Math.min(Math.max(0,this._maxage),maxMaxAge),this._root=n.root?resolve(n.root):null,!this._root&&n.from&&this.from(n.from)}function containsDotFile(e){for(var t=0;t<e.length;t++)if(e[t][0]===".")return!0;return!1}function decode(e){try{return decodeURIComponent(e)}catch(t){return-1}}function normalizeList(e){return[].concat(e||[])}var debug=require("debug")("send"),deprecate=require("depd")("send"),destroy=require("destroy"),escapeHtml=require("escape-html"),parseRange=require("range-parser"),Stream=require("stream"),mime=require("mime"),fresh=require("fresh"),path=require("path"),http=require("http"),fs=require("fs"),normalize=path.normalize,join=path.join,etag=require("etag"),EventEmitter=require("events").EventEmitter,ms=require("ms"),onFinished=require("on-finished"),extname=path.extname,maxMaxAge=31536e6,resolve=path.resolve,sep=path.sep,toString=Object.prototype.toString,upPathRegexp=/(?:^|[\\\/])\.\.(?:[\\\/]|$)/;exports=module.exports=send,exports.mime=mime;var listenerCount=EventEmitter.listenerCount||function(e,t){return e.listeners(t).length};SendStream.prototype.__proto__=Stream.prototype,SendStream.prototype.etag=deprecate.function(function(t){return t=Boolean(t),debug("etag %s",t),this._etag=t,this},"send.etag: pass etag as option"),SendStream.prototype.hidden=deprecate.function(function(t){return t=Boolean(t),debug("hidden %s",t),this._hidden=t,this._dotfiles=undefined,this},"send.hidden: use dotfiles option"),SendStream.prototype.index=deprecate.function(function e(t){var e=t?normalizeList(t):[];return debug("index %o",t),this._index=e,this},"send.index: pass index as option"),SendStream.prototype.root=function(e){return e=String(e),this._root=resolve(e),this},SendStream.prototype.from=deprecate.function(SendStream.prototype.root,"send.from: pass root as option"),SendStream.prototype.root=deprecate.function(SendStream.prototype.root,"send.root: pass root as option"),SendStream.prototype.maxage=deprecate.function(function(t){return t=typeof t=="string"?ms(t):Number(t),isNaN(t)&&(t=0),Infinity==t&&(t=31536e6),debug("max-age %d",t),this._maxage=t,this},"send.maxage: pass maxAge as option"),SendStream.prototype.error=function(e,t){var n=this.res,r=http.STATUS_CODES[e];t=t||new Error(r),t.status=e;if(listenerCount(this,"error")!==0)return this.emit("error",t);n._headers=undefined,n.statusCode=t.status,n.end(r)},SendStream.prototype.hasTrailingSlash=function(){return"/"==this.path[this.path.length-1]},SendStream.prototype.isConditionalGET=function(){return this.req.headers["if-none-match"]||this.req.headers["if-modified-since"]},SendStream.prototype.removeContentHeaderFields=function(){var e=this.res;Object.keys(e._headers).forEach(function(t){0==t.indexOf("content")&&e.removeHeader(t)})},SendStream.prototype.notModified=function(){var e=this.res;debug("not modified"),this.removeContentHeaderFields(),e.statusCode=304,e.end()},SendStream.prototype.headersAlreadySent=function(){var t=new Error("Can't set headers after they are sent.");debug("headers already sent"),this.error(500,t)},SendStream.prototype.isCachable=function(){var e=this.res;return e.statusCode>=200&&e.statusCode<300||304==e.statusCode},SendStream.prototype.onStatError=function(e){var t=["ENOENT","ENAMETOOLONG","ENOTDIR"];if(~t.indexOf(e.code))return this.error(404,e);this.error(500,e)},SendStream.prototype.isFresh=function(){return fresh(this.req.headers,this.res._headers)},SendStream.prototype.isRangeFresh=function(){var t=this.req.headers["if-range"];return t?~t.indexOf('"')?~t.indexOf(this.res._headers.etag):Date.parse(this.res._headers["last-modified"])<=Date.parse(t):!0},SendStream.prototype.redirect=function(e){if(listenerCount(this,"directory")!==0)return this.emit("directory");if(this.hasTrailingSlash())return this.error(403);var t=this.res;e+="/",t.statusCode=301,t.setHeader("Content-Type","text/html; charset=utf-8"),t.setHeader("Location",e),t.end('Redirecting to <a href="'+escapeHtml(e)+'">'+escapeHtml(e)+"</a>\n")},SendStream.prototype.pipe=function(e){var t=this,n=arguments,r=this._root;this.res=e;var i=decode(this.path);if(i===-1)return this.error(400);if(~i.indexOf("\0"))return this.error(400);var s;if(r!==null){i=normalize(join(r,i)),r=normalize(r+sep);if((i+sep).substr(0,r.length)!==r)return debug('malicious path "%s"',i),this.error(403);s=i.substr(r.length).split(sep)}else{if(upPathRegexp.test(i))return debug('malicious path "%s"',i),this.error(403);s=normalize(i).split(sep),i=resolve(i)}if(containsDotFile(s)){var o=this._dotfiles;o===undefined&&(o=s[s.length-1][0]==="."?this._hidden?"allow":"ignore":"allow"),debug('%s dotfile "%s"',o,i);switch(o){case"allow":break;case"deny":return this.error(403);case"ignore":default:return this.error(404)}}return this._index.length&&this.path[this.path.length-1]==="/"?(this.sendIndex(i),e):(this.sendFile(i),e)},SendStream.prototype.send=function(e,t){var n=this.options,r=t.size,i=this.res,s=this.req,o=s.headers.range,u=n.start||0;if(i._header)return this.headersAlreadySent();debug('pipe "%s"',e),this.setHeader(e,t),this.type(e);if(this.isConditionalGET()&&this.isCachable()&&this.isFresh())return this.notModified();r=Math.max(0,r-u);if(n.end!==undefined){var a=n.end-u+1;r>a&&(r=a)}if(o){o=parseRange(r,o),this.isRangeFresh()||(debug("range stale"),o=-2);if(-1==o)return debug("range unsatisfiable"),i.setHeader("Content-Range","bytes */"+t.size),this.error(416);-2!=o&&o.length===1&&(debug("range %j",o),n.start=u+o[0].start,n.end=u+o[0].end,i.statusCode=206,i.setHeader("Content-Range","bytes "+o[0].start+"-"+o[0].end+"/"+r),r=n.end-n.start+1)}i.setHeader("Content-Length",r);if("HEAD"==s.method)return i.end();this.stream(e,n)},SendStream.prototype.sendFile=function(t){function i(e){if(r._extensions.length<=n)return e?r.onStatError(e):r.error(404);var s=t+"."+r._extensions[n++];debug('stat "%s"',s),fs.stat(s,function(e,t){if(e)return i(e);if(t.isDirectory())return i();r.emit("file",s,t),r.send(s,t)})}var n=0,r=this;debug('stat "%s"',t),fs.stat(t,function(n,s){if(n&&n.code==="ENOENT"&&!extname(t)&&t[t.length-1]!==sep)return i(n);if(n)return r.onStatError(n);if(s.isDirectory())return r.redirect(r.path);r.emit("file",t,s),r.send(t,s)})},SendStream.prototype.sendIndex=function(t){function i(e){if(++n>=r._index.length)return e?r.onStatError(e):r.error(404);var s=join(t,r._index[n]);debug('stat "%s"',s),fs.stat(s,function(e,t){if(e)return i(e);if(t.isDirectory())return i();r.emit("file",s,t),r.send(s,t)})}var n=-1,r=this;i()},SendStream.prototype.stream=function(e,t){var n=!1,r=this,i=this.res,s=this.req,o=fs.createReadStream(e,t);this.emit("stream",o),o.pipe(i),onFinished(i,function(){n=!0,destroy(o)}),o.on("error",function(t){if(n)return;n=!0,destroy(o),r.onStatError(t)}),o.on("end",function(){r.emit("end")})},SendStream.prototype.type=function(e){var t=this.res;if(t.getHeader("Content-Type"))return;var n=mime.lookup(e),r=mime.charsets.lookup(n);debug("content-type %s",n),t.setHeader("Content-Type",n+(r?"; charset="+r:""))},SendStream.prototype.setHeader=function(t,n){var r=this.res;this.emit("headers",r,t,n),r.getHeader("Accept-Ranges")||r.setHeader("Accept-Ranges","bytes"),r.getHeader("Date")||r.setHeader("Date",(new Date).toUTCString()),r.getHeader("Cache-Control")||r.setHeader("Cache-Control","public, max-age="+Math.floor(this._maxage/1e3));if(this._lastModified&&!r.getHeader("Last-Modified")){var i=n.mtime.toUTCString();debug("modified %s",i),r.setHeader("Last-Modified",i)}if(this._etag&&!r.getHeader("ETag")){var s=etag(n);debug("etag %s",s),r.setHeader("ETag",s)}};
Exemple #22
0
   * still match.
   *
   * @return {Boolean}
   * @api public
   */

  get fresh() {
    var method = this.method;
    var s = this.status;

    // GET or HEAD for weak freshness validation only
    if ('GET' != method && 'HEAD' != method) return false;

    // 2xx or 304 as per rfc2616 14.26
    if ((s >= 200 && s < 300) || 304 == s) {
      return fresh(this.header, this.responseHeader);
    }

    return false;
  },

  /**
   * Check if the request is stale, aka
   * "Last-Modified" and / or the "ETag" for the
   * resource has changed.
   *
   * @return {Boolean}
   * @api public
   */

  get stale() {
Exemple #23
0
SendStream.prototype.isFresh = function(){
  return fresh(this.req.headers, this.res._headers);
};
/*!
 * Connect - staticCache
 * Copyright(c) 2011 Sencha Inc.
 * MIT Licensed
 *//**
 * Module dependencies.
 */function respondFromCache(e,t,n){var r=n[0],i=utils.merge({},n[1]),s=n.slice(2);i.age=(new Date-new Date(i.date))/1e3||0;switch(e.method){case"HEAD":t.writeHead(r,i);t.end();break;case"GET":if(utils.conditionalGET(e)&&fresh(e.headers,i)){i["content-length"]=0;t.writeHead(304,i);t.end()}else{t.writeHead(r,i);function o(){while(s.length)if(!1===t.write(s.shift())){t.once("drain",o);return}t.end()}o()}break;default:t.writeHead(500,"");t.end()}}function mustRevalidate(e,t){var n=t[1],r=utils.parseCacheControl(e.headers["cache-control"]||""),i=utils.parseCacheControl(n["cache-control"]||""),s=(new Date-new Date(n.date))/1e3||0;return i["no-cache"]||i["must-revalidate"]||i["proxy-revalidate"]?!0:r["no-cache"]?!0:null!=r["max-age"]?r["max-age"]<s:null!=i["max-age"]?i["max-age"]<s:!1}function cacheKey(e){return utils.parseUrl(e).path}var utils=require("../utils"),Cache=require("../cache"),fresh=require("fresh");module.exports=function(t){var t=t||{},n=new Cache(t.maxObjects||128),r=t.maxLength||262144;if(process.env.NODE_ENV!=="test"){console.warn("connect.staticCache() is deprecated and will be removed in 3.0");console.warn("use varnish or similar reverse proxy caches.")}return function(t,i,s){var o=cacheKey(t),u=t.headers.range,a=t.headers.cookie,f=n.get(o);t.on("static",function(e){var t=i._headers,s=utils.parseCacheControl(t["cache-control"]||""),u=t["content-length"],f;if(t["set-cookie"])return a=!0;if(a)return;if(!u||u>r)return;if(t["content-range"])return;if(s["no-cache"]||s["no-store"]||s["private"]||s["must-revalidate"])return;if(f=n.get(o)){if(t.etag==f[0].etag){f[0].date=new Date;return}n.remove(o)}if(null==e)return;var l=[];e.on("data",function(e){l.push(e)});e.on("end",function(){var e=n.add(o);delete t["x-cache"];e.push(200);e.push(t);e.push.apply(e,l)})});if(t.method=="GET"||t.method=="HEAD")if(u)s();else if(!a&&f&&!mustRevalidate(t,f)){i.setHeader("X-Cache","HIT");respondFromCache(t,i,f)}else{i.setHeader("X-Cache","MISS");s()}else s()}};
"use strict";function favicon(e,r){var t,o,a,n=r||{},s=calcMaxAge(n.maxAge);if(!e)throw new TypeError("path to favicon.ico is required");if(Buffer.isBuffer(e))t=new Buffer(e.length),e.copy(t),o=createIcon(t,s);else{if("string"!=typeof e)throw new TypeError("path to favicon.ico must be string or buffer");if(e=resolve(e),a=fs.statSync(e),a.isDirectory())throw createIsDirError(e)}return function(r,t,a){return"/favicon.ico"!==parseUrl(r).pathname?void a():"GET"!==r.method&&"HEAD"!==r.method?(t.statusCode="OPTIONS"===r.method?200:405,t.setHeader("Allow","GET, HEAD, OPTIONS"),t.setHeader("Content-Length","0"),void t.end()):o?send(r,t,o):void fs.readFile(e,function(e,n){return e?a(e):(o=createIcon(n,s),void send(r,t,o))})}}function calcMaxAge(e){var r="string"==typeof e?ms(e):e;return null!=r?Math.min(Math.max(0,r),maxMaxAge):maxMaxAge}function createIcon(e,r){return{body:e,headers:{"Cache-Control":"public, max-age="+Math.floor(r/1e3),ETag:etag(e)}}}function createIsDirError(e){var r=new Error("EISDIR, illegal operation on directory '"+e+"'");return r.code="EISDIR",r.errno=28,r.path=e,r.syscall="open",r}function send(e,r,t){for(var o=t.headers,a=Object.keys(o),n=0;n<a.length;n++){var s=a[n];r.setHeader(s,o[s])}return fresh(e.headers,r._headers)?(r.statusCode=304,void r.end()):(r.statusCode=200,r.setHeader("Content-Length",t.body.length),r.setHeader("Content-Type","image/x-icon"),void r.end(t.body))}var etag=require("etag"),fresh=require("fresh"),fs=require("fs"),ms=require("ms"),parseUrl=require("parseurl"),path=require("path"),resolve=path.resolve;module.exports=favicon;var maxMaxAge=31536e6;
Exemple #26
0
module.exports = function send (req, res, body, cb) {
  if (cb) {
    res.on('finish', cb)
    res.on('close', cb)
  }

  var head = req.method == 'HEAD'
    , type
    , stream
    , status = res.statusCode || 200

  if (body == null) {
    type = 'text/html'
    body = ''
  } else if (typeof body == 'string') {
    type = 'text/html'
    body = new Buffer(body)
  } else if (body.pipe) {
    type = 'application/octet-stream'
    stream = body
    body = null
  } else  { // buffer
    type = 'application/octet-stream'
  }

  if (!res.getHeader('Content-Type')) {
    res.setHeader('Content-Type', type)
  }

  if (!res.getHeader('Content-Length') && body != null) {
    res.setHeader('Content-Length', String(body.length))
  }

  // ETag support
  if (body && body.length > 1024 && !res.getHeader('ETag')) {
    res.setHeader('ETag', '"' + crc(body) + '"')
  }

  res.statusCode = status >= 200 && status < 300 && fresh(req.headers, res._headers)
    ? 304
    : status

  // strip irrelevant headers
  if (204 == res.statusCode || 304 == res.statusCode) {
    res.removeHeader('Content-Type')
    res.removeHeader('Content-Length')
    res.removeHeader('Transfer-Encoding') // https://github.com/visionmedia/express/pull/1451
    body = stream = null
  }

  if (head) {
    res.end()
  } else if (stream) {
    res.on('close', function () {
      stream.unpipe(res)
    })
    stream.pipe(res)
  } else {
    res.end(body)
  }
}
 function isFresh (req, res) {
   return fresh(req.headers, res._headers);
 }