macgyver 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,510 @@
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 net = require('net');
24
+ var EventEmitter = require('events').EventEmitter;
25
+ var HTTPParser = process.binding('http_parser').HTTPParser;
26
+ var assert = require('assert').ok;
27
+
28
+ var common = require('_http_common');
29
+ var parsers = common.parsers;
30
+ var freeParser = common.freeParser;
31
+ var debug = common.debug;
32
+ var CRLF = common.CRLF;
33
+ var continueExpression = common.continueExpression;
34
+ var chunkExpression = common.chunkExpression;
35
+ var httpSocketSetup = common.httpSocketSetup;
36
+
37
+ var OutgoingMessage = require('_http_outgoing').OutgoingMessage;
38
+
39
+
40
+ var STATUS_CODES = exports.STATUS_CODES = {
41
+ 100 : 'Continue',
42
+ 101 : 'Switching Protocols',
43
+ 102 : 'Processing', // RFC 2518, obsoleted by RFC 4918
44
+ 200 : 'OK',
45
+ 201 : 'Created',
46
+ 202 : 'Accepted',
47
+ 203 : 'Non-Authoritative Information',
48
+ 204 : 'No Content',
49
+ 205 : 'Reset Content',
50
+ 206 : 'Partial Content',
51
+ 207 : 'Multi-Status', // RFC 4918
52
+ 300 : 'Multiple Choices',
53
+ 301 : 'Moved Permanently',
54
+ 302 : 'Moved Temporarily',
55
+ 303 : 'See Other',
56
+ 304 : 'Not Modified',
57
+ 305 : 'Use Proxy',
58
+ 307 : 'Temporary Redirect',
59
+ 400 : 'Bad Request',
60
+ 401 : 'Unauthorized',
61
+ 402 : 'Payment Required',
62
+ 403 : 'Forbidden',
63
+ 404 : 'Not Found',
64
+ 405 : 'Method Not Allowed',
65
+ 406 : 'Not Acceptable',
66
+ 407 : 'Proxy Authentication Required',
67
+ 408 : 'Request Time-out',
68
+ 409 : 'Conflict',
69
+ 410 : 'Gone',
70
+ 411 : 'Length Required',
71
+ 412 : 'Precondition Failed',
72
+ 413 : 'Request Entity Too Large',
73
+ 414 : 'Request-URI Too Large',
74
+ 415 : 'Unsupported Media Type',
75
+ 416 : 'Requested Range Not Satisfiable',
76
+ 417 : 'Expectation Failed',
77
+ 418 : 'I\'m a teapot', // RFC 2324
78
+ 422 : 'Unprocessable Entity', // RFC 4918
79
+ 423 : 'Locked', // RFC 4918
80
+ 424 : 'Failed Dependency', // RFC 4918
81
+ 425 : 'Unordered Collection', // RFC 4918
82
+ 426 : 'Upgrade Required', // RFC 2817
83
+ 428 : 'Precondition Required', // RFC 6585
84
+ 429 : 'Too Many Requests', // RFC 6585
85
+ 431 : 'Request Header Fields Too Large',// RFC 6585
86
+ 500 : 'Internal Server Error',
87
+ 501 : 'Not Implemented',
88
+ 502 : 'Bad Gateway',
89
+ 503 : 'Service Unavailable',
90
+ 504 : 'Gateway Time-out',
91
+ 505 : 'HTTP Version Not Supported',
92
+ 506 : 'Variant Also Negotiates', // RFC 2295
93
+ 507 : 'Insufficient Storage', // RFC 4918
94
+ 509 : 'Bandwidth Limit Exceeded',
95
+ 510 : 'Not Extended', // RFC 2774
96
+ 511 : 'Network Authentication Required' // RFC 6585
97
+ };
98
+
99
+
100
+ function ServerResponse(req) {
101
+ OutgoingMessage.call(this);
102
+
103
+ if (req.method === 'HEAD') this._hasBody = false;
104
+
105
+ this.sendDate = true;
106
+
107
+ if (req.httpVersionMajor < 1 || req.httpVersionMinor < 1) {
108
+ this.useChunkedEncodingByDefault = chunkExpression.test(req.headers.te);
109
+ this.shouldKeepAlive = false;
110
+ }
111
+ }
112
+ util.inherits(ServerResponse, OutgoingMessage);
113
+
114
+ ServerResponse.prototype._finish = function() {
115
+ DTRACE_HTTP_SERVER_RESPONSE(this.connection);
116
+ COUNTER_HTTP_SERVER_RESPONSE();
117
+ OutgoingMessage.prototype._finish.call(this);
118
+ };
119
+
120
+
121
+
122
+ exports.ServerResponse = ServerResponse;
123
+
124
+ ServerResponse.prototype.statusCode = 200;
125
+ ServerResponse.prototype.statusMessage = undefined;
126
+
127
+ function onServerResponseClose() {
128
+ // EventEmitter.emit makes a copy of the 'close' listeners array before
129
+ // calling the listeners. detachSocket() unregisters onServerResponseClose
130
+ // but if detachSocket() is called, directly or indirectly, by a 'close'
131
+ // listener, onServerResponseClose is still in that copy of the listeners
132
+ // array. That is, in the example below, b still gets called even though
133
+ // it's been removed by a:
134
+ //
135
+ // var obj = new events.EventEmitter;
136
+ // obj.on('event', a);
137
+ // obj.on('event', b);
138
+ // function a() { obj.removeListener('event', b) }
139
+ // function b() { throw "BAM!" }
140
+ // obj.emit('event'); // throws
141
+ //
142
+ // Ergo, we need to deal with stale 'close' events and handle the case
143
+ // where the ServerResponse object has already been deconstructed.
144
+ // Fortunately, that requires only a single if check. :-)
145
+ if (this._httpMessage) this._httpMessage.emit('close');
146
+ }
147
+
148
+ ServerResponse.prototype.assignSocket = function(socket) {
149
+ assert(!socket._httpMessage);
150
+ socket._httpMessage = this;
151
+ socket.on('close', onServerResponseClose);
152
+ this.socket = socket;
153
+ this.connection = socket;
154
+ this.emit('socket', socket);
155
+ this._flush();
156
+ };
157
+
158
+ ServerResponse.prototype.detachSocket = function(socket) {
159
+ assert(socket._httpMessage == this);
160
+ socket.removeListener('close', onServerResponseClose);
161
+ socket._httpMessage = null;
162
+ this.socket = this.connection = null;
163
+ };
164
+
165
+ ServerResponse.prototype.writeContinue = function(cb) {
166
+ this._writeRaw('HTTP/1.1 100 Continue' + CRLF + CRLF, 'ascii', cb);
167
+ this._sent100 = true;
168
+ };
169
+
170
+ ServerResponse.prototype._implicitHeader = function() {
171
+ this.writeHead(this.statusCode);
172
+ };
173
+
174
+ ServerResponse.prototype.writeHead = function(statusCode) {
175
+ var headers, headerIndex;
176
+
177
+ if (util.isString(arguments[1])) {
178
+ this.statusMessage = arguments[1];
179
+ headerIndex = 2;
180
+ } else {
181
+ this.statusMessage =
182
+ this.statusMessage || STATUS_CODES[statusCode] || 'unknown';
183
+ headerIndex = 1;
184
+ }
185
+ this.statusCode = statusCode;
186
+
187
+ var obj = arguments[headerIndex];
188
+
189
+ if (obj && this._headers) {
190
+ // Slow-case: when progressive API and header fields are passed.
191
+ headers = this._renderHeaders();
192
+
193
+ if (util.isArray(obj)) {
194
+ // handle array case
195
+ // TODO: remove when array is no longer accepted
196
+ var field;
197
+ for (var i = 0, len = obj.length; i < len; ++i) {
198
+ field = obj[i][0];
199
+ if (!util.isUndefined(headers[field])) {
200
+ obj.push([field, headers[field]]);
201
+ }
202
+ }
203
+ headers = obj;
204
+
205
+ } else {
206
+ // handle object case
207
+ var keys = Object.keys(obj);
208
+ for (var i = 0; i < keys.length; i++) {
209
+ var k = keys[i];
210
+ if (k) headers[k] = obj[k];
211
+ }
212
+ }
213
+ } else if (this._headers) {
214
+ // only progressive api is used
215
+ headers = this._renderHeaders();
216
+ } else {
217
+ // only writeHead() called
218
+ headers = obj;
219
+ }
220
+
221
+ var statusLine = 'HTTP/1.1 ' + statusCode.toString() + ' ' +
222
+ this.statusMessage + CRLF;
223
+
224
+ if (statusCode === 204 || statusCode === 304 ||
225
+ (100 <= statusCode && statusCode <= 199)) {
226
+ // RFC 2616, 10.2.5:
227
+ // The 204 response MUST NOT include a message-body, and thus is always
228
+ // terminated by the first empty line after the header fields.
229
+ // RFC 2616, 10.3.5:
230
+ // The 304 response MUST NOT contain a message-body, and thus is always
231
+ // terminated by the first empty line after the header fields.
232
+ // RFC 2616, 10.1 Informational 1xx:
233
+ // This class of status code indicates a provisional response,
234
+ // consisting only of the Status-Line and optional headers, and is
235
+ // terminated by an empty line.
236
+ this._hasBody = false;
237
+ }
238
+
239
+ // don't keep alive connections where the client expects 100 Continue
240
+ // but we sent a final status; they may put extra bytes on the wire.
241
+ if (this._expect_continue && !this._sent100) {
242
+ this.shouldKeepAlive = false;
243
+ }
244
+
245
+ this._storeHeader(statusLine, headers);
246
+ };
247
+
248
+ ServerResponse.prototype.writeHeader = function() {
249
+ this.writeHead.apply(this, arguments);
250
+ };
251
+
252
+
253
+ function Server(requestListener) {
254
+ if (!(this instanceof Server)) return new Server(requestListener);
255
+ net.Server.call(this, { allowHalfOpen: true });
256
+
257
+ if (requestListener) {
258
+ this.addListener('request', requestListener);
259
+ }
260
+
261
+ // Similar option to this. Too lazy to write my own docs.
262
+ // http://www.squid-cache.org/Doc/config/half_closed_clients/
263
+ // http://wiki.squid-cache.org/SquidFaq/InnerWorkings#What_is_a_half-closed_filedescriptor.3F
264
+ this.httpAllowHalfOpen = false;
265
+
266
+ this.addListener('connection', connectionListener);
267
+
268
+ this.addListener('clientError', function(err, conn) {
269
+ conn.destroy(err);
270
+ });
271
+
272
+ this.timeout = 2 * 60 * 1000;
273
+ }
274
+ util.inherits(Server, net.Server);
275
+
276
+
277
+ Server.prototype.setTimeout = function(msecs, callback) {
278
+ this.timeout = msecs;
279
+ if (callback)
280
+ this.on('timeout', callback);
281
+ };
282
+
283
+
284
+ exports.Server = Server;
285
+
286
+
287
+ function connectionListener(socket) {
288
+ var self = this;
289
+ var outgoing = [];
290
+ var incoming = [];
291
+
292
+ function abortIncoming() {
293
+ while (incoming.length) {
294
+ var req = incoming.shift();
295
+ req.emit('aborted');
296
+ req.emit('close');
297
+ }
298
+ // abort socket._httpMessage ?
299
+ }
300
+
301
+ function serverSocketCloseListener() {
302
+ debug('server socket close');
303
+ // mark this parser as reusable
304
+ if (this.parser)
305
+ freeParser(this.parser);
306
+
307
+ abortIncoming();
308
+ }
309
+
310
+ debug('SERVER new http connection');
311
+
312
+ httpSocketSetup(socket);
313
+
314
+ // If the user has added a listener to the server,
315
+ // request, or response, then it's their responsibility.
316
+ // otherwise, destroy on timeout by default
317
+ if (self.timeout)
318
+ socket.setTimeout(self.timeout);
319
+ socket.on('timeout', function() {
320
+ var req = socket.parser && socket.parser.incoming;
321
+ var reqTimeout = req && !req.complete && req.emit('timeout', socket);
322
+ var res = socket._httpMessage;
323
+ var resTimeout = res && res.emit('timeout', socket);
324
+ var serverTimeout = self.emit('timeout', socket);
325
+
326
+ if (!reqTimeout && !resTimeout && !serverTimeout)
327
+ socket.destroy();
328
+ });
329
+
330
+ var parser = parsers.alloc();
331
+ parser.reinitialize(HTTPParser.REQUEST);
332
+ parser.socket = socket;
333
+ socket.parser = parser;
334
+ parser.incoming = null;
335
+
336
+ // Propagate headers limit from server instance to parser
337
+ if (util.isNumber(this.maxHeadersCount)) {
338
+ parser.maxHeaderPairs = this.maxHeadersCount << 1;
339
+ } else {
340
+ // Set default value because parser may be reused from FreeList
341
+ parser.maxHeaderPairs = 2000;
342
+ }
343
+
344
+ socket.addListener('error', socketOnError);
345
+ socket.addListener('close', serverSocketCloseListener);
346
+ parser.onIncoming = parserOnIncoming;
347
+ socket.on('end', socketOnEnd);
348
+ socket.on('data', socketOnData);
349
+
350
+ // TODO(isaacs): Move all these functions out of here
351
+ function socketOnError(e) {
352
+ self.emit('clientError', e, this);
353
+ }
354
+
355
+ function socketOnData(d) {
356
+ assert(!socket._paused);
357
+ debug('SERVER socketOnData %d', d.length);
358
+ var ret = parser.execute(d);
359
+ if (ret instanceof Error) {
360
+ debug('parse error');
361
+ socket.destroy(ret);
362
+ } else if (parser.incoming && parser.incoming.upgrade) {
363
+ // Upgrade or CONNECT
364
+ var bytesParsed = ret;
365
+ var req = parser.incoming;
366
+ debug('SERVER upgrade or connect', req.method);
367
+
368
+ socket.removeListener('data', socketOnData);
369
+ socket.removeListener('end', socketOnEnd);
370
+ socket.removeListener('close', serverSocketCloseListener);
371
+ parser.finish();
372
+ freeParser(parser, req);
373
+
374
+ var eventName = req.method === 'CONNECT' ? 'connect' : 'upgrade';
375
+ if (EventEmitter.listenerCount(self, eventName) > 0) {
376
+ debug('SERVER have listener for %s', eventName);
377
+ var bodyHead = d.slice(bytesParsed, d.length);
378
+
379
+ // TODO(isaacs): Need a way to reset a stream to fresh state
380
+ // IE, not flowing, and not explicitly paused.
381
+ socket._readableState.flowing = null;
382
+ self.emit(eventName, req, socket, bodyHead);
383
+ } else {
384
+ // Got upgrade header or CONNECT method, but have no handler.
385
+ socket.destroy();
386
+ }
387
+ }
388
+
389
+ if (socket._paused) {
390
+ // onIncoming paused the socket, we should pause the parser as well
391
+ debug('pause parser');
392
+ socket.parser.pause();
393
+ }
394
+ }
395
+
396
+ function socketOnEnd() {
397
+ var socket = this;
398
+ var ret = parser.finish();
399
+
400
+ if (ret instanceof Error) {
401
+ debug('parse error');
402
+ socket.destroy(ret);
403
+ return;
404
+ }
405
+
406
+ if (!self.httpAllowHalfOpen) {
407
+ abortIncoming();
408
+ if (socket.writable) socket.end();
409
+ } else if (outgoing.length) {
410
+ outgoing[outgoing.length - 1]._last = true;
411
+ } else if (socket._httpMessage) {
412
+ socket._httpMessage._last = true;
413
+ } else {
414
+ if (socket.writable) socket.end();
415
+ }
416
+ }
417
+
418
+
419
+ // The following callback is issued after the headers have been read on a
420
+ // new message. In this callback we setup the response object and pass it
421
+ // to the user.
422
+
423
+ socket._paused = false;
424
+ function socketOnDrain() {
425
+ // If we previously paused, then start reading again.
426
+ if (socket._paused) {
427
+ socket._paused = false;
428
+ socket.parser.resume();
429
+ socket.resume();
430
+ }
431
+ }
432
+ socket.on('drain', socketOnDrain);
433
+
434
+ function parserOnIncoming(req, shouldKeepAlive) {
435
+ incoming.push(req);
436
+
437
+ // If the writable end isn't consuming, then stop reading
438
+ // so that we don't become overwhelmed by a flood of
439
+ // pipelined requests that may never be resolved.
440
+ if (!socket._paused) {
441
+ var needPause = socket._writableState.needDrain;
442
+ if (needPause) {
443
+ socket._paused = true;
444
+ // We also need to pause the parser, but don't do that until after
445
+ // the call to execute, because we may still be processing the last
446
+ // chunk.
447
+ socket.pause();
448
+ }
449
+ }
450
+
451
+ var res = new ServerResponse(req);
452
+
453
+ res.shouldKeepAlive = shouldKeepAlive;
454
+ DTRACE_HTTP_SERVER_REQUEST(req, socket);
455
+ COUNTER_HTTP_SERVER_REQUEST();
456
+
457
+ if (socket._httpMessage) {
458
+ // There are already pending outgoing res, append.
459
+ outgoing.push(res);
460
+ } else {
461
+ res.assignSocket(socket);
462
+ }
463
+
464
+ // When we're finished writing the response, check if this is the last
465
+ // respose, if so destroy the socket.
466
+ res.on('prefinish', resOnFinish);
467
+ function resOnFinish() {
468
+ // Usually the first incoming element should be our request. it may
469
+ // be that in the case abortIncoming() was called that the incoming
470
+ // array will be empty.
471
+ assert(incoming.length == 0 || incoming[0] === req);
472
+
473
+ incoming.shift();
474
+
475
+ // if the user never called req.read(), and didn't pipe() or
476
+ // .resume() or .on('data'), then we call req._dump() so that the
477
+ // bytes will be pulled off the wire.
478
+ if (!req._consuming)
479
+ req._dump();
480
+
481
+ res.detachSocket(socket);
482
+
483
+ if (res._last) {
484
+ socket.destroySoon();
485
+ } else {
486
+ // start sending the next message
487
+ var m = outgoing.shift();
488
+ if (m) {
489
+ m.assignSocket(socket);
490
+ }
491
+ }
492
+ }
493
+
494
+ if (!util.isUndefined(req.headers.expect) &&
495
+ (req.httpVersionMajor == 1 && req.httpVersionMinor == 1) &&
496
+ continueExpression.test(req.headers['expect'])) {
497
+ res._expect_continue = true;
498
+ if (EventEmitter.listenerCount(self, 'checkContinue') > 0) {
499
+ self.emit('checkContinue', req, res);
500
+ } else {
501
+ res.writeContinue();
502
+ self.emit('request', req, res);
503
+ }
504
+ } else {
505
+ self.emit('request', req, res);
506
+ }
507
+ return false; // Not a HEAD response. (Not even a response!)
508
+ }
509
+ }
510
+ exports._connectionListener = connectionListener;