2014-11-22 16:59:48 +01:00
|
|
|
'use strict';
|
|
|
|
|
2015-01-21 17:36:59 +01:00
|
|
|
const util = require('util');
|
|
|
|
const Stream = require('stream');
|
2013-04-12 00:00:45 +02:00
|
|
|
|
|
|
|
function readStart(socket) {
|
2013-10-11 00:00:05 +02:00
|
|
|
if (socket && !socket._paused && socket.readable)
|
2013-08-15 20:15:10 +02:00
|
|
|
socket.resume();
|
2013-04-12 00:00:45 +02:00
|
|
|
}
|
|
|
|
exports.readStart = readStart;
|
|
|
|
|
|
|
|
function readStop(socket) {
|
2013-08-15 20:15:10 +02:00
|
|
|
if (socket)
|
|
|
|
socket.pause();
|
2013-04-12 00:00:45 +02:00
|
|
|
}
|
|
|
|
exports.readStop = readStop;
|
|
|
|
|
|
|
|
|
|
|
|
/* Abstract base class for ServerRequest and ClientResponse. */
|
|
|
|
function IncomingMessage(socket) {
|
|
|
|
Stream.Readable.call(this);
|
|
|
|
|
|
|
|
// XXX This implementation is kind of all over the place
|
|
|
|
// When the parser emits body chunks, they go in this list.
|
|
|
|
// _read() pulls them out, and when it finds EOF, it ends.
|
|
|
|
|
|
|
|
this.socket = socket;
|
|
|
|
this.connection = socket;
|
|
|
|
|
2014-08-21 18:05:42 +02:00
|
|
|
this.httpVersionMajor = null;
|
|
|
|
this.httpVersionMinor = null;
|
2013-04-12 00:00:45 +02:00
|
|
|
this.httpVersion = null;
|
|
|
|
this.complete = false;
|
|
|
|
this.headers = {};
|
2013-08-06 03:41:17 +02:00
|
|
|
this.rawHeaders = [];
|
2013-04-12 00:00:45 +02:00
|
|
|
this.trailers = {};
|
2013-08-06 03:41:17 +02:00
|
|
|
this.rawTrailers = [];
|
2013-04-12 00:00:45 +02:00
|
|
|
|
|
|
|
this.readable = true;
|
|
|
|
|
2014-08-21 18:05:42 +02:00
|
|
|
this.upgrade = null;
|
2013-04-12 00:00:45 +02:00
|
|
|
|
|
|
|
// request (server) only
|
|
|
|
this.url = '';
|
|
|
|
this.method = null;
|
|
|
|
|
|
|
|
// response (client) only
|
|
|
|
this.statusCode = null;
|
2013-09-22 16:06:58 +02:00
|
|
|
this.statusMessage = null;
|
2015-05-31 13:25:27 +02:00
|
|
|
this.client = socket;
|
2013-04-12 00:00:45 +02:00
|
|
|
|
|
|
|
// flag for backwards compatibility grossness.
|
|
|
|
this._consuming = false;
|
|
|
|
|
|
|
|
// flag for when we decide that this message cannot possibly be
|
|
|
|
// read by the user, so there's no point continuing to handle it.
|
|
|
|
this._dumped = false;
|
|
|
|
}
|
|
|
|
util.inherits(IncomingMessage, Stream.Readable);
|
|
|
|
|
|
|
|
|
|
|
|
exports.IncomingMessage = IncomingMessage;
|
|
|
|
|
|
|
|
|
|
|
|
IncomingMessage.prototype.setTimeout = function(msecs, callback) {
|
|
|
|
if (callback)
|
|
|
|
this.on('timeout', callback);
|
|
|
|
this.socket.setTimeout(msecs);
|
2015-05-14 04:25:57 +02:00
|
|
|
return this;
|
2013-04-12 00:00:45 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
IncomingMessage.prototype.read = function(n) {
|
|
|
|
this._consuming = true;
|
|
|
|
this.read = Stream.Readable.prototype.read;
|
|
|
|
return this.read(n);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
IncomingMessage.prototype._read = function(n) {
|
|
|
|
// We actually do almost nothing here, because the parserOnBody
|
|
|
|
// function fills up our internal buffer directly. However, we
|
|
|
|
// do need to unpause the underlying socket so that it flows.
|
2014-01-24 13:25:11 +01:00
|
|
|
if (this.socket.readable)
|
2013-04-12 00:00:45 +02:00
|
|
|
readStart(this.socket);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-04-29 14:12:24 +02:00
|
|
|
// It's possible that the socket will be destroyed, and removed from
|
|
|
|
// any messages, before ever calling this. In that case, just skip
|
|
|
|
// it, since something else is destroying this connection anyway.
|
2013-04-12 00:00:45 +02:00
|
|
|
IncomingMessage.prototype.destroy = function(error) {
|
2013-04-22 17:52:42 +02:00
|
|
|
if (this.socket)
|
|
|
|
this.socket.destroy(error);
|
2013-04-12 00:00:45 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-08-06 03:41:17 +02:00
|
|
|
IncomingMessage.prototype._addHeaderLines = function(headers, n) {
|
|
|
|
if (headers && headers.length) {
|
|
|
|
var raw, dest;
|
|
|
|
if (this.complete) {
|
|
|
|
raw = this.rawTrailers;
|
|
|
|
dest = this.trailers;
|
|
|
|
} else {
|
|
|
|
raw = this.rawHeaders;
|
|
|
|
dest = this.headers;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var i = 0; i < n; i += 2) {
|
|
|
|
var k = headers[i];
|
|
|
|
var v = headers[i + 1];
|
2014-09-24 07:14:48 +02:00
|
|
|
raw.push(k);
|
|
|
|
raw.push(v);
|
2013-08-06 03:41:17 +02:00
|
|
|
this._addHeaderLine(k, v, dest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-04-12 00:00:45 +02:00
|
|
|
// Add the given (field, value) pair to the message
|
|
|
|
//
|
|
|
|
// Per RFC2616, section 4.2 it is acceptable to join multiple instances of the
|
|
|
|
// same header with a ', ' if the header in question supports specification of
|
|
|
|
// multiple values this way. If not, we declare the first instance the winner
|
|
|
|
// and drop the second. Extended header fields (those beginning with 'x-') are
|
|
|
|
// always joined.
|
2013-08-06 03:41:17 +02:00
|
|
|
IncomingMessage.prototype._addHeaderLine = function(field, value, dest) {
|
2013-04-12 00:00:45 +02:00
|
|
|
field = field.toLowerCase();
|
|
|
|
switch (field) {
|
|
|
|
// Array headers:
|
|
|
|
case 'set-cookie':
|
2015-01-29 02:05:53 +01:00
|
|
|
if (dest[field] !== undefined) {
|
2013-04-12 00:00:45 +02:00
|
|
|
dest[field].push(value);
|
|
|
|
} else {
|
|
|
|
dest[field] = [value];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2015-04-28 19:46:14 +02:00
|
|
|
/* eslint-disable max-len */
|
2014-01-06 08:59:40 +01:00
|
|
|
// list is taken from:
|
|
|
|
// https://mxr.mozilla.org/mozilla/source/netwerk/protocol/http/src/nsHttpHeaderArray.cpp
|
2015-04-28 19:46:14 +02:00
|
|
|
/* eslint-enable max-len */
|
2014-01-06 08:59:40 +01:00
|
|
|
case 'content-type':
|
|
|
|
case 'content-length':
|
|
|
|
case 'user-agent':
|
|
|
|
case 'referer':
|
|
|
|
case 'host':
|
|
|
|
case 'authorization':
|
|
|
|
case 'proxy-authorization':
|
|
|
|
case 'if-modified-since':
|
|
|
|
case 'if-unmodified-since':
|
|
|
|
case 'from':
|
|
|
|
case 'location':
|
|
|
|
case 'max-forwards':
|
2015-09-27 20:55:47 +02:00
|
|
|
case 'retry-after':
|
|
|
|
case 'etag':
|
|
|
|
case 'last-modified':
|
|
|
|
case 'server':
|
|
|
|
case 'age':
|
|
|
|
case 'expires':
|
2014-01-06 08:59:40 +01:00
|
|
|
// drop duplicates
|
2015-01-29 02:05:53 +01:00
|
|
|
if (dest[field] === undefined)
|
2013-04-12 00:00:45 +02:00
|
|
|
dest[field] = value;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2014-01-06 08:59:40 +01:00
|
|
|
// make comma-separated list
|
2015-04-28 19:46:14 +02:00
|
|
|
if (dest[field] !== undefined) {
|
2014-01-06 08:59:40 +01:00
|
|
|
dest[field] += ', ' + value;
|
2015-04-28 19:46:14 +02:00
|
|
|
} else {
|
2014-01-06 08:59:40 +01:00
|
|
|
dest[field] = value;
|
2013-04-12 00:00:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Call this instead of resume() if we want to just
|
|
|
|
// dump all the data to /dev/null
|
|
|
|
IncomingMessage.prototype._dump = function() {
|
|
|
|
if (!this._dumped) {
|
|
|
|
this._dumped = true;
|
2013-08-15 20:15:10 +02:00
|
|
|
this.resume();
|
2013-04-12 00:00:45 +02:00
|
|
|
}
|
|
|
|
};
|