/lib/_http_incoming.js
JavaScript | 198 lines | 115 code | 34 blank | 49 comment | 19 complexity | e740b1936914a0d89c74dbd31ab506a9 MD5 | raw file
Possible License(s): 0BSD, Apache-2.0, MPL-2.0-no-copyleft-exception, JSON, WTFPL, CC-BY-SA-3.0, Unlicense, ISC, BSD-3-Clause, MIT, AGPL-3.0
- // Copyright Joyent, Inc. and other Node contributors.
- //
- // Permission is hereby granted, free of charge, to any person obtaining a
- // copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to permit
- // persons to whom the Software is furnished to do so, subject to the
- // following conditions:
- //
- // The above copyright notice and this permission notice shall be included
- // in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
- // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
- // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
- // USE OR OTHER DEALINGS IN THE SOFTWARE.
- 'use strict';
- var util = require('util');
- var Stream = require('stream');
- function readStart(socket) {
- if (socket && !socket._paused && socket.readable)
- socket.resume();
- }
- exports.readStart = readStart;
- function readStop(socket) {
- if (socket)
- socket.pause();
- }
- 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;
- this.httpVersionMajor = null;
- this.httpVersionMinor = null;
- this.httpVersion = null;
- this.complete = false;
- this.headers = {};
- this.rawHeaders = [];
- this.trailers = {};
- this.rawTrailers = [];
- this.readable = true;
- this._pendings = [];
- this._pendingIndex = 0;
- this.upgrade = null;
- // request (server) only
- this.url = '';
- this.method = null;
- // response (client) only
- this.statusCode = null;
- this.statusMessage = null;
- this.client = this.socket;
- // 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);
- };
- 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.
- if (this.socket.readable)
- readStart(this.socket);
- };
- // 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.
- IncomingMessage.prototype.destroy = function(error) {
- if (this.socket)
- this.socket.destroy(error);
- };
- 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];
- raw.push(k);
- raw.push(v);
- this._addHeaderLine(k, v, dest);
- }
- }
- };
- // 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.
- IncomingMessage.prototype._addHeaderLine = function(field, value, dest) {
- field = field.toLowerCase();
- switch (field) {
- // Array headers:
- case 'set-cookie':
- if (!util.isUndefined(dest[field])) {
- dest[field].push(value);
- } else {
- dest[field] = [value];
- }
- break;
- // list is taken from:
- // https://mxr.mozilla.org/mozilla/source/netwerk/protocol/http/src/nsHttpHeaderArray.cpp
- 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':
- // drop duplicates
- if (util.isUndefined(dest[field]))
- dest[field] = value;
- break;
- default:
- // make comma-separated list
- if (!util.isUndefined(dest[field]))
- dest[field] += ', ' + value;
- else {
- dest[field] = value;
- }
- }
- };
- // 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;
- this.resume();
- }
- };