4 * Copyright(c) 2011 TJ Holowaychuk
12 var cookie = require('cookie');
13 var deprecate = require('depd')('connect');
14 var http = require('http');
15 var merge = require('utils-merge');
16 var onHeaders = require('on-headers');
17 var utils = require('./utils')
18 , res = http.ServerResponse.prototype
19 , addListener = res.addListener
20 , setHeader = res.setHeader;
24 if (!res._hasConnectPatch) {
27 * Provide a public "header sent" flag
34 Object.defineProperty(res, 'headerSent', {
40 deprecate.property(res, 'headerSent', 'res.headerSent: use standard res.headersSent');
42 if (!('headersSent' in res)) {
45 * Provide the public "header sent" flag
46 * added in node.js 0.10.
52 Object.defineProperty(res, 'headersSent', {
61 * Set cookie `name` to `val`, with the given `options`.
65 * - `maxAge` max-age in milliseconds, converted to `expires`
66 * - `path` defaults to "/"
68 * @param {String} name
70 * @param {Object} options
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;
80 if (null == options.path) options.path = '/';
81 this.setHeader('Set-Cookie', cookie.serialize(name, String(val), options));
85 * Append additional header `field` with value `val`.
87 * @param {String} field
92 res.appendHeader = function appendHeader(field, val){
93 var prev = this.getHeader(field);
95 if (!prev) return setHeader.call(this, field, val);
97 // concat the new and prev vals
98 val = Array.isArray(prev) ? prev.concat(val)
99 : Array.isArray(val) ? [prev].concat(val)
102 return setHeader.call(this, field, val);
106 * Set header `field` to `val`, special-casing
107 * the `Set-Cookie` field for multiple support.
109 * @param {String} field
110 * @param {String} val
114 res.setHeader = function(field, val){
115 var key = field.toLowerCase()
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);
126 return this.appendHeader(field, val);
130 if ('content-type' == key && this.charset) {
131 val = utils.setCharset(val, this.charset, true);
134 return setHeader.call(this, field, val);
138 * Proxy to emit "header" event.
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);
148 return addListener.apply(this, arguments);
151 res._hasConnectPatch = true;
155 * Determine if headers sent.
161 function headersSent(){
162 return Boolean(this._header);
166 * Get unique elements in arr that are not in reference.
168 * @param {array} reference
174 function unique(reference, arr){
177 for (var i = 0; i < arr.length; i++) {
178 if (reference.indexOf(arr[i]) === -1) {