1 // Copyright Joyent, Inc. and other Node contributors.
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
24 var util = require('util');
25 var Stream = require('stream');
27 function readStart(socket) {
28 if (socket && !socket._paused && socket.readable)
31 exports.readStart = readStart;
33 function readStop(socket) {
37 exports.readStop = readStop;
40 /* Abstract base class for ServerRequest and ClientResponse. */
41 function IncomingMessage(socket) {
42 Stream.Readable.call(this);
44 // XXX This implementation is kind of all over the place
45 // When the parser emits body chunks, they go in this list.
46 // _read() pulls them out, and when it finds EOF, it ends.
49 this.connection = socket;
51 this.httpVersionMajor = null;
52 this.httpVersionMinor = null;
53 this.httpVersion = null;
54 this.complete = false;
58 this.rawTrailers = [];
63 this._pendingIndex = 0;
66 // request (server) only
70 // response (client) only
71 this.statusCode = null;
72 this.statusMessage = null;
73 this.client = this.socket;
75 // flag for backwards compatibility grossness.
76 this._consuming = false;
78 // flag for when we decide that this message cannot possibly be
79 // read by the user, so there's no point continuing to handle it.
82 util.inherits(IncomingMessage, Stream.Readable);
85 exports.IncomingMessage = IncomingMessage;
88 IncomingMessage.prototype.setTimeout = function(msecs, callback) {
90 this.on('timeout', callback);
91 this.socket.setTimeout(msecs);
95 IncomingMessage.prototype.read = function(n) {
96 this._consuming = true;
97 this.read = Stream.Readable.prototype.read;
102 IncomingMessage.prototype._read = function(n) {
103 // We actually do almost nothing here, because the parserOnBody
104 // function fills up our internal buffer directly. However, we
105 // do need to unpause the underlying socket so that it flows.
106 if (this.socket.readable)
107 readStart(this.socket);
111 // It's possible that the socket will be destroyed, and removed from
112 // any messages, before ever calling this. In that case, just skip
113 // it, since something else is destroying this connection anyway.
114 IncomingMessage.prototype.destroy = function(error) {
116 this.socket.destroy(error);
120 IncomingMessage.prototype._addHeaderLines = function(headers, n) {
121 if (headers && headers.length) {
124 raw = this.rawTrailers;
125 dest = this.trailers;
127 raw = this.rawHeaders;
131 for (var i = 0; i < n; i += 2) {
133 var v = headers[i + 1];
136 this._addHeaderLine(k, v, dest);
142 // Add the given (field, value) pair to the message
144 // Per RFC2616, section 4.2 it is acceptable to join multiple instances of the
145 // same header with a ', ' if the header in question supports specification of
146 // multiple values this way. If not, we declare the first instance the winner
147 // and drop the second. Extended header fields (those beginning with 'x-') are
149 IncomingMessage.prototype._addHeaderLine = function(field, value, dest) {
150 field = field.toLowerCase();
154 if (!util.isUndefined(dest[field])) {
155 dest[field].push(value);
157 dest[field] = [value];
161 // list is taken from:
162 // https://mxr.mozilla.org/mozilla/source/netwerk/protocol/http/src/nsHttpHeaderArray.cpp
164 case 'content-length':
168 case 'authorization':
169 case 'proxy-authorization':
170 case 'if-modified-since':
171 case 'if-unmodified-since':
176 if (util.isUndefined(dest[field]))
181 // make comma-separated list
182 if (!util.isUndefined(dest[field]))
183 dest[field] += ', ' + value;
191 // Call this instead of resume() if we want to just
192 // dump all the data to /dev/null
193 IncomingMessage.prototype._dump = function() {