macgyver 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +20 -0
  5. data/README.md +45 -0
  6. data/Rakefile +1 -0
  7. data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Growl +0 -0
  8. data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/Growl +0 -0
  9. data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/Headers/Growl.h +5 -0
  10. data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/Headers/GrowlApplicationBridge.h +551 -0
  11. data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/Headers/GrowlDefines.h +341 -0
  12. data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/Resources/Info.plist +40 -0
  13. data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/_CodeSignature/CodeResources +34 -0
  14. data/assets/MacGap.app/Contents/Info.plist +48 -0
  15. data/assets/MacGap.app/Contents/MacOS/MacGap +0 -0
  16. data/assets/MacGap.app/Contents/PkgInfo +1 -0
  17. data/assets/MacGap.app/Contents/Resources/_debugger.js +1718 -0
  18. data/assets/MacGap.app/Contents/Resources/_http_agent.js +310 -0
  19. data/assets/MacGap.app/Contents/Resources/_http_client.js +533 -0
  20. data/assets/MacGap.app/Contents/Resources/_http_common.js +222 -0
  21. data/assets/MacGap.app/Contents/Resources/_http_incoming.js +194 -0
  22. data/assets/MacGap.app/Contents/Resources/_http_outgoing.js +597 -0
  23. data/assets/MacGap.app/Contents/Resources/_http_server.js +510 -0
  24. data/assets/MacGap.app/Contents/Resources/_linklist.js +76 -0
  25. data/assets/MacGap.app/Contents/Resources/_stream_duplex.js +69 -0
  26. data/assets/MacGap.app/Contents/Resources/_stream_passthrough.js +41 -0
  27. data/assets/MacGap.app/Contents/Resources/_stream_readable.js +900 -0
  28. data/assets/MacGap.app/Contents/Resources/_stream_transform.js +204 -0
  29. data/assets/MacGap.app/Contents/Resources/_stream_writable.js +456 -0
  30. data/assets/MacGap.app/Contents/Resources/_tls_legacy.js +887 -0
  31. data/assets/MacGap.app/Contents/Resources/_tls_wrap.js +831 -0
  32. data/assets/MacGap.app/Contents/Resources/application.icns +0 -0
  33. data/assets/MacGap.app/Contents/Resources/assert.js +326 -0
  34. data/assets/MacGap.app/Contents/Resources/buffer.js +724 -0
  35. data/assets/MacGap.app/Contents/Resources/child_process.js +1107 -0
  36. data/assets/MacGap.app/Contents/Resources/cluster.js +613 -0
  37. data/assets/MacGap.app/Contents/Resources/console.js +108 -0
  38. data/assets/MacGap.app/Contents/Resources/constants.js +22 -0
  39. data/assets/MacGap.app/Contents/Resources/crypto.js +691 -0
  40. data/assets/MacGap.app/Contents/Resources/dgram.js +459 -0
  41. data/assets/MacGap.app/Contents/Resources/dns.js +274 -0
  42. data/assets/MacGap.app/Contents/Resources/domain.js +292 -0
  43. data/assets/MacGap.app/Contents/Resources/en.lproj/Credits.rtf +29 -0
  44. data/assets/MacGap.app/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
  45. data/assets/MacGap.app/Contents/Resources/en.lproj/MainMenu.nib +0 -0
  46. data/assets/MacGap.app/Contents/Resources/en.lproj/Window.nib +0 -0
  47. data/assets/MacGap.app/Contents/Resources/events.js +312 -0
  48. data/assets/MacGap.app/Contents/Resources/freelist.js +43 -0
  49. data/assets/MacGap.app/Contents/Resources/fs.js +1732 -0
  50. data/assets/MacGap.app/Contents/Resources/http.js +119 -0
  51. data/assets/MacGap.app/Contents/Resources/https.js +134 -0
  52. data/assets/MacGap.app/Contents/Resources/module.js +529 -0
  53. data/assets/MacGap.app/Contents/Resources/net.js +1378 -0
  54. data/assets/MacGap.app/Contents/Resources/nodelike.js +195 -0
  55. data/assets/MacGap.app/Contents/Resources/os.js +64 -0
  56. data/assets/MacGap.app/Contents/Resources/path.js +517 -0
  57. data/assets/MacGap.app/Contents/Resources/public/index.html +38 -0
  58. data/assets/MacGap.app/Contents/Resources/punycode.js +507 -0
  59. data/assets/MacGap.app/Contents/Resources/querystring.js +206 -0
  60. data/assets/MacGap.app/Contents/Resources/readline.js +1311 -0
  61. data/assets/MacGap.app/Contents/Resources/repl.js +945 -0
  62. data/assets/MacGap.app/Contents/Resources/smalloc.js +90 -0
  63. data/assets/MacGap.app/Contents/Resources/stream.js +127 -0
  64. data/assets/MacGap.app/Contents/Resources/string_decoder.js +189 -0
  65. data/assets/MacGap.app/Contents/Resources/sys.js +24 -0
  66. data/assets/MacGap.app/Contents/Resources/timers.js +568 -0
  67. data/assets/MacGap.app/Contents/Resources/tls.js +220 -0
  68. data/assets/MacGap.app/Contents/Resources/tty.js +129 -0
  69. data/assets/MacGap.app/Contents/Resources/url.js +693 -0
  70. data/assets/MacGap.app/Contents/Resources/util.js +688 -0
  71. data/assets/MacGap.app/Contents/Resources/vm.js +73 -0
  72. data/assets/MacGap.app/Contents/Resources/zlib.js +524 -0
  73. data/assets/index.html +38 -0
  74. data/bin/macgyver +104 -0
  75. data/macgyver.gemspec +19 -0
  76. data/test/public/index.html +27 -0
  77. metadata +121 -0
@@ -0,0 +1,222 @@
1
+ // Copyright Joyent, Inc. and other Node contributors.
2
+ //
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:
10
+ //
11
+ // The above copyright notice and this permission notice shall be included
12
+ // in all copies or substantial portions of the Software.
13
+ //
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.
21
+
22
+ var FreeList = require('freelist').FreeList;
23
+ var HTTPParser = process.binding('http_parser').HTTPParser;
24
+
25
+ var incoming = require('_http_incoming');
26
+ var IncomingMessage = incoming.IncomingMessage;
27
+ var readStart = incoming.readStart;
28
+ var readStop = incoming.readStop;
29
+
30
+ var isNumber = require('util').isNumber;
31
+ var debug = require('util').debuglog('http');
32
+ exports.debug = debug;
33
+
34
+ exports.CRLF = '\r\n';
35
+ exports.chunkExpression = /chunk/i;
36
+ exports.continueExpression = /100-continue/i;
37
+ exports.methods = HTTPParser.methods;
38
+
39
+ var kOnHeaders = HTTPParser.kOnHeaders | 0;
40
+ var kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0;
41
+ var kOnBody = HTTPParser.kOnBody | 0;
42
+ var kOnMessageComplete = HTTPParser.kOnMessageComplete | 0;
43
+
44
+ // Only called in the slow case where slow means
45
+ // that the request headers were either fragmented
46
+ // across multiple TCP packets or too large to be
47
+ // processed in a single run. This method is also
48
+ // called to process trailing HTTP headers.
49
+ function parserOnHeaders(headers, url) {
50
+ // Once we exceeded headers limit - stop collecting them
51
+ if (this.maxHeaderPairs <= 0 ||
52
+ this._headers.length < this.maxHeaderPairs) {
53
+ this._headers = this._headers.concat(headers);
54
+ }
55
+ this._url += url;
56
+ }
57
+
58
+ // info.headers and info.url are set only if .onHeaders()
59
+ // has not been called for this request.
60
+ //
61
+ // info.url is not set for response parsers but that's not
62
+ // applicable here since all our parsers are request parsers.
63
+ function parserOnHeadersComplete(info) {
64
+ debug('parserOnHeadersComplete', info);
65
+ var parser = this;
66
+ var headers = info.headers;
67
+ var url = info.url;
68
+
69
+ if (!headers) {
70
+ headers = parser._headers;
71
+ parser._headers = [];
72
+ }
73
+
74
+ if (!url) {
75
+ url = parser._url;
76
+ parser._url = '';
77
+ }
78
+
79
+ parser.incoming = new IncomingMessage(parser.socket);
80
+ parser.incoming.httpVersionMajor = info.versionMajor;
81
+ parser.incoming.httpVersionMinor = info.versionMinor;
82
+ parser.incoming.httpVersion = info.versionMajor + '.' + info.versionMinor;
83
+ parser.incoming.url = url;
84
+
85
+ var n = headers.length;
86
+
87
+ // If parser.maxHeaderPairs <= 0 - assume that there're no limit
88
+ if (parser.maxHeaderPairs > 0) {
89
+ n = Math.min(n, parser.maxHeaderPairs);
90
+ }
91
+
92
+ parser.incoming._addHeaderLines(headers, n);
93
+
94
+ if (isNumber(info.method)) {
95
+ // server only
96
+ parser.incoming.method = HTTPParser.methods[info.method];
97
+ } else {
98
+ // client only
99
+ parser.incoming.statusCode = info.statusCode;
100
+ parser.incoming.statusMessage = info.statusMessage;
101
+ }
102
+
103
+ parser.incoming.upgrade = info.upgrade;
104
+
105
+ var skipBody = false; // response to HEAD or CONNECT
106
+
107
+ if (!info.upgrade) {
108
+ // For upgraded connections and CONNECT method request,
109
+ // we'll emit this after parser.execute
110
+ // so that we can capture the first part of the new protocol
111
+ skipBody = parser.onIncoming(parser.incoming, info.shouldKeepAlive);
112
+ }
113
+
114
+ return skipBody;
115
+ }
116
+
117
+ // XXX This is a mess.
118
+ // TODO: http.Parser should be a Writable emits request/response events.
119
+ function parserOnBody(b, start, len) {
120
+ var parser = this;
121
+ var stream = parser.incoming;
122
+
123
+ // if the stream has already been removed, then drop it.
124
+ if (!stream)
125
+ return;
126
+
127
+ var socket = stream.socket;
128
+
129
+ // pretend this was the result of a stream._read call.
130
+ if (len > 0 && !stream._dumped) {
131
+ var slice = b.slice(start, start + len);
132
+ var ret = stream.push(slice);
133
+ if (!ret)
134
+ readStop(socket);
135
+ }
136
+ }
137
+
138
+ function parserOnMessageComplete() {
139
+ var parser = this;
140
+ var stream = parser.incoming;
141
+
142
+ if (stream) {
143
+ stream.complete = true;
144
+ // Emit any trailing headers.
145
+ var headers = parser._headers;
146
+ if (headers) {
147
+ parser.incoming._addHeaderLines(headers, headers.length);
148
+ parser._headers = [];
149
+ parser._url = '';
150
+ }
151
+
152
+ if (!stream.upgrade)
153
+ // For upgraded connections, also emit this after parser.execute
154
+ stream.push(null);
155
+ }
156
+
157
+ if (stream && !parser.incoming._pendings.length) {
158
+ // For emit end event
159
+ stream.push(null);
160
+ }
161
+
162
+ // force to read the next incoming message
163
+ readStart(parser.socket);
164
+ }
165
+
166
+
167
+ var parsers = new FreeList('parsers', 1000, function() {
168
+ var parser = new HTTPParser(HTTPParser.REQUEST);
169
+
170
+ parser._headers = [];
171
+ parser._url = '';
172
+
173
+ // Only called in the slow case where slow means
174
+ // that the request headers were either fragmented
175
+ // across multiple TCP packets or too large to be
176
+ // processed in a single run. This method is also
177
+ // called to process trailing HTTP headers.
178
+ parser[kOnHeaders] = parserOnHeaders;
179
+ parser[kOnHeadersComplete] = parserOnHeadersComplete;
180
+ parser[kOnBody] = parserOnBody;
181
+ parser[kOnMessageComplete] = parserOnMessageComplete;
182
+
183
+ return parser;
184
+ });
185
+ exports.parsers = parsers;
186
+
187
+
188
+ // Free the parser and also break any links that it
189
+ // might have to any other things.
190
+ // TODO: All parser data should be attached to a
191
+ // single object, so that it can be easily cleaned
192
+ // up by doing `parser.data = {}`, which should
193
+ // be done in FreeList.free. `parsers.free(parser)`
194
+ // should be all that is needed.
195
+ function freeParser(parser, req) {
196
+ if (parser) {
197
+ parser._headers = [];
198
+ parser.onIncoming = null;
199
+ if (parser.socket)
200
+ parser.socket.parser = null;
201
+ parser.socket = null;
202
+ parser.incoming = null;
203
+ parsers.free(parser);
204
+ parser = null;
205
+ }
206
+ if (req) {
207
+ req.parser = null;
208
+ }
209
+ }
210
+ exports.freeParser = freeParser;
211
+
212
+
213
+ function ondrain() {
214
+ if (this._httpMessage) this._httpMessage.emit('drain');
215
+ }
216
+
217
+
218
+ function httpSocketSetup(socket) {
219
+ socket.removeListener('drain', ondrain);
220
+ socket.on('drain', ondrain);
221
+ }
222
+ exports.httpSocketSetup = httpSocketSetup;
@@ -0,0 +1,194 @@
1
+ // Copyright Joyent, Inc. and other Node contributors.
2
+ //
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:
10
+ //
11
+ // The above copyright notice and this permission notice shall be included
12
+ // in all copies or substantial portions of the Software.
13
+ //
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.
21
+
22
+ var util = require('util');
23
+ var Stream = require('stream');
24
+
25
+ function readStart(socket) {
26
+ if (socket && !socket._paused && socket.readable)
27
+ socket.resume();
28
+ }
29
+ exports.readStart = readStart;
30
+
31
+ function readStop(socket) {
32
+ if (socket)
33
+ socket.pause();
34
+ }
35
+ exports.readStop = readStop;
36
+
37
+
38
+ /* Abstract base class for ServerRequest and ClientResponse. */
39
+ function IncomingMessage(socket) {
40
+ Stream.Readable.call(this);
41
+
42
+ // XXX This implementation is kind of all over the place
43
+ // When the parser emits body chunks, they go in this list.
44
+ // _read() pulls them out, and when it finds EOF, it ends.
45
+
46
+ this.socket = socket;
47
+ this.connection = socket;
48
+
49
+ this.httpVersion = null;
50
+ this.complete = false;
51
+ this.headers = {};
52
+ this.rawHeaders = [];
53
+ this.trailers = {};
54
+ this.rawTrailers = [];
55
+
56
+ this.readable = true;
57
+
58
+ this._pendings = [];
59
+ this._pendingIndex = 0;
60
+
61
+ // request (server) only
62
+ this.url = '';
63
+ this.method = null;
64
+
65
+ // response (client) only
66
+ this.statusCode = null;
67
+ this.statusMessage = null;
68
+ this.client = this.socket;
69
+
70
+ // flag for backwards compatibility grossness.
71
+ this._consuming = false;
72
+
73
+ // flag for when we decide that this message cannot possibly be
74
+ // read by the user, so there's no point continuing to handle it.
75
+ this._dumped = false;
76
+ }
77
+ util.inherits(IncomingMessage, Stream.Readable);
78
+
79
+
80
+ exports.IncomingMessage = IncomingMessage;
81
+
82
+
83
+ IncomingMessage.prototype.setTimeout = function(msecs, callback) {
84
+ if (callback)
85
+ this.on('timeout', callback);
86
+ this.socket.setTimeout(msecs);
87
+ };
88
+
89
+
90
+ IncomingMessage.prototype.read = function(n) {
91
+ this._consuming = true;
92
+ this.read = Stream.Readable.prototype.read;
93
+ return this.read(n);
94
+ };
95
+
96
+
97
+ IncomingMessage.prototype._read = function(n) {
98
+ // We actually do almost nothing here, because the parserOnBody
99
+ // function fills up our internal buffer directly. However, we
100
+ // do need to unpause the underlying socket so that it flows.
101
+ if (!this.socket.readable)
102
+ this.push(null);
103
+ else
104
+ readStart(this.socket);
105
+ };
106
+
107
+
108
+ // It's possible that the socket will be destroyed, and removed from
109
+ // any messages, before ever calling this. In that case, just skip
110
+ // it, since something else is destroying this connection anyway.
111
+ IncomingMessage.prototype.destroy = function(error) {
112
+ if (this.socket)
113
+ this.socket.destroy(error);
114
+ };
115
+
116
+
117
+ IncomingMessage.prototype._addHeaderLines = function(headers, n) {
118
+ if (headers && headers.length) {
119
+ var raw, dest;
120
+ if (this.complete) {
121
+ raw = this.rawTrailers;
122
+ dest = this.trailers;
123
+ } else {
124
+ raw = this.rawHeaders;
125
+ dest = this.headers;
126
+ }
127
+ raw.push.apply(raw, headers);
128
+
129
+ for (var i = 0; i < n; i += 2) {
130
+ var k = headers[i];
131
+ var v = headers[i + 1];
132
+ this._addHeaderLine(k, v, dest);
133
+ }
134
+ }
135
+ };
136
+
137
+
138
+ // Add the given (field, value) pair to the message
139
+ //
140
+ // Per RFC2616, section 4.2 it is acceptable to join multiple instances of the
141
+ // same header with a ', ' if the header in question supports specification of
142
+ // multiple values this way. If not, we declare the first instance the winner
143
+ // and drop the second. Extended header fields (those beginning with 'x-') are
144
+ // always joined.
145
+ IncomingMessage.prototype._addHeaderLine = function(field, value, dest) {
146
+ field = field.toLowerCase();
147
+ switch (field) {
148
+ // Array headers:
149
+ case 'set-cookie':
150
+ if (!util.isUndefined(dest[field])) {
151
+ dest[field].push(value);
152
+ } else {
153
+ dest[field] = [value];
154
+ }
155
+ break;
156
+
157
+ // list is taken from:
158
+ // https://mxr.mozilla.org/mozilla/source/netwerk/protocol/http/src/nsHttpHeaderArray.cpp
159
+ case 'content-type':
160
+ case 'content-length':
161
+ case 'user-agent':
162
+ case 'referer':
163
+ case 'host':
164
+ case 'authorization':
165
+ case 'proxy-authorization':
166
+ case 'if-modified-since':
167
+ case 'if-unmodified-since':
168
+ case 'from':
169
+ case 'location':
170
+ case 'max-forwards':
171
+ // drop duplicates
172
+ if (util.isUndefined(dest[field]))
173
+ dest[field] = value;
174
+ break;
175
+
176
+ default:
177
+ // make comma-separated list
178
+ if (!util.isUndefined(dest[field]))
179
+ dest[field] += ', ' + value;
180
+ else {
181
+ dest[field] = value;
182
+ }
183
+ }
184
+ };
185
+
186
+
187
+ // Call this instead of resume() if we want to just
188
+ // dump all the data to /dev/null
189
+ IncomingMessage.prototype._dump = function() {
190
+ if (!this._dumped) {
191
+ this._dumped = true;
192
+ this.resume();
193
+ }
194
+ };
@@ -0,0 +1,597 @@
1
+ // Copyright Joyent, Inc. and other Node contributors.
2
+ //
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:
10
+ //
11
+ // The above copyright notice and this permission notice shall be included
12
+ // in all copies or substantial portions of the Software.
13
+ //
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.
21
+
22
+ var assert = require('assert').ok;
23
+ var Stream = require('stream');
24
+ var timers = require('timers');
25
+ var util = require('util');
26
+
27
+ var common = require('_http_common');
28
+
29
+ var CRLF = common.CRLF;
30
+ var chunkExpression = common.chunkExpression;
31
+ var debug = common.debug;
32
+
33
+
34
+ var connectionExpression = /Connection/i;
35
+ var transferEncodingExpression = /Transfer-Encoding/i;
36
+ var closeExpression = /close/i;
37
+ var contentLengthExpression = /Content-Length/i;
38
+ var dateExpression = /Date/i;
39
+ var expectExpression = /Expect/i;
40
+
41
+ var automaticHeaders = {
42
+ connection: true,
43
+ 'content-length': true,
44
+ 'transfer-encoding': true,
45
+ date: true
46
+ };
47
+
48
+
49
+ var dateCache;
50
+ function utcDate() {
51
+ if (!dateCache) {
52
+ var d = new Date();
53
+ dateCache = d.toUTCString();
54
+ timers.enroll(utcDate, 1000 - d.getMilliseconds());
55
+ timers._unrefActive(utcDate);
56
+ }
57
+ return dateCache;
58
+ }
59
+ utcDate._onTimeout = function() {
60
+ dateCache = undefined;
61
+ };
62
+
63
+
64
+ function OutgoingMessage() {
65
+ Stream.call(this);
66
+
67
+ this.output = [];
68
+ this.outputEncodings = [];
69
+ this.outputCallbacks = [];
70
+
71
+ this.writable = true;
72
+
73
+ this._last = false;
74
+ this.chunkedEncoding = false;
75
+ this.shouldKeepAlive = true;
76
+ this.useChunkedEncodingByDefault = true;
77
+ this.sendDate = false;
78
+ this._removedHeader = {};
79
+
80
+ this._hasBody = true;
81
+ this._trailer = '';
82
+
83
+ this.finished = false;
84
+ this._hangupClose = false;
85
+
86
+ this.socket = null;
87
+ this.connection = null;
88
+ }
89
+ util.inherits(OutgoingMessage, Stream);
90
+
91
+
92
+ exports.OutgoingMessage = OutgoingMessage;
93
+
94
+
95
+ OutgoingMessage.prototype.setTimeout = function(msecs, callback) {
96
+ if (callback)
97
+ this.on('timeout', callback);
98
+ if (!this.socket) {
99
+ this.once('socket', function(socket) {
100
+ socket.setTimeout(msecs);
101
+ });
102
+ } else
103
+ this.socket.setTimeout(msecs);
104
+ };
105
+
106
+
107
+ // It's possible that the socket will be destroyed, and removed from
108
+ // any messages, before ever calling this. In that case, just skip
109
+ // it, since something else is destroying this connection anyway.
110
+ OutgoingMessage.prototype.destroy = function(error) {
111
+ if (this.socket)
112
+ this.socket.destroy(error);
113
+ else
114
+ this.once('socket', function(socket) {
115
+ socket.destroy(error);
116
+ });
117
+ };
118
+
119
+
120
+ // This abstract either writing directly to the socket or buffering it.
121
+ OutgoingMessage.prototype._send = function(data, encoding, callback) {
122
+ // This is a shameful hack to get the headers and first body chunk onto
123
+ // the same packet. Future versions of Node are going to take care of
124
+ // this at a lower level and in a more general way.
125
+ if (!this._headerSent) {
126
+ if (util.isString(data) &&
127
+ encoding !== 'hex' &&
128
+ encoding !== 'base64') {
129
+ data = this._header + data;
130
+ } else {
131
+ this.output.unshift(this._header);
132
+ this.outputEncodings.unshift('binary');
133
+ this.outputCallbacks.unshift(null);
134
+ }
135
+ this._headerSent = true;
136
+ }
137
+ return this._writeRaw(data, encoding, callback);
138
+ };
139
+
140
+
141
+ OutgoingMessage.prototype._writeRaw = function(data, encoding, callback) {
142
+ if (util.isFunction(encoding)) {
143
+ callback = encoding;
144
+ encoding = null;
145
+ }
146
+
147
+ if (data.length === 0) {
148
+ if (util.isFunction(callback))
149
+ process.nextTick(callback);
150
+ return true;
151
+ }
152
+
153
+ if (this.connection &&
154
+ this.connection._httpMessage === this &&
155
+ this.connection.writable &&
156
+ !this.connection.destroyed) {
157
+ // There might be pending data in the this.output buffer.
158
+ while (this.output.length) {
159
+ if (!this.connection.writable) {
160
+ this._buffer(data, encoding, callback);
161
+ return false;
162
+ }
163
+ var c = this.output.shift();
164
+ var e = this.outputEncodings.shift();
165
+ var cb = this.outputCallbacks.shift();
166
+ this.connection.write(c, e, cb);
167
+ }
168
+
169
+ // Directly write to socket.
170
+ return this.connection.write(data, encoding, callback);
171
+ } else if (this.connection && this.connection.destroyed) {
172
+ // The socket was destroyed. If we're still trying to write to it,
173
+ // then we haven't gotten the 'close' event yet.
174
+ return false;
175
+ } else {
176
+ // buffer, as long as we're not destroyed.
177
+ this._buffer(data, encoding, callback);
178
+ return false;
179
+ }
180
+ };
181
+
182
+
183
+ OutgoingMessage.prototype._buffer = function(data, encoding, callback) {
184
+ this.output.push(data);
185
+ this.outputEncodings.push(encoding);
186
+ this.outputCallbacks.push(callback);
187
+ return false;
188
+ };
189
+
190
+
191
+ OutgoingMessage.prototype._storeHeader = function(firstLine, headers) {
192
+ // firstLine in the case of request is: 'GET /index.html HTTP/1.1\r\n'
193
+ // in the case of response it is: 'HTTP/1.1 200 OK\r\n'
194
+ var state = {
195
+ sentConnectionHeader: false,
196
+ sentContentLengthHeader: false,
197
+ sentTransferEncodingHeader: false,
198
+ sentDateHeader: false,
199
+ sentExpect: false,
200
+ messageHeader: firstLine
201
+ };
202
+
203
+ var field, value;
204
+
205
+ if (headers) {
206
+ var keys = Object.keys(headers);
207
+ var isArray = util.isArray(headers);
208
+ var field, value;
209
+
210
+ for (var i = 0, l = keys.length; i < l; i++) {
211
+ var key = keys[i];
212
+ if (isArray) {
213
+ field = headers[key][0];
214
+ value = headers[key][1];
215
+ } else {
216
+ field = key;
217
+ value = headers[key];
218
+ }
219
+
220
+ if (util.isArray(value)) {
221
+ for (var j = 0; j < value.length; j++) {
222
+ storeHeader(this, state, field, value[j]);
223
+ }
224
+ } else {
225
+ storeHeader(this, state, field, value);
226
+ }
227
+ }
228
+ }
229
+
230
+ // Date header
231
+ if (this.sendDate == true && state.sentDateHeader == false) {
232
+ state.messageHeader += 'Date: ' + utcDate() + CRLF;
233
+ }
234
+
235
+ // Force the connection to close when the response is a 204 No Content or
236
+ // a 304 Not Modified and the user has set a "Transfer-Encoding: chunked"
237
+ // header.
238
+ //
239
+ // RFC 2616 mandates that 204 and 304 responses MUST NOT have a body but
240
+ // node.js used to send out a zero chunk anyway to accommodate clients
241
+ // that don't have special handling for those responses.
242
+ //
243
+ // It was pointed out that this might confuse reverse proxies to the point
244
+ // of creating security liabilities, so suppress the zero chunk and force
245
+ // the connection to close.
246
+ var statusCode = this.statusCode;
247
+ if ((statusCode == 204 || statusCode === 304) &&
248
+ this.chunkedEncoding === true) {
249
+ debug(statusCode + ' response should not use chunked encoding,' +
250
+ ' closing connection.');
251
+ this.chunkedEncoding = false;
252
+ this.shouldKeepAlive = false;
253
+ }
254
+
255
+ // keep-alive logic
256
+ if (this._removedHeader.connection) {
257
+ this._last = true;
258
+ this.shouldKeepAlive = false;
259
+ } else if (state.sentConnectionHeader === false) {
260
+ var shouldSendKeepAlive = this.shouldKeepAlive &&
261
+ (state.sentContentLengthHeader ||
262
+ this.useChunkedEncodingByDefault ||
263
+ this.agent);
264
+ if (shouldSendKeepAlive) {
265
+ state.messageHeader += 'Connection: keep-alive\r\n';
266
+ } else {
267
+ this._last = true;
268
+ state.messageHeader += 'Connection: close\r\n';
269
+ }
270
+ }
271
+
272
+ if (state.sentContentLengthHeader == false &&
273
+ state.sentTransferEncodingHeader == false) {
274
+ if (this._hasBody && !this._removedHeader['transfer-encoding']) {
275
+ if (this.useChunkedEncodingByDefault) {
276
+ state.messageHeader += 'Transfer-Encoding: chunked\r\n';
277
+ this.chunkedEncoding = true;
278
+ } else {
279
+ this._last = true;
280
+ }
281
+ } else {
282
+ // Make sure we don't end the 0\r\n\r\n at the end of the message.
283
+ this.chunkedEncoding = false;
284
+ }
285
+ }
286
+
287
+ this._header = state.messageHeader + CRLF;
288
+ this._headerSent = false;
289
+
290
+ // wait until the first body chunk, or close(), is sent to flush,
291
+ // UNLESS we're sending Expect: 100-continue.
292
+ if (state.sentExpect) this._send('');
293
+ };
294
+
295
+ function storeHeader(self, state, field, value) {
296
+ // Protect against response splitting. The if statement is there to
297
+ // minimize the performance impact in the common case.
298
+ if (/[\r\n]/.test(value))
299
+ value = value.replace(/[\r\n]+[ \t]*/g, '');
300
+
301
+ state.messageHeader += field + ': ' + value + CRLF;
302
+
303
+ if (connectionExpression.test(field)) {
304
+ state.sentConnectionHeader = true;
305
+ if (closeExpression.test(value)) {
306
+ self._last = true;
307
+ } else {
308
+ self.shouldKeepAlive = true;
309
+ }
310
+
311
+ } else if (transferEncodingExpression.test(field)) {
312
+ state.sentTransferEncodingHeader = true;
313
+ if (chunkExpression.test(value)) self.chunkedEncoding = true;
314
+
315
+ } else if (contentLengthExpression.test(field)) {
316
+ state.sentContentLengthHeader = true;
317
+ } else if (dateExpression.test(field)) {
318
+ state.sentDateHeader = true;
319
+ } else if (expectExpression.test(field)) {
320
+ state.sentExpect = true;
321
+ }
322
+ }
323
+
324
+
325
+ OutgoingMessage.prototype.setHeader = function(name, value) {
326
+ if (arguments.length < 2) {
327
+ throw new Error('`name` and `value` are required for setHeader().');
328
+ }
329
+
330
+ if (this._header) {
331
+ throw new Error('Can\'t set headers after they are sent.');
332
+ }
333
+
334
+ var key = name.toLowerCase();
335
+ this._headers = this._headers || {};
336
+ this._headerNames = this._headerNames || {};
337
+ this._headers[key] = value;
338
+ this._headerNames[key] = name;
339
+
340
+ if (automaticHeaders[key]) {
341
+ this._removedHeader[key] = false;
342
+ }
343
+ };
344
+
345
+
346
+ OutgoingMessage.prototype.getHeader = function(name) {
347
+ if (arguments.length < 1) {
348
+ throw new Error('`name` is required for getHeader().');
349
+ }
350
+
351
+ if (!this._headers) return;
352
+
353
+ var key = name.toLowerCase();
354
+ return this._headers[key];
355
+ };
356
+
357
+
358
+ OutgoingMessage.prototype.removeHeader = function(name) {
359
+ if (arguments.length < 1) {
360
+ throw new Error('`name` is required for removeHeader().');
361
+ }
362
+
363
+ if (this._header) {
364
+ throw new Error('Can\'t remove headers after they are sent.');
365
+ }
366
+
367
+ var key = name.toLowerCase();
368
+
369
+ if (key === 'date')
370
+ this.sendDate = false;
371
+ else if (automaticHeaders[key])
372
+ this._removedHeader[key] = true;
373
+
374
+ if (this._headers) {
375
+ delete this._headers[key];
376
+ delete this._headerNames[key];
377
+ }
378
+ };
379
+
380
+
381
+ OutgoingMessage.prototype._renderHeaders = function() {
382
+ if (this._header) {
383
+ throw new Error('Can\'t render headers after they are sent to the client.');
384
+ }
385
+
386
+ if (!this._headers) return {};
387
+
388
+ var headers = {};
389
+ var keys = Object.keys(this._headers);
390
+ for (var i = 0, l = keys.length; i < l; i++) {
391
+ var key = keys[i];
392
+ headers[this._headerNames[key]] = this._headers[key];
393
+ }
394
+ return headers;
395
+ };
396
+
397
+
398
+ Object.defineProperty(OutgoingMessage.prototype, 'headersSent', {
399
+ configurable: true,
400
+ enumerable: true,
401
+ get: function() { return !!this._header; }
402
+ });
403
+
404
+
405
+ OutgoingMessage.prototype.write = function(chunk, encoding, callback) {
406
+ if (!this._header) {
407
+ this._implicitHeader();
408
+ }
409
+
410
+ if (!this._hasBody) {
411
+ debug('This type of response MUST NOT have a body. ' +
412
+ 'Ignoring write() calls.');
413
+ return true;
414
+ }
415
+
416
+ if (!util.isString(chunk) && !util.isBuffer(chunk)) {
417
+ throw new TypeError('first argument must be a string or Buffer');
418
+ }
419
+
420
+
421
+ // If we get an empty string or buffer, then just do nothing, and
422
+ // signal the user to keep writing.
423
+ if (chunk.length === 0) return true;
424
+
425
+ var len, ret;
426
+ if (this.chunkedEncoding) {
427
+ if (util.isString(chunk) &&
428
+ encoding !== 'hex' &&
429
+ encoding !== 'base64' &&
430
+ encoding !== 'binary') {
431
+ len = Buffer.byteLength(chunk, encoding);
432
+ chunk = len.toString(16) + CRLF + chunk + CRLF;
433
+ ret = this._send(chunk, encoding, callback);
434
+ } else {
435
+ // buffer, or a non-toString-friendly encoding
436
+ if (util.isString(chunk))
437
+ len = Buffer.byteLength(chunk, encoding);
438
+ else
439
+ len = chunk.length;
440
+
441
+ if (this.connection && !this.connection.corked) {
442
+ this.connection.cork();
443
+ var conn = this.connection;
444
+ process.nextTick(function connectionCork() {
445
+ if (conn)
446
+ conn.uncork();
447
+ });
448
+ }
449
+ this._send(len.toString(16), 'binary', null);
450
+ this._send(crlf_buf, null, null);
451
+ this._send(chunk, encoding, null);
452
+ ret = this._send(crlf_buf, null, callback);
453
+ }
454
+ } else {
455
+ ret = this._send(chunk, encoding, callback);
456
+ }
457
+
458
+ debug('write ret = ' + ret);
459
+ return ret;
460
+ };
461
+
462
+
463
+ OutgoingMessage.prototype.addTrailers = function(headers) {
464
+ this._trailer = '';
465
+ var keys = Object.keys(headers);
466
+ var isArray = util.isArray(headers);
467
+ var field, value;
468
+ for (var i = 0, l = keys.length; i < l; i++) {
469
+ var key = keys[i];
470
+ if (isArray) {
471
+ field = headers[key][0];
472
+ value = headers[key][1];
473
+ } else {
474
+ field = key;
475
+ value = headers[key];
476
+ }
477
+
478
+ this._trailer += field + ': ' + value + CRLF;
479
+ }
480
+ };
481
+
482
+
483
+ var crlf_buf = new Buffer('\r\n');
484
+
485
+
486
+ OutgoingMessage.prototype.end = function(data, encoding, callback) {
487
+ if (util.isFunction(data)) {
488
+ callback = data;
489
+ data = null;
490
+ } else if (util.isFunction(encoding)) {
491
+ callback = encoding;
492
+ encoding = null;
493
+ }
494
+
495
+ if (data && !util.isString(data) && !util.isBuffer(data)) {
496
+ throw new TypeError('first argument must be a string or Buffer');
497
+ }
498
+
499
+ if (this.finished) {
500
+ return false;
501
+ }
502
+
503
+ var self = this;
504
+ function finish() {
505
+ self.emit('finish');
506
+ }
507
+
508
+ if (util.isFunction(callback))
509
+ this.once('finish', callback);
510
+
511
+
512
+ if (!this._header) {
513
+ this._implicitHeader();
514
+ }
515
+
516
+ if (data && !this._hasBody) {
517
+ debug('This type of response MUST NOT have a body. ' +
518
+ 'Ignoring data passed to end().');
519
+ data = null;
520
+ }
521
+
522
+ if (this.connection && data)
523
+ this.connection.cork();
524
+
525
+ var ret;
526
+ if (data) {
527
+ // Normal body write.
528
+ ret = this.write(data, encoding);
529
+ }
530
+
531
+ if (this.chunkedEncoding) {
532
+ ret = this._send('0\r\n' + this._trailer + '\r\n', 'binary', finish);
533
+ } else {
534
+ // Force a flush, HACK.
535
+ ret = this._send('', 'binary', finish);
536
+ }
537
+
538
+ if (this.connection && data)
539
+ this.connection.uncork();
540
+
541
+ this.finished = true;
542
+
543
+ // There is the first message on the outgoing queue, and we've sent
544
+ // everything to the socket.
545
+ debug('outgoing message end.');
546
+ if (this.output.length === 0 && this.connection._httpMessage === this) {
547
+ this._finish();
548
+ }
549
+
550
+ return ret;
551
+ };
552
+
553
+
554
+ OutgoingMessage.prototype._finish = function() {
555
+ assert(this.connection);
556
+ this.emit('prefinish');
557
+ };
558
+
559
+
560
+ // This logic is probably a bit confusing. Let me explain a bit:
561
+ //
562
+ // In both HTTP servers and clients it is possible to queue up several
563
+ // outgoing messages. This is easiest to imagine in the case of a client.
564
+ // Take the following situation:
565
+ //
566
+ // req1 = client.request('GET', '/');
567
+ // req2 = client.request('POST', '/');
568
+ //
569
+ // When the user does
570
+ //
571
+ // req2.write('hello world\n');
572
+ //
573
+ // it's possible that the first request has not been completely flushed to
574
+ // the socket yet. Thus the outgoing messages need to be prepared to queue
575
+ // up data internally before sending it on further to the socket's queue.
576
+ //
577
+ // This function, outgoingFlush(), is called by both the Server and Client
578
+ // to attempt to flush any pending messages out to the socket.
579
+ OutgoingMessage.prototype._flush = function() {
580
+ if (this.socket && this.socket.writable) {
581
+ var ret;
582
+ while (this.output.length) {
583
+ var data = this.output.shift();
584
+ var encoding = this.outputEncodings.shift();
585
+ var cb = this.outputCallbacks.shift();
586
+ ret = this.socket.write(data, encoding, cb);
587
+ }
588
+
589
+ if (this.finished) {
590
+ // This is a queue to the server or client to bring in the next this.
591
+ this._finish();
592
+ } else if (ret) {
593
+ // This is necessary to prevent https from breaking
594
+ this.emit('drain');
595
+ }
596
+ }
597
+ };