357 lines · 8.5 KB · JavaScript
RawDownload
 /*! * Express - request * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca> * MIT Licensed */ /** * Module dependencies. */ var http = require('http')  , req = http.IncomingMessage.prototype  , utils = require('./utils')  , parse = require('url').parse  , mime = require('mime'); /** * Default flash formatters. * * @type Object */ var flashFormatters = exports.flashFormatters = {  s: function(val){    return String(val);  }}; /** * Return request header or optional default. * * The `Referrer` header field is special-cased, * both `Referrer` and `Referer` will yield are * interchangeable. * * Examples: * *     req.header('Content-Type'); *     // => "text/plain" *      *     req.header('content-type'); *     // => "text/plain" *      *     req.header('Accept'); *     // => undefined *      *     req.header('Accept', 'text/html'); *     // => "text/html" * * @param {String} name * @param {String} defaultValue * @return {String}  * @api public */ req.header = function(name, defaultValue){  switch (name = name.toLowerCase()) {    case 'referer':    case 'referrer':      return this.headers.referrer        || this.headers.referer        || defaultValue;    default:      return this.headers[name] || defaultValue;  }}; /** * Get `field`'s `param` value, defaulting to ''. * * Examples: * *     req.get('content-disposition', 'filename'); *     // => "something.png" * * @param {String} field * @param {String} param * @return {String} * @api public */ req.get = function(field, param){  var val = this.header(field);  if (!val) return '';  var regexp = new RegExp(param + ' *= *(?:"([^"]+)"|([^;]+))', 'i');  if (!regexp.exec(val)) return '';  return RegExp.$1 || RegExp.$2;}; /** * Short-hand for `require('url').parse(req.url).pathname`. * * @return {String} * @api public */ req.__defineGetter__('path', function(){  return parse(this.url).pathname;}); /** * Check if the _Accept_ header is present, and includes the given `type`. * * When the _Accept_ header is not present `true` is returned. Otherwise * the given `type` is matched by an exact match, and then subtypes. You * may pass the subtype such as "html" which is then converted internally * to "text/html" using the mime lookup table. * * Examples: *  *     // Accept: text/html *     req.accepts('html'); *     // => true * *     // Accept: text/*; application/json *     req.accepts('html'); *     req.accepts('text/html'); *     req.accepts('text/plain'); *     req.accepts('application/json'); *     // => true * *     req.accepts('image/png'); *     req.accepts('png'); *     // => false * * @param {String} type * @return {Boolean} * @api public */ req.accepts = function(type){  var accept = this.header('Accept');   // normalize extensions ".json" -> "json"  if (type && '.' == type[0]) type = type.substr(1);   // when Accept does not exist, or contains '*/*' return true  if (!accept || ~accept.indexOf('*/*')) {    return true;  } else if (type) {    // allow "html" vs "text/html" etc    if (!~type.indexOf('/')) type = mime.lookup(type);     // check if we have a direct match    if (~accept.indexOf(type)) return true;     // check if we have type/*    type = type.split('/')[0] + '/*';    return !!~accept.indexOf(type);  } else {    return false;  }}; /** * Return the value of param `name` when present or `defaultValue`. * *  - Checks route placeholders, ex: _/user/:id_ *  - Checks query string params, ex: ?id=12 *  - Checks urlencoded body params, ex: id=12 * * To utilize urlencoded request bodies, `req.body` * should be an object. This can be done by using * the `connect.bodyParser` middleware. * * @param {String} name * @param {Mixed} defaultValue * @return {String} * @api public */ req.param = function(name, defaultValue){  // route params like /user/:id  if (this.params && this.params.hasOwnProperty(name) && undefined !== this.params[name]) {    return this.params[name];   }  // query string params  if (undefined !== this.query[name]) {    return this.query[name];   }  // request body params via connect.bodyParser  if (this.body && undefined !== this.body[name]) {    return this.body[name];  }  return defaultValue;}; /** * Queue flash `msg` of the given `type`. * * Examples: * *      req.flash('info', 'email sent'); *      req.flash('error', 'email delivery failed'); *      req.flash('info', 'email re-sent'); *      // => 2 * *      req.flash('info'); *      // => ['email sent', 'email re-sent'] * *      req.flash('info'); *      // => [] * *      req.flash(); *      // => { error: ['email delivery failed'], info: [] } * * Formatting: * * Flash notifications also support arbitrary formatting support. * For example you may pass variable arguments to `req.flash()` * and use the %s specifier to be replaced by the associated argument: * *     req.flash('info', 'email has been sent to %s.', userName); * * To add custom formatters use the `exports.flashFormatters` object. * * @param {String} type * @param {String} msg * @return {Array|Object|Number} * @api public */ req.flash = function(type, msg){  if (this.session === undefined) throw Error('req.flash() requires sessions');  var msgs = this.session.flash = this.session.flash || {};  if (type && msg) {    var i = 2      , args = arguments      , formatters = this.app.flashFormatters || {};    formatters.__proto__ = flashFormatters;    msg = utils.miniMarkdown(msg);    msg = msg.replace(/%([a-zA-Z])/g, function(_, format){      var formatter = formatters[format];      if (formatter) return formatter(utils.escape(args[i++]));    });    return (msgs[type] = msgs[type] || []).push(msg);  } else if (type) {    var arr = msgs[type];    delete msgs[type];    return arr || [];  } else {    this.session.flash = {};    return msgs;  }}; /** * Check if the incoming request contains the "Content-Type"  * header field, and it contains the give mime `type`. * * Examples: * *      // With Content-Type: text/html; charset=utf-8 *      req.is('html'); *      req.is('text/html'); *      // => true *      *      // When Content-Type is application/json *      req.is('json'); *      req.is('application/json'); *      // => true *      *      req.is('html'); *      // => false *  * Ad-hoc callbacks can also be registered with Express, to perform * assertions again the request, for example if we need an expressive * way to check if our incoming request is an image, we can register "an image" * callback: *  *       app.is('an image', function(req){ *         return 0 == req.headers['content-type'].indexOf('image'); *       }); *        *  Now within our route callbacks, we can use to to assert content types *  such as "image/jpeg", "image/png", etc. *  *      app.post('/image/upload', function(req, res, next){ *        if (req.is('an image')) { *          // do something *        } else { *          next(); *        } *      }); *  * @param {String} type * @return {Boolean} * @api public */ req.is = function(type){  var fn = this.app.is(type);  if (fn) return fn(this);  var ct = this.headers['content-type'];  if (!ct) return false;  ct = ct.split(';')[0];  if (!~type.indexOf('/')) type = mime.lookup(type);  if (~type.indexOf('*')) {    type = type.split('/');    ct = ct.split('/');    if ('*' == type[0] && type[1] == ct[1]) return true;    if ('*' == type[1] && type[0] == ct[0]) return true;    return false;  }  return !! ~ct.indexOf(type);}; // Callback for isXMLHttpRequest / xhr function isxhr() {  return this.header('X-Requested-With', '').toLowerCase() === 'xmlhttprequest';} /** * Check if the request was an _XMLHttpRequest_. * * @return {Boolean} * @api public */ req.__defineGetter__('isXMLHttpRequest', isxhr);req.__defineGetter__('xhr', isxhr); /** * Return the protocol string "http" or "https" * when requested with TLS. When the "trust proxy"  * setting is enabled the "X-Forwarded-Proto" header * field will be trusted. If you're running behind * a reverse proxy that supplies https for you this * may be enabled. * * @return {String} * @api public */ req.__defineGetter__('protocol', function(){  var trustProxy = this.app.set('trust proxy');  return this.connection.encrypted    ? 'https'    : trustProxy      ? (this.header('X-Forwarded-Proto') || 'http')      : 'http';}); /** * Short-hand for: * *    req.protocol == 'https' * * @return {Boolean} * @api public */ req.__defineGetter__('secure', function(){  return 'https' == this.protocol;});