/node_modules/express/lib/request.js

https://bitbucket.org/gagginaspinnata/todo-app-with-angularjs · JavaScript · 484 lines · 147 code · 51 blank · 286 comment · 40 complexity · b58c2e8e3b1a37f9291a937ea312c863 MD5 · raw file

  1. /**
  2. * Module dependencies.
  3. */
  4. var http = require('http')
  5. , utils = require('./utils')
  6. , connect = require('connect')
  7. , fresh = require('fresh')
  8. , parseRange = require('range-parser')
  9. , parse = connect.utils.parseUrl
  10. , mime = connect.mime;
  11. /**
  12. * Request prototype.
  13. */
  14. var req = exports = module.exports = {
  15. __proto__: http.IncomingMessage.prototype
  16. };
  17. /**
  18. * Return request header.
  19. *
  20. * The `Referrer` header field is special-cased,
  21. * both `Referrer` and `Referer` are interchangeable.
  22. *
  23. * Examples:
  24. *
  25. * req.get('Content-Type');
  26. * // => "text/plain"
  27. *
  28. * req.get('content-type');
  29. * // => "text/plain"
  30. *
  31. * req.get('Something');
  32. * // => undefined
  33. *
  34. * Aliased as `req.header()`.
  35. *
  36. * @param {String} name
  37. * @return {String}
  38. * @api public
  39. */
  40. req.get =
  41. req.header = function(name){
  42. switch (name = name.toLowerCase()) {
  43. case 'referer':
  44. case 'referrer':
  45. return this.headers.referrer
  46. || this.headers.referer;
  47. default:
  48. return this.headers[name];
  49. }
  50. };
  51. /**
  52. * Check if the given `type(s)` is acceptable, returning
  53. * the best match when true, otherwise `undefined`, in which
  54. * case you should respond with 406 "Not Acceptable".
  55. *
  56. * The `type` value may be a single mime type string
  57. * such as "application/json", the extension name
  58. * such as "json", a comma-delimted list such as "json, html, text/plain",
  59. * or an array `["json", "html", "text/plain"]`. When a list
  60. * or array is given the _best_ match, if any is returned.
  61. *
  62. * Examples:
  63. *
  64. * // Accept: text/html
  65. * req.accepts('html');
  66. * // => "html"
  67. *
  68. * // Accept: text/*, application/json
  69. * req.accepts('html');
  70. * // => "html"
  71. * req.accepts('text/html');
  72. * // => "text/html"
  73. * req.accepts('json, text');
  74. * // => "json"
  75. * req.accepts('application/json');
  76. * // => "application/json"
  77. *
  78. * // Accept: text/*, application/json
  79. * req.accepts('image/png');
  80. * req.accepts('png');
  81. * // => undefined
  82. *
  83. * // Accept: text/*;q=.5, application/json
  84. * req.accepts(['html', 'json']);
  85. * req.accepts('html, json');
  86. * // => "json"
  87. *
  88. * @param {String|Array} type(s)
  89. * @return {String}
  90. * @api public
  91. */
  92. req.accepts = function(type){
  93. return utils.accepts(type, this.get('Accept'));
  94. };
  95. /**
  96. * Check if the given `charset` is acceptable,
  97. * otherwise you should respond with 406 "Not Acceptable".
  98. *
  99. * @param {String} charset
  100. * @return {Boolean}
  101. * @api public
  102. */
  103. req.acceptsCharset = function(charset){
  104. var accepted = this.acceptedCharsets;
  105. return accepted.length
  106. ? ~accepted.indexOf(charset)
  107. : true;
  108. };
  109. /**
  110. * Check if the given `lang` is acceptable,
  111. * otherwise you should respond with 406 "Not Acceptable".
  112. *
  113. * @param {String} lang
  114. * @return {Boolean}
  115. * @api public
  116. */
  117. req.acceptsLanguage = function(lang){
  118. var accepted = this.acceptedLanguages;
  119. return accepted.length
  120. ? ~accepted.indexOf(lang)
  121. : true;
  122. };
  123. /**
  124. * Parse Range header field,
  125. * capping to the given `size`.
  126. *
  127. * Unspecified ranges such as "0-" require
  128. * knowledge of your resource length. In
  129. * the case of a byte range this is of course
  130. * the total number of bytes. If the Range
  131. * header field is not given `null` is returned,
  132. * `-1` when unsatisfiable, `-2` when syntactically invalid.
  133. *
  134. * NOTE: remember that ranges are inclusive, so
  135. * for example "Range: users=0-3" should respond
  136. * with 4 users when available, not 3.
  137. *
  138. * @param {Number} size
  139. * @return {Array}
  140. * @api public
  141. */
  142. req.range = function(size){
  143. var range = this.get('Range');
  144. if (!range) return;
  145. return parseRange(size, range);
  146. };
  147. /**
  148. * Return an array of Accepted media types
  149. * ordered from highest quality to lowest.
  150. *
  151. * Examples:
  152. *
  153. * [ { value: 'application/json',
  154. * quality: 1,
  155. * type: 'application',
  156. * subtype: 'json' },
  157. * { value: 'text/html',
  158. * quality: 0.5,
  159. * type: 'text',
  160. * subtype: 'html' } ]
  161. *
  162. * @return {Array}
  163. * @api public
  164. */
  165. req.__defineGetter__('accepted', function(){
  166. var accept = this.get('Accept');
  167. return accept
  168. ? utils.parseAccept(accept)
  169. : [];
  170. });
  171. /**
  172. * Return an array of Accepted languages
  173. * ordered from highest quality to lowest.
  174. *
  175. * Examples:
  176. *
  177. * Accept-Language: en;q=.5, en-us
  178. * ['en-us', 'en']
  179. *
  180. * @return {Array}
  181. * @api public
  182. */
  183. req.__defineGetter__('acceptedLanguages', function(){
  184. var accept = this.get('Accept-Language');
  185. return accept
  186. ? utils
  187. .parseQuality(accept)
  188. .map(function(obj){
  189. return obj.value;
  190. })
  191. : [];
  192. });
  193. /**
  194. * Return an array of Accepted charsets
  195. * ordered from highest quality to lowest.
  196. *
  197. * Examples:
  198. *
  199. * Accept-Charset: iso-8859-5;q=.2, unicode-1-1;q=0.8
  200. * ['unicode-1-1', 'iso-8859-5']
  201. *
  202. * @return {Array}
  203. * @api public
  204. */
  205. req.__defineGetter__('acceptedCharsets', function(){
  206. var accept = this.get('Accept-Charset');
  207. return accept
  208. ? utils
  209. .parseQuality(accept)
  210. .map(function(obj){
  211. return obj.value;
  212. })
  213. : [];
  214. });
  215. /**
  216. * Return the value of param `name` when present or `defaultValue`.
  217. *
  218. * - Checks route placeholders, ex: _/user/:id_
  219. * - Checks body params, ex: id=12, {"id":12}
  220. * - Checks query string params, ex: ?id=12
  221. *
  222. * To utilize request bodies, `req.body`
  223. * should be an object. This can be done by using
  224. * the `connect.bodyParser()` middleware.
  225. *
  226. * @param {String} name
  227. * @param {Mixed} defaultValue
  228. * @return {String}
  229. * @api public
  230. */
  231. req.param = function(name, defaultValue){
  232. var params = this.params || {};
  233. var body = this.body || {};
  234. var query = this.query || {};
  235. if (null != params[name] && params.hasOwnProperty(name)) return params[name];
  236. if (null != body[name]) return body[name];
  237. if (null != query[name]) return query[name];
  238. return defaultValue;
  239. };
  240. /**
  241. * Check if the incoming request contains the "Content-Type"
  242. * header field, and it contains the give mime `type`.
  243. *
  244. * Examples:
  245. *
  246. * // With Content-Type: text/html; charset=utf-8
  247. * req.is('html');
  248. * req.is('text/html');
  249. * req.is('text/*');
  250. * // => true
  251. *
  252. * // When Content-Type is application/json
  253. * req.is('json');
  254. * req.is('application/json');
  255. * req.is('application/*');
  256. * // => true
  257. *
  258. * req.is('html');
  259. * // => false
  260. *
  261. * @param {String} type
  262. * @return {Boolean}
  263. * @api public
  264. */
  265. req.is = function(type){
  266. var ct = this.get('Content-Type');
  267. if (!ct) return false;
  268. ct = ct.split(';')[0];
  269. if (!~type.indexOf('/')) type = mime.lookup(type);
  270. if (~type.indexOf('*')) {
  271. type = type.split('/');
  272. ct = ct.split('/');
  273. if ('*' == type[0] && type[1] == ct[1]) return true;
  274. if ('*' == type[1] && type[0] == ct[0]) return true;
  275. return false;
  276. }
  277. return !! ~ct.indexOf(type);
  278. };
  279. /**
  280. * Return the protocol string "http" or "https"
  281. * when requested with TLS. When the "trust proxy"
  282. * setting is enabled the "X-Forwarded-Proto" header
  283. * field will be trusted. If you're running behind
  284. * a reverse proxy that supplies https for you this
  285. * may be enabled.
  286. *
  287. * @return {String}
  288. * @api public
  289. */
  290. req.__defineGetter__('protocol', function(){
  291. var trustProxy = this.app.get('trust proxy');
  292. return this.connection.encrypted
  293. ? 'https'
  294. : trustProxy
  295. ? (this.get('X-Forwarded-Proto') || 'http')
  296. : 'http';
  297. });
  298. /**
  299. * Short-hand for:
  300. *
  301. * req.protocol == 'https'
  302. *
  303. * @return {Boolean}
  304. * @api public
  305. */
  306. req.__defineGetter__('secure', function(){
  307. return 'https' == this.protocol;
  308. });
  309. /**
  310. * Return the remote address, or when
  311. * "trust proxy" is `true` return
  312. * the upstream addr.
  313. *
  314. * @return {String}
  315. * @api public
  316. */
  317. req.__defineGetter__('ip', function(){
  318. return this.ips[0] || this.connection.remoteAddress;
  319. });
  320. /**
  321. * When "trust proxy" is `true`, parse
  322. * the "X-Forwarded-For" ip address list.
  323. *
  324. * For example if the value were "client, proxy1, proxy2"
  325. * you would receive the array `["client", "proxy1", "proxy2"]`
  326. * where "proxy2" is the furthest down-stream.
  327. *
  328. * @return {Array}
  329. * @api public
  330. */
  331. req.__defineGetter__('ips', function(){
  332. var trustProxy = this.app.get('trust proxy');
  333. var val = this.get('X-Forwarded-For');
  334. return trustProxy && val
  335. ? val.split(/ *, */)
  336. : [];
  337. });
  338. /**
  339. * Return basic auth credentials.
  340. *
  341. * Examples:
  342. *
  343. * // http://tobi:hello@example.com
  344. * req.auth
  345. * // => { username: 'tobi', password: 'hello' }
  346. *
  347. * @return {Object}
  348. * @api public
  349. */
  350. req.__defineGetter__('auth', function(){
  351. // missing
  352. var auth = this.get('Authorization');
  353. if (!auth) return {};
  354. // malformed
  355. auth = auth.split(' ')[1];
  356. if (!auth) return {};
  357. // credentials
  358. auth = new Buffer(auth, 'base64').toString().split(':');
  359. return { username: auth[0], password: auth[1] };
  360. });
  361. /**
  362. * Return subdomains as an array.
  363. *
  364. * For example "tobi.ferrets.example.com"
  365. * would provide `["ferrets", "tobi"]`.
  366. *
  367. * @return {Array}
  368. * @api public
  369. */
  370. req.__defineGetter__('subdomains', function(){
  371. return this.get('Host')
  372. .split('.')
  373. .slice(0, -2)
  374. .reverse();
  375. });
  376. /**
  377. * Short-hand for `url.parse(req.url).pathname`.
  378. *
  379. * @return {String}
  380. * @api public
  381. */
  382. req.__defineGetter__('path', function(){
  383. return parse(this).pathname;
  384. });
  385. /**
  386. * Parse the "Host" header field hostname.
  387. *
  388. * @return {String}
  389. * @api public
  390. */
  391. req.__defineGetter__('host', function(){
  392. return this.get('Host').split(':')[0];
  393. });
  394. /**
  395. * Check if the request is fresh, aka
  396. * Last-Modified and/or the ETag
  397. * still match.
  398. *
  399. * @return {Boolean}
  400. * @api public
  401. */
  402. req.__defineGetter__('fresh', function(){
  403. var method = this.method;
  404. var s = this.res.statusCode;
  405. // GET or HEAD for weak freshness validation only
  406. if ('GET' != method && 'HEAD' != method) return false;
  407. // 2xx or 304 as per rfc2616 14.26
  408. if ((s >= 200 && s < 300) || 304 == s) {
  409. return fresh(this.headers, this.res._headers);
  410. }
  411. return false;
  412. });
  413. /**
  414. * Check if the request is stale, aka
  415. * "Last-Modified" and / or the "ETag" for the
  416. * resource has changed.
  417. *
  418. * @return {Boolean}
  419. * @api public
  420. */
  421. req.__defineGetter__('stale', function(){
  422. return !this.fresh;
  423. });
  424. /**
  425. * Check if the request was an _XMLHttpRequest_.
  426. *
  427. * @return {Boolean}
  428. * @api public
  429. */
  430. req.__defineGetter__('xhr', function(){
  431. var val = this.get('X-Requested-With') || '';
  432. return 'xmlhttprequest' == val.toLowerCase();
  433. });