passenger 4.0.44 → 4.0.45

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

Files changed (110) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/.travis.yml +3 -0
  5. data/CHANGELOG +31 -0
  6. data/CONTRIBUTING.md +70 -10
  7. data/CONTRIBUTORS +4 -0
  8. data/README.md +1 -1
  9. data/Vagrantfile +50 -0
  10. data/bin/passenger-install-nginx-module +7 -2
  11. data/build/basics.rb +4 -1
  12. data/build/documentation.rb +6 -0
  13. data/build/node_tests.rb +7 -1
  14. data/build/packaging.rb +5 -0
  15. data/build/test_basics.rb +3 -3
  16. data/debian.template/copyright +1 -1
  17. data/debian.template/passenger.manpages +0 -1
  18. data/dev/rack.test/config.ru +5 -0
  19. data/dev/rack.test/public/asset.txt +1 -0
  20. data/dev/vagrant/apache_default_site.conf +35 -0
  21. data/dev/vagrant/apache_passenger.conf +5 -0
  22. data/dev/vagrant/apache_passenger.load +1 -0
  23. data/dev/vagrant/apache_ports.conf +24 -0
  24. data/dev/vagrant/apache_rack_test.conf +9 -0
  25. data/dev/vagrant/bashrc +21 -0
  26. data/dev/vagrant/nginx.conf +39 -0
  27. data/dev/vagrant/nginx_rakefile +34 -0
  28. data/dev/vagrant/nginx_start +32 -0
  29. data/dev/vagrant/provision.sh +115 -0
  30. data/dev/vagrant/sudoers.conf +5 -0
  31. data/doc/Design and Architecture.txt +515 -0
  32. data/doc/DeveloperQuickstart.md +70 -0
  33. data/doc/Users guide Apache.idmap.txt +24 -18
  34. data/doc/Users guide Apache.txt +200 -62
  35. data/doc/Users guide Nginx.idmap.txt +53 -45
  36. data/doc/Users guide Nginx.txt +501 -360
  37. data/doc/Users guide Standalone.txt +8 -0
  38. data/doc/images/direct_spawning.png +0 -0
  39. data/doc/images/direct_spawning.svg +16 -13
  40. data/doc/images/helper_agent_core_architecture.png +0 -0
  41. data/doc/images/passenger_architecture_overview.png +0 -0
  42. data/doc/images/smart_spawning.png +0 -0
  43. data/doc/images/{smart.svg → smart_spawning.svg} +23 -20
  44. data/doc/images/spawning_preparation_work.png +0 -0
  45. data/doc/images/startup_sequence.png +0 -0
  46. data/doc/users_guide_snippets/appendix_c_spawning_methods.txt +82 -121
  47. data/doc/users_guide_snippets/environment_variables.txt +1 -1
  48. data/doc/users_guide_snippets/support_information.txt +2 -0
  49. data/doc/users_guide_snippets/tips.txt +117 -9
  50. data/ext/apache2/Configuration.hpp +4 -2
  51. data/ext/apache2/ConfigurationCommands.cpp +14 -0
  52. data/ext/apache2/ConfigurationFields.hpp +4 -0
  53. data/ext/apache2/ConfigurationSetters.cpp +22 -0
  54. data/ext/apache2/CreateDirConfig.cpp +2 -0
  55. data/ext/apache2/Hooks.cpp +30 -14
  56. data/ext/apache2/MergeDirConfig.cpp +14 -0
  57. data/ext/apache2/SetHeaders.cpp +8 -0
  58. data/ext/common/ApplicationPool2/AppTypes.cpp +6 -1
  59. data/ext/common/ApplicationPool2/Implementation.cpp +1 -1
  60. data/ext/common/ApplicationPool2/Session.h +1 -1
  61. data/ext/common/Constants.h +9 -7
  62. data/ext/common/Utils/HttpHeaderBufferer.h +23 -4
  63. data/ext/common/Utils/StrIntUtils.h +35 -0
  64. data/ext/common/Utils/StringScanning.h +4 -10
  65. data/ext/common/agents/HelperAgent/RequestHandler.h +90 -49
  66. data/ext/nginx/CacheLocationConfig.c +40 -0
  67. data/ext/nginx/ConfigurationCommands.c +20 -0
  68. data/ext/nginx/ConfigurationFields.h +4 -0
  69. data/ext/nginx/ContentHandler.c +1 -1
  70. data/ext/nginx/CreateLocationConfig.c +9 -0
  71. data/ext/nginx/MergeLocationConfig.c +12 -0
  72. data/ext/nginx/config +2 -2
  73. data/ext/nginx/ngx_http_passenger_module.c +4 -4
  74. data/helper-scripts/node-loader.js +40 -27
  75. data/lib/phusion_passenger.rb +1 -1
  76. data/lib/phusion_passenger/apache2/config_options.rb +14 -2
  77. data/lib/phusion_passenger/constants.rb +7 -6
  78. data/lib/phusion_passenger/loader_shared_helpers.rb +11 -1
  79. data/lib/phusion_passenger/nginx/config_options.rb +8 -0
  80. data/lib/phusion_passenger/packaging.rb +8 -3
  81. data/lib/phusion_passenger/platform_info/apache.rb +3 -0
  82. data/lib/phusion_passenger/platform_info/ruby.rb +4 -1
  83. data/lib/phusion_passenger/standalone/command.rb +0 -1
  84. data/lib/phusion_passenger/standalone/package_runtime_command.rb +1 -0
  85. data/lib/phusion_passenger/standalone/start_command.rb +80 -62
  86. data/lib/phusion_passenger/standalone/status_command.rb +1 -0
  87. data/lib/phusion_passenger/standalone/stop_command.rb +1 -0
  88. data/man/passenger-config.1 +1 -1
  89. data/man/passenger-memory-stats.8 +1 -1
  90. data/man/passenger-status.8 +1 -1
  91. data/npm-shrinkwrap.json +229 -0
  92. data/package.json +28 -0
  93. data/resources/templates/standalone/config.erb +2 -0
  94. data/rpm/Vagrantfile +0 -3
  95. data/test/config.json.vagrant +30 -0
  96. data/test/cxx/HttpHeaderBuffererTest.cpp +64 -10
  97. data/test/cxx/RequestHandlerTest.cpp +35 -13
  98. data/test/integration_tests/apache2_tests.rb +1 -0
  99. data/test/stub/node/app.js +26 -18
  100. metadata +28 -13
  101. metadata.gz.asc +7 -7
  102. data/doc/Architectural overview.idmap.txt +0 -36
  103. data/doc/Architectural overview.txt +0 -410
  104. data/doc/images/smart.png +0 -0
  105. data/ext/common/ApplicationPool2/README.md +0 -56
  106. data/man/passenger-stress-test.1 +0 -43
  107. data/node_lib/phusion_passenger/httplib_emulation.js +0 -215
  108. data/node_lib/phusion_passenger/request_handler.js +0 -73
  109. data/node_lib/phusion_passenger/session_protocol_parser.js +0 -113
  110. data/test/node/httplib_emulation_spec.js +0 -623
@@ -1,623 +0,0 @@
1
- var Helper = require('./spec_helper').Helper;
2
- var FakeStream = require('./spec_helper').FakeStream;
3
- var should = require('should');
4
- var assert = require('assert');
5
- var net = require('net');
6
- var HttplibEmulation = require('phusion_passenger/httplib_emulation');
7
-
8
- /*
9
- * Caveat:
10
- * According to the Node.js source code, when a stream is set to flowing mode,
11
- * it is supposed to set _readableState.flowing to true. Yet from empirical tests
12
- * with http.Server, this does not happen. Neither on the IncomingMessage object,
13
- * nor on the socket object. Therefore, in the flowing mode tests, we only check
14
- * the flowing mode flag on the request object, not the socket.
15
- */
16
- describe('HttplibEmulation', function() {
17
- this.timeout(1000);
18
-
19
- beforeEach(function() {
20
- var state = this.state = {};
21
-
22
- state.createSocket = function(callback) {
23
- if (state.server || state.client) {
24
- throw new Error('createSocket() may only be called once');
25
- }
26
-
27
- var server = net.createServer();
28
-
29
- function maybeDone() {
30
- if (state.serverSocket && state.client) {
31
- callback(state.serverSocket, state.client);
32
- }
33
- }
34
-
35
- server.listen(0, '127.0.0.1', function() {
36
- var client = new net.Socket();
37
- client.once('connect', function() {
38
- state.client = client;
39
- maybeDone();
40
- });
41
- client.connect(server.address().port, '127.0.0.1');
42
- });
43
- server.once('connection', function(socket) {
44
- state.server = server;
45
- state.serverSocket = socket;
46
- maybeDone();
47
- });
48
- }
49
- });
50
-
51
- afterEach(function(done) {
52
- var state = this.state;
53
- var events = 1;
54
- var counter = 0;
55
-
56
- function maybeDone() {
57
- counter++;
58
- if (counter == events) {
59
- done();
60
- }
61
- }
62
-
63
- if (state.server) {
64
- events += 1;
65
- state.server.close(maybeDone);
66
- state.serverSocket.destroy();
67
- }
68
- if (state.client) {
69
- state.client.destroy();
70
- }
71
- maybeDone();
72
- });
73
-
74
- function createHeaders(object) {
75
- var key, keys = [];
76
- var result = {
77
- 'SERVER_PROTOCOL': 'HTTP/1.1',
78
- 'REMOTE_ADDR': '127.0.0.1',
79
- 'REMOTE_PORT': '3000',
80
- 'REQUEST_METHOD': 'GET',
81
- 'REQUEST_URI': '/',
82
- 'PATH_INFO': '/'
83
- };
84
- for (key in object) {
85
- result[key] = object[key];
86
- }
87
- for (key in result) {
88
- keys.push(key);
89
- }
90
- result.keys = keys;
91
- return result;
92
- }
93
-
94
- describe('the request object', function() {
95
- beforeEach(function() {
96
- var state = this.state;
97
- state.setup = function(headers, callback) {
98
- if (!callback) {
99
- callback = headers;
100
- headers = {};
101
- }
102
- state.headers = createHeaders(headers);
103
- state.createSocket(function(serverSocket, client) {
104
- state.req = HttplibEmulation.createIncomingMessage(
105
- state.headers, serverSocket, "");
106
- callback();
107
- });
108
- }
109
- });
110
-
111
- specify('.on() returns the request object', function(done) {
112
- var state = this.state;
113
- state.setup(function() {
114
- var result = state.req.on('foo', function() {});
115
- assert.strictEqual(result, state.req);
116
- done();
117
- });
118
- });
119
-
120
- it('sets no "upgrade" flag if there is no Upgrade header', function(done) {
121
- var state = this.state;
122
- state.setup(function() {
123
- assert.ok(!state.req.upgrade);
124
- done();
125
- });
126
- });
127
-
128
- it('sets the "upgrade" flag if there is an Upgrade header', function(done) {
129
- var state = this.state;
130
- var headers = {
131
- 'HTTP_UPGRADE': 'WebSocket'
132
- };
133
- state.setup(headers, function() {
134
- assert.ok(state.req.upgrade);
135
- done();
136
- });
137
- });
138
- });
139
-
140
- describe('if the request may have a request body', function() {
141
- beforeEach(function() {
142
- var state = this.state;
143
- state.setup = function(headers, callback) {
144
- if (!callback) {
145
- callback = headers;
146
- headers = {
147
- 'REQUEST_METHOD': 'POST'
148
- };
149
- }
150
- state.headers = createHeaders(headers);
151
- state.createSocket(function(serverSocket, client) {
152
- state.req = HttplibEmulation.createIncomingMessage(
153
- state.headers, serverSocket, "");
154
- callback();
155
- });
156
- }
157
- });
158
-
159
- it("isn't in flowing mode by default", function(done) {
160
- var state = this.state;
161
- state.setup(function() {
162
- assert.strictEqual(state.req._flowing, undefined);
163
- done();
164
- });
165
- });
166
-
167
- it("is set to flowing mode upon calling pause", function(done) {
168
- var state = this.state;
169
- state.setup(function() {
170
- state.req.pause();
171
- assert.strictEqual(state.req._flowing, false);
172
- done();
173
- });
174
- });
175
-
176
- it("is set to flowing mode upon calling resume", function(done) {
177
- var state = this.state;
178
- state.setup(function() {
179
- state.req.resume();
180
- assert.strictEqual(state.req._flowing, true);
181
- done();
182
- });
183
- });
184
-
185
- it("is set to flowing mode upon attaching a data event handler", function(done) {
186
- var state = this.state;
187
- state.setup(function() {
188
- var chunks = [];
189
- state.req.on('data', function(chunk) {
190
- chunks.push(chunk.toString('utf-8'));
191
- });
192
- assert.strictEqual(state.req._flowing, true);
193
- state.client.write("hello");
194
- Helper.eventually(100, function() {
195
- return chunks.length > 0;
196
- }, function() {
197
- chunks.should.eql(['hello']);
198
- done();
199
- });
200
- });
201
- });
202
-
203
- describe("when in flowing mode", function() {
204
- beforeEach(function(done) {
205
- var state = this.state;
206
- state.setup(function() {
207
- state.req.resume();
208
- assert.ok(state.req._flowing);
209
- done();
210
- });
211
- });
212
-
213
- specify("the request object emits data events as data is received", function(done) {
214
- var state = this.state;
215
- var chunks = [];
216
-
217
- state.req.on('data', function(chunk) {
218
- chunks.push(chunk.toString('utf-8'));
219
- });
220
- state.client.write("hello");
221
-
222
- Helper.eventually(100, function() {
223
- return chunks.length > 0;
224
- }, function() {
225
- chunks.should.eql(["hello"]);
226
- done();
227
- });
228
- });
229
-
230
- specify("the request object emits the end event after the client closes the socket", function(done) {
231
- var state = this.state;
232
- var finished;
233
-
234
- function endReachedPrematurely() {
235
- assert.fail("end event received prematurely");
236
- finished = true;
237
- done();
238
- }
239
- state.req.once('end', endReachedPrematurely);
240
-
241
- setTimeout(function() {
242
- if (!finished) {
243
- state.req.removeListener('end', endReachedPrematurely);
244
- state.req.once('end', function() {
245
- done();
246
- });
247
- state.client.destroy();
248
- }
249
- }, 50);
250
- });
251
- });
252
-
253
- describe("when in non-flowing mode", function() {
254
- beforeEach(function(done) {
255
- var state = this.state;
256
- state.setup(function() {
257
- assert.ok(!state.req._flowing);
258
- done();
259
- });
260
- });
261
-
262
- specify("the request object emits readable events upon receiving data", function(done) {
263
- var state = this.state;
264
- var readable = 0;
265
- state.req.on('readable', function() {
266
- readable++;
267
- });
268
- setTimeout(function() {
269
- state.client.write("hello");
270
- Helper.eventually(100, function() {
271
- return readable == 1;
272
- }, done);
273
- }, 50);
274
- });
275
-
276
- it("allows reading from the request object", function(done) {
277
- var state = this.state;
278
- state.client.write("hello");
279
-
280
- setTimeout(function() {
281
- var chunk = state.req.read(5);
282
- assert.ok(!!chunk);
283
- chunk.toString('utf-8').should.eql('hello');
284
- done();
285
- }, 50);
286
- });
287
-
288
- it("emits a readable event if data was already received before attaching the event listener", function(done) {
289
- var state = this.state;
290
- state.client.write("hello");
291
-
292
- setTimeout(function() {
293
- var readable = 0;
294
- state.req.on('readable', function() {
295
- readable++;
296
- });
297
- Helper.eventually(100, function() {
298
- return readable == 1;
299
- }, done);
300
- }, 50);
301
- });
302
-
303
- it("pauses the socket data flow if the request buffer becomes too full", function(done) {
304
- var state = this.state;
305
- var i, buf;
306
-
307
- state.client.write("hello");
308
- buf = new Buffer(1024);
309
- buf.fill("x");
310
- for (i = 0; i < 1024; i++) {
311
- state.client.write(buf);
312
- }
313
-
314
- setTimeout(function() {
315
- var len = state.req._readableState.length;
316
- assert.ok(len > 0);
317
-
318
- buf = new Buffer(1024);
319
- buf.fill("y");
320
- for (i = 0; i < 1024; i++) {
321
- state.client.write(buf);
322
- }
323
-
324
- setTimeout(function() {
325
- state.req._readableState.length.should.equal(len);
326
- var chunk = state.req.read(7);
327
- assert.ok(!!chunk);
328
- chunk.toString('utf-8').should.eql("helloxx");
329
- done();
330
- }, 100);
331
- }, 100);
332
- });
333
-
334
- it("resumes the socket data flow if the request buffer's size drops to below the high water mark", function(done) {
335
- var state = this.state;
336
- var i, buf;
337
-
338
- buf = new Buffer(1024);
339
- buf.fill("x");
340
- for (i = 0; i < 1024; i++) {
341
- state.client.write(buf);
342
- }
343
-
344
- var len = 0;
345
- var str = buf.slice(0, 512).toString('utf-8');
346
- state.req.on('readable', function() {
347
- var chunk;
348
- while ((chunk = state.req.read(512)) !== null) {
349
- chunk.toString('utf-8').should.eql(str);
350
- len += chunk.length;
351
- }
352
- });
353
- Helper.eventually(100, function() {
354
- return len == 1024 * 1024;
355
- }, done);
356
- })
357
-
358
- it("doesn't emit the end event if the request was never read from", function(done) {
359
- var state = this.state;
360
- var finished;
361
- setTimeout(function() {
362
- if (!finished) {
363
- finished = true;
364
- done();
365
- }
366
- }, 50);
367
- state.req.on('end', function() {
368
- if (!finished) {
369
- finished = true;
370
- assert.fail("unexpected end event");
371
- }
372
- });
373
- });
374
-
375
- it("emits the end event upon reaching the end of the request body", function(done) {
376
- var state = this.state;
377
- var i, buf;
378
-
379
- state.client.write("hello");
380
- buf = new Buffer(1024);
381
- buf.fill("x");
382
- for (i = 0; i < 1024; i++) {
383
- state.client.write(buf);
384
- }
385
- state.client.end();
386
-
387
- var len = 0;
388
- state.req.on('readable', function() {
389
- while ((buf = state.req.read(512)) !== null) {
390
- len += buf.length;
391
- }
392
- });
393
- state.req.on('end', function() {
394
- len.should.equal(1024 * 1024);
395
- done();
396
- })
397
- });
398
-
399
- it("emits the end event when read() encounters EOF", function(done) {
400
- var state = this.state;
401
- var finished;
402
- state.req.on('end', function() {
403
- if (!finished) {
404
- finished = true;
405
- done();
406
- }
407
- });
408
- state.client.end();
409
- setTimeout(function() {
410
- state.req.read(10);
411
- }, 10);
412
- });
413
- });
414
- });
415
-
416
- describe("if the request doesn't have a request body", function() {
417
- beforeEach(function() {
418
- var state = this.state;
419
- state.setup = function(headers, callback) {
420
- if (!callback) {
421
- callback = headers;
422
- headers = {};
423
- }
424
- state.headers = createHeaders(headers);
425
- state.createSocket(function(serverSocket, client) {
426
- state.req = HttplibEmulation.createIncomingMessage(
427
- state.headers, serverSocket, "");
428
- callback();
429
- });
430
- }
431
- });
432
-
433
- it("isn't in flowing mode by default", function(done) {
434
- var state = this.state;
435
- state.setup(function() {
436
- assert.strictEqual(state.req._flowing, undefined);
437
- done();
438
- });
439
- });
440
-
441
- it("is set to flowing mode upon calling pause", function(done) {
442
- var state = this.state;
443
- state.setup(function() {
444
- state.req.pause();
445
- assert.strictEqual(state.req._flowing, false);
446
- done();
447
- });
448
- });
449
-
450
- it("is set to flowing mode upon calling resume", function(done) {
451
- var state = this.state;
452
- state.setup(function() {
453
- state.req.resume();
454
- assert.strictEqual(state.req._flowing, true);
455
- done();
456
- });
457
- });
458
-
459
- it("is set to flowing mode upon attaching a data event handler", function(done) {
460
- var state = this.state;
461
- state.setup(function() {
462
- state.req.on('data', function(chunk) {});
463
- assert.strictEqual(state.req._flowing, true);
464
- done();
465
- });
466
- });
467
-
468
- describe("when in flowing mode", function() {
469
- beforeEach(function(done) {
470
- var state = this.state;
471
- state.setup(function() {
472
- state.req.resume();
473
- assert.ok(state.req._flowing);
474
- done();
475
- });
476
- });
477
-
478
- it("sends the end event immediately", function(done) {
479
- var state = this.state;
480
- var finished;
481
- setTimeout(function() {
482
- if (!finished) {
483
- finished = true;
484
- assert.fail("end event never sent");
485
- }
486
- }, 50);
487
- state.req.on('end', function() {
488
- if (!finished) {
489
- finished = true;
490
- done();
491
- }
492
- });
493
- });
494
- });
495
-
496
- describe("when in non-flowing mode", function() {
497
- beforeEach(function(done) {
498
- var state = this.state;
499
- state.setup(function() {
500
- assert.ok(!state.req._flowing);
501
- done();
502
- });
503
- });
504
-
505
- it("doesn't send the end event if the request was never read from", function(done) {
506
- var state = this.state;
507
- var finished;
508
- setTimeout(function() {
509
- if (!finished) {
510
- finished = true;
511
- done();
512
- }
513
- }, 50);
514
- state.req.on('end', function() {
515
- if (!finished) {
516
- finished = true;
517
- assert.fail("unexpected end event");
518
- }
519
- });
520
- });
521
-
522
- it("sends the end event when read() encounters EOF", function(done) {
523
- var state = this.state;
524
- var finished;
525
- state.req.on('end', function() {
526
- if (!finished) {
527
- finished = true;
528
- done();
529
- }
530
- });
531
- state.req.read(10);
532
- });
533
- });
534
- });
535
-
536
- describe('requests with Upgrade header', function() {
537
- beforeEach(function() {
538
- var state = this.state;
539
- state.setup = function(headers, callback) {
540
- if (!callback) {
541
- callback = headers;
542
- headers = {
543
- 'HTTP_UPGRADE': 'websocket'
544
- };
545
- }
546
- state.headers = createHeaders(headers);
547
- state.createSocket(function(serverSocket, client) {
548
- state.req = HttplibEmulation.createIncomingMessage(
549
- state.headers, serverSocket, "");
550
- callback();
551
- });
552
- }
553
- });
554
-
555
- specify('the request object emits no data events', function(done) {
556
- var state = this.state;
557
- state.setup(function() {
558
- var hasData = false;
559
-
560
- state.req.on('data', function(data) {
561
- hasData = true;
562
- });
563
- state.client.write("hello");
564
-
565
- Helper.shouldNeverHappen(50, function() {
566
- return hasData;
567
- }, done);
568
- });
569
- });
570
-
571
- specify('the request object ends immediately', function(done) {
572
- var state = this.state;
573
- state.setup(function() {
574
- var readable = false;
575
- var readData;
576
- var ended = false;
577
-
578
- state.req.on('readable', function() {
579
- readable = true;
580
- readData = state.req.read(100);
581
- });
582
- state.req.on('end', function() {
583
- ended = true;
584
- });
585
-
586
- Helper.eventually(50, function() {
587
- return readable && ended;
588
- }, function() {
589
- assert.strictEqual(readData, null);
590
- done();
591
- });
592
- });
593
- });
594
-
595
- specify('the socket emits data events as data is received', function(done) {
596
- var state = this.state;
597
- state.setup(function() {
598
- var hasData = false;
599
-
600
- state.req.socket.on('data', function(data) {
601
- hasData = true;
602
- });
603
- state.client.write("hello");
604
-
605
- Helper.eventually(50, function() {
606
- return hasData;
607
- }, done);
608
- });
609
- });
610
-
611
- it('allows reading from the socket', function(done) {
612
- var state = this.state;
613
- state.setup(function() {
614
- state.req.socket.on('readable', function() {
615
- var chunk = state.req.socket.read(5).toString('utf-8');
616
- chunk.should.eql("hello");
617
- done();
618
- });
619
- state.client.write("hello");
620
- });
621
- });
622
- });
623
- });