211 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
 | 
						|
/**
 | 
						|
 * Module dependencies.
 | 
						|
 */
 | 
						|
 | 
						|
var util = require('util');
 | 
						|
var utils = require('./utils');
 | 
						|
var Stream = require('stream');
 | 
						|
 | 
						|
/**
 | 
						|
 * Expose `Response`.
 | 
						|
 */
 | 
						|
 | 
						|
module.exports = Response;
 | 
						|
 | 
						|
/**
 | 
						|
 * Initialize a new `Response` with the given `xhr`.
 | 
						|
 *
 | 
						|
 *  - set flags (.ok, .error, etc)
 | 
						|
 *  - parse header
 | 
						|
 *
 | 
						|
 * @param {Request} req
 | 
						|
 * @param {Object} options
 | 
						|
 * @constructor
 | 
						|
 * @extends {Stream}
 | 
						|
 * @implements {ReadableStream}
 | 
						|
 * @api private
 | 
						|
 */
 | 
						|
 | 
						|
function Response(req, options) {
 | 
						|
  Stream.call(this);
 | 
						|
  options = options || {};
 | 
						|
  var res = this.res = req.res;
 | 
						|
  this.request = req;
 | 
						|
  this.req = req.req;
 | 
						|
  this.links = {};
 | 
						|
  this.text = res.text;
 | 
						|
  this.body = res.body !== undefined ? res.body : {};
 | 
						|
  this.files = res.files || {};
 | 
						|
  this.buffered = 'string' == typeof this.text;
 | 
						|
  this.header = this.headers = res.headers;
 | 
						|
  this.setStatusProperties(res.statusCode);
 | 
						|
  this.setHeaderProperties(this.header);
 | 
						|
  this.setEncoding = res.setEncoding.bind(res);
 | 
						|
  res.on('data', this.emit.bind(this, 'data'));
 | 
						|
  res.on('end', this.emit.bind(this, 'end'));
 | 
						|
  res.on('close', this.emit.bind(this, 'close'));
 | 
						|
  res.on('error', this.emit.bind(this, 'error'));
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Inherit from `Stream`.
 | 
						|
 */
 | 
						|
 | 
						|
util.inherits(Response, Stream);
 | 
						|
 | 
						|
/**
 | 
						|
 * Get case-insensitive `field` value.
 | 
						|
 *
 | 
						|
 * @param {String} field
 | 
						|
 * @return {String}
 | 
						|
 * @api public
 | 
						|
 */
 | 
						|
 | 
						|
Response.prototype.get = function(field){
 | 
						|
  return this.header[field.toLowerCase()];
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Implements methods of a `ReadableStream`
 | 
						|
 */
 | 
						|
 | 
						|
Response.prototype.destroy = function(err){
 | 
						|
  this.res.destroy(err);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Pause.
 | 
						|
 */
 | 
						|
 | 
						|
Response.prototype.pause = function(){
 | 
						|
  this.res.pause();
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Resume.
 | 
						|
 */
 | 
						|
 | 
						|
Response.prototype.resume = function(){
 | 
						|
  this.res.resume();
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Return an `Error` representative of this response.
 | 
						|
 *
 | 
						|
 * @return {Error}
 | 
						|
 * @api public
 | 
						|
 */
 | 
						|
 | 
						|
Response.prototype.toError = function(){
 | 
						|
  var req = this.req;
 | 
						|
  var method = req.method;
 | 
						|
  var path = req.path;
 | 
						|
 | 
						|
  var msg = 'cannot ' + method + ' ' + path + ' (' + this.status + ')';
 | 
						|
  var err = new Error(msg);
 | 
						|
  err.status = this.status;
 | 
						|
  err.text = this.text;
 | 
						|
  err.method = method;
 | 
						|
  err.path = path;
 | 
						|
 | 
						|
  return err;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Set header related properties:
 | 
						|
 *
 | 
						|
 *   - `.type` the content type without params
 | 
						|
 *
 | 
						|
 * A response of "Content-Type: text/plain; charset=utf-8"
 | 
						|
 * will provide you with a `.type` of "text/plain".
 | 
						|
 *
 | 
						|
 * @param {Object} header
 | 
						|
 * @api private
 | 
						|
 */
 | 
						|
 | 
						|
Response.prototype.setHeaderProperties = function(header){
 | 
						|
  // TODO: moar!
 | 
						|
  // TODO: make this a util
 | 
						|
 | 
						|
  // content-type
 | 
						|
  var ct = this.header['content-type'] || '';
 | 
						|
 | 
						|
  // params
 | 
						|
  var params = utils.params(ct);
 | 
						|
  for (var key in params) this[key] = params[key];
 | 
						|
 | 
						|
  this.type = utils.type(ct);
 | 
						|
 | 
						|
  // links
 | 
						|
  try {
 | 
						|
    if (header.link) this.links = utils.parseLinks(header.link);
 | 
						|
  } catch (err) {
 | 
						|
    // ignore
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Set flags such as `.ok` based on `status`.
 | 
						|
 *
 | 
						|
 * For example a 2xx response will give you a `.ok` of __true__
 | 
						|
 * whereas 5xx will be __false__ and `.error` will be __true__. The
 | 
						|
 * `.clientError` and `.serverError` are also available to be more
 | 
						|
 * specific, and `.statusType` is the class of error ranging from 1..5
 | 
						|
 * sometimes useful for mapping respond colors etc.
 | 
						|
 *
 | 
						|
 * "sugar" properties are also defined for common cases. Currently providing:
 | 
						|
 *
 | 
						|
 *   - .noContent
 | 
						|
 *   - .badRequest
 | 
						|
 *   - .unauthorized
 | 
						|
 *   - .notAcceptable
 | 
						|
 *   - .notFound
 | 
						|
 *
 | 
						|
 * @param {Number} status
 | 
						|
 * @api private
 | 
						|
 */
 | 
						|
 | 
						|
Response.prototype.setStatusProperties = function(status){
 | 
						|
  var type = status / 100 | 0;
 | 
						|
 | 
						|
  // status / class
 | 
						|
  this.status = this.statusCode = status;
 | 
						|
  this.statusType = type;
 | 
						|
 | 
						|
  // basics
 | 
						|
  this.info = 1 == type;
 | 
						|
  this.ok = 2 == type;
 | 
						|
  this.redirect = 3 == type;
 | 
						|
  this.clientError = 4 == type;
 | 
						|
  this.serverError = 5 == type;
 | 
						|
  this.error = (4 == type || 5 == type)
 | 
						|
    ? this.toError()
 | 
						|
    : false;
 | 
						|
 | 
						|
  // sugar
 | 
						|
  this.accepted = 202 == status;
 | 
						|
  this.noContent = 204 == status;
 | 
						|
  this.badRequest = 400 == status;
 | 
						|
  this.unauthorized = 401 == status;
 | 
						|
  this.notAcceptable = 406 == status;
 | 
						|
  this.forbidden = 403 == status;
 | 
						|
  this.notFound = 404 == status;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * To json.
 | 
						|
 *
 | 
						|
 * @return {Object}
 | 
						|
 * @api public
 | 
						|
 */
 | 
						|
 | 
						|
Response.prototype.toJSON = function(){
 | 
						|
  return {
 | 
						|
    req: this.request.toJSON(),
 | 
						|
    header: this.header,
 | 
						|
    status: this.status,
 | 
						|
    text: this.text
 | 
						|
  };
 | 
						|
};
 |