UNPKG

3.84 kBJavaScriptView Raw
1
2/*!
3 * Connect
4 * Copyright(c) 2011 TJ Holowaychuk
5 * MIT Licensed
6 */
7
8/**
9 * Module dependencies.
10 */
11
12var cookie = require('cookie');
13var deprecate = require('depd')('connect');
14var http = require('http');
15var merge = require('utils-merge');
16var onHeaders = require('on-headers');
17var utils = require('./utils')
18 , res = http.ServerResponse.prototype
19 , addListener = res.addListener
20 , setHeader = res.setHeader;
21
22// apply only once
23
24if (!res._hasConnectPatch) {
25
26 /**
27 * Provide a public "header sent" flag
28 * until node does.
29 *
30 * @return {Boolean}
31 * @api public
32 */
33
34 Object.defineProperty(res, 'headerSent', {
35 configurable: true,
36 enumerable: true,
37 get: headersSent
38 });
39
40 deprecate.property(res, 'headerSent', 'res.headerSent: use standard res.headersSent');
41
42 if (!('headersSent' in res)) {
43
44 /**
45 * Provide the public "header sent" flag
46 * added in node.js 0.10.
47 *
48 * @return {Boolean}
49 * @api public
50 */
51
52 Object.defineProperty(res, 'headersSent', {
53 configurable: true,
54 enumerable: true,
55 get: headersSent
56 });
57
58 }
59
60 /**
61 * Set cookie `name` to `val`, with the given `options`.
62 *
63 * Options:
64 *
65 * - `maxAge` max-age in milliseconds, converted to `expires`
66 * - `path` defaults to "/"
67 *
68 * @param {String} name
69 * @param {String} val
70 * @param {Object} options
71 * @api public
72 */
73
74 res.cookie = function(name, val, options){
75 options = merge({}, options);
76 if ('maxAge' in options) {
77 options.expires = new Date(Date.now() + options.maxAge);
78 options.maxAge /= 1000;
79 }
80 if (null == options.path) options.path = '/';
81 this.setHeader('Set-Cookie', cookie.serialize(name, String(val), options));
82 };
83
84 /**
85 * Append additional header `field` with value `val`.
86 *
87 * @param {String} field
88 * @param {String} val
89 * @api public
90 */
91
92 res.appendHeader = function appendHeader(field, val){
93 var prev = this.getHeader(field);
94
95 if (!prev) return setHeader.call(this, field, val);
96
97 // concat the new and prev vals
98 val = Array.isArray(prev) ? prev.concat(val)
99 : Array.isArray(val) ? [prev].concat(val)
100 : [prev, val];
101
102 return setHeader.call(this, field, val);
103 };
104
105 /**
106 * Set header `field` to `val`, special-casing
107 * the `Set-Cookie` field for multiple support.
108 *
109 * @param {String} field
110 * @param {String} val
111 * @api public
112 */
113
114 res.setHeader = function(field, val){
115 var key = field.toLowerCase()
116 , prev;
117
118 // special-case Set-Cookie
119 if (key === 'set-cookie') {
120 // detect code doing getHeader -> setHeader
121 if (Array.isArray(val) && val.length > 1) {
122 prev = [].concat(this.getHeader(field) || []);
123 val = unique(prev, val);
124 }
125
126 return this.appendHeader(field, val);
127 }
128
129 // charset
130 if ('content-type' == key && this.charset) {
131 val = utils.setCharset(val, this.charset, true);
132 }
133
134 return setHeader.call(this, field, val);
135 };
136
137 /**
138 * Proxy to emit "header" event.
139 */
140
141 res.on = function(type, listener){
142 if (type === 'header') {
143 deprecate('res.on("header"): use on-headers npm module instead');
144 onHeaders(this, listener);
145 return this;
146 }
147
148 return addListener.apply(this, arguments);
149 };
150
151 res._hasConnectPatch = true;
152}
153
154/**
155 * Determine if headers sent.
156 *
157 * @return {Boolean}
158 * @api private
159 */
160
161function headersSent(){
162 return Boolean(this._header);
163}
164
165/**
166 * Get unique elements in arr that are not in reference.
167 *
168 * @param {array} reference
169 * @param {array} arr
170 * @return {array}
171 * @api private
172 */
173
174function unique(reference, arr){
175 var array = [];
176
177 for (var i = 0; i < arr.length; i++) {
178 if (reference.indexOf(arr[i]) === -1) {
179 array.push(arr[i]);
180 }
181 }
182
183 return array;
184}