doc: improvements to debugger.markdown copy
[platform/upstream/nodejs.git] / lib / _http_incoming.js
1 'use strict';
2
3 const util = require('util');
4 const Stream = require('stream');
5
6 function readStart(socket) {
7   if (socket && !socket._paused && socket.readable)
8     socket.resume();
9 }
10 exports.readStart = readStart;
11
12 function readStop(socket) {
13   if (socket)
14     socket.pause();
15 }
16 exports.readStop = readStop;
17
18
19 /* Abstract base class for ServerRequest and ClientResponse. */
20 function IncomingMessage(socket) {
21   Stream.Readable.call(this);
22
23   // XXX This implementation is kind of all over the place
24   // When the parser emits body chunks, they go in this list.
25   // _read() pulls them out, and when it finds EOF, it ends.
26
27   this.socket = socket;
28   this.connection = socket;
29
30   this.httpVersionMajor = null;
31   this.httpVersionMinor = null;
32   this.httpVersion = null;
33   this.complete = false;
34   this.headers = {};
35   this.rawHeaders = [];
36   this.trailers = {};
37   this.rawTrailers = [];
38
39   this.readable = true;
40
41   this.upgrade = null;
42
43   // request (server) only
44   this.url = '';
45   this.method = null;
46
47   // response (client) only
48   this.statusCode = null;
49   this.statusMessage = null;
50   this.client = socket;
51
52   // flag for backwards compatibility grossness.
53   this._consuming = false;
54
55   // flag for when we decide that this message cannot possibly be
56   // read by the user, so there's no point continuing to handle it.
57   this._dumped = false;
58 }
59 util.inherits(IncomingMessage, Stream.Readable);
60
61
62 exports.IncomingMessage = IncomingMessage;
63
64
65 IncomingMessage.prototype.setTimeout = function(msecs, callback) {
66   if (callback)
67     this.on('timeout', callback);
68   this.socket.setTimeout(msecs);
69   return this;
70 };
71
72
73 IncomingMessage.prototype.read = function(n) {
74   this._consuming = true;
75   this.read = Stream.Readable.prototype.read;
76   return this.read(n);
77 };
78
79
80 IncomingMessage.prototype._read = function(n) {
81   // We actually do almost nothing here, because the parserOnBody
82   // function fills up our internal buffer directly.  However, we
83   // do need to unpause the underlying socket so that it flows.
84   if (this.socket.readable)
85     readStart(this.socket);
86 };
87
88
89 // It's possible that the socket will be destroyed, and removed from
90 // any messages, before ever calling this.  In that case, just skip
91 // it, since something else is destroying this connection anyway.
92 IncomingMessage.prototype.destroy = function(error) {
93   if (this.socket)
94     this.socket.destroy(error);
95 };
96
97
98 IncomingMessage.prototype._addHeaderLines = function(headers, n) {
99   if (headers && headers.length) {
100     var raw, dest;
101     if (this.complete) {
102       raw = this.rawTrailers;
103       dest = this.trailers;
104     } else {
105       raw = this.rawHeaders;
106       dest = this.headers;
107     }
108
109     for (var i = 0; i < n; i += 2) {
110       var k = headers[i];
111       var v = headers[i + 1];
112       raw.push(k);
113       raw.push(v);
114       this._addHeaderLine(k, v, dest);
115     }
116   }
117 };
118
119
120 // Add the given (field, value) pair to the message
121 //
122 // Per RFC2616, section 4.2 it is acceptable to join multiple instances of the
123 // same header with a ', ' if the header in question supports specification of
124 // multiple values this way. If not, we declare the first instance the winner
125 // and drop the second. Extended header fields (those beginning with 'x-') are
126 // always joined.
127 IncomingMessage.prototype._addHeaderLine = function(field, value, dest) {
128   field = field.toLowerCase();
129   switch (field) {
130     // Array headers:
131     case 'set-cookie':
132       if (dest[field] !== undefined) {
133         dest[field].push(value);
134       } else {
135         dest[field] = [value];
136       }
137       break;
138
139     /* eslint-disable max-len */
140     // list is taken from:
141     // https://mxr.mozilla.org/mozilla/source/netwerk/protocol/http/src/nsHttpHeaderArray.cpp
142     /* eslint-enable max-len */
143     case 'content-type':
144     case 'content-length':
145     case 'user-agent':
146     case 'referer':
147     case 'host':
148     case 'authorization':
149     case 'proxy-authorization':
150     case 'if-modified-since':
151     case 'if-unmodified-since':
152     case 'from':
153     case 'location':
154     case 'max-forwards':
155       // drop duplicates
156       if (dest[field] === undefined)
157         dest[field] = value;
158       break;
159
160     default:
161       // make comma-separated list
162       if (dest[field] !== undefined) {
163         dest[field] += ', ' + value;
164       } else {
165         dest[field] = value;
166       }
167   }
168 };
169
170
171 // Call this instead of resume() if we want to just
172 // dump all the data to /dev/null
173 IncomingMessage.prototype._dump = function() {
174   if (!this._dumped) {
175     this._dumped = true;
176     this.resume();
177   }
178 };