passenger 4.0.36 → 4.0.37
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.
- checksums.yaml +8 -8
- checksums.yaml.gz.asc +7 -7
- data.tar.gz.asc +7 -7
- data/NEWS +51 -0
- data/README.md +3 -1
- data/build/integration_tests.rb +5 -1
- data/build/test_basics.rb +2 -2
- data/dev/run_travis.sh +3 -0
- data/doc/Users guide Nginx.txt +3 -3
- data/ext/common/ApplicationPool2/Group.h +2 -1
- data/ext/common/ApplicationPool2/Implementation.cpp +30 -1
- data/ext/common/ApplicationPool2/Pool.h +26 -3
- data/ext/common/ApplicationPool2/Process.h +39 -10
- data/ext/common/Constants.h +1 -1
- data/ext/common/MultiLibeio.cpp +4 -0
- data/ext/common/ServerInstanceDir.h +1 -1
- data/ext/common/Utils.cpp +29 -0
- data/ext/common/Utils.h +7 -1
- data/ext/common/Utils/BufferedIO.h +13 -0
- data/ext/common/agents/HelperAgent/Main.cpp +6 -2
- data/ext/common/agents/HelperAgent/RequestHandler.h +32 -1
- data/helper-scripts/meteor-loader.rb +126 -10
- data/helper-scripts/node-loader.js +5 -3
- data/helper-scripts/wsgi-loader.py +23 -11
- data/lib/phusion_passenger.rb +1 -1
- data/lib/phusion_passenger/config/detach_process_command.rb +96 -0
- data/lib/phusion_passenger/config/main.rb +1 -0
- data/lib/phusion_passenger/request_handler.rb +11 -4
- data/node_lib/phusion_passenger/httplib_emulation.js +20 -14
- data/test/cxx/RequestHandlerTest.cpp +80 -0
- data/test/integration_tests/apache2_tests.rb +57 -0
- data/test/integration_tests/nginx_tests.rb +62 -0
- data/test/node/httplib_emulation_spec.js +137 -5
- data/test/node/spec_helper.js +13 -0
- data/test/stub/node/app.js +125 -0
- data/test/stub/node/public/.gitignore +0 -0
- data/test/stub/node/tmp/.gitignore +0 -0
- data/test/stub/rack/config.ru +19 -0
- data/test/stub/wsgi/passenger_wsgi.py +37 -1
- metadata +6 -2
- metadata.gz.asc +7 -7
@@ -91,6 +91,52 @@ describe('HttplibEmulation', function() {
|
|
91
91
|
return result;
|
92
92
|
}
|
93
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
|
+
|
94
140
|
describe('if the request may have a request body', function() {
|
95
141
|
beforeEach(function() {
|
96
142
|
var state = this.state;
|
@@ -105,7 +151,6 @@ describe('HttplibEmulation', function() {
|
|
105
151
|
state.createSocket(function(serverSocket, client) {
|
106
152
|
state.req = HttplibEmulation.createIncomingMessage(
|
107
153
|
state.headers, serverSocket, "");
|
108
|
-
assert.ok(state.req._mayHaveRequestBody);
|
109
154
|
callback();
|
110
155
|
});
|
111
156
|
}
|
@@ -165,7 +210,7 @@ describe('HttplibEmulation', function() {
|
|
165
210
|
});
|
166
211
|
});
|
167
212
|
|
168
|
-
|
213
|
+
specify("the request object emits data events as data is received", function(done) {
|
169
214
|
var state = this.state;
|
170
215
|
var chunks = [];
|
171
216
|
|
@@ -182,7 +227,7 @@ describe('HttplibEmulation', function() {
|
|
182
227
|
});
|
183
228
|
});
|
184
229
|
|
185
|
-
|
230
|
+
specify("the request object emits the end event after the client closes the socket", function(done) {
|
186
231
|
var state = this.state;
|
187
232
|
var finished;
|
188
233
|
|
@@ -214,7 +259,7 @@ describe('HttplibEmulation', function() {
|
|
214
259
|
});
|
215
260
|
});
|
216
261
|
|
217
|
-
|
262
|
+
specify("the request object emits readable events upon receiving data", function(done) {
|
218
263
|
var state = this.state;
|
219
264
|
var readable = 0;
|
220
265
|
state.req.on('readable', function() {
|
@@ -380,7 +425,6 @@ describe('HttplibEmulation', function() {
|
|
380
425
|
state.createSocket(function(serverSocket, client) {
|
381
426
|
state.req = HttplibEmulation.createIncomingMessage(
|
382
427
|
state.headers, serverSocket, "");
|
383
|
-
assert.ok(!state.req._mayHaveRequestBody);
|
384
428
|
callback();
|
385
429
|
});
|
386
430
|
}
|
@@ -488,4 +532,92 @@ describe('HttplibEmulation', function() {
|
|
488
532
|
});
|
489
533
|
});
|
490
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
|
+
});
|
491
623
|
});
|
data/test/node/spec_helper.js
CHANGED
@@ -46,6 +46,19 @@ var Helper = {
|
|
46
46
|
assert.fail("Something which should eventually happen never happened");
|
47
47
|
}
|
48
48
|
}, 10);
|
49
|
+
},
|
50
|
+
|
51
|
+
shouldNeverHappen: function(timeout, check, done) {
|
52
|
+
var startTime = new Date();
|
53
|
+
var id = setInterval(function() {
|
54
|
+
if (check()) {
|
55
|
+
clearInterval(id);
|
56
|
+
assert.fail("Something which should never happen, happened anyway");
|
57
|
+
} else if (new Date() - startTime > timeout) {
|
58
|
+
clearInterval(id);
|
59
|
+
done();
|
60
|
+
}
|
61
|
+
}, 10);
|
49
62
|
}
|
50
63
|
};
|
51
64
|
|
@@ -0,0 +1,125 @@
|
|
1
|
+
var fs = require('fs');
|
2
|
+
var url = require('url');
|
3
|
+
var express = require('express');
|
4
|
+
var app = express();
|
5
|
+
var bodyParser = express.bodyParser();
|
6
|
+
|
7
|
+
function textResponse(res, content) {
|
8
|
+
content = String(content);
|
9
|
+
res.setHeader("Content-Type", "text/plain");
|
10
|
+
res.setHeader("Content-Length", content.length);
|
11
|
+
res.end(content);
|
12
|
+
}
|
13
|
+
|
14
|
+
function fileExists(filename) {
|
15
|
+
try {
|
16
|
+
fs.statSync(filename);
|
17
|
+
return true;
|
18
|
+
} catch (e) {
|
19
|
+
return false;
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
if (process.env.PASSENGER_BASE_URI) {
|
24
|
+
app.use(process.env.PASSENGER_BASE_URI, app.router);
|
25
|
+
}
|
26
|
+
|
27
|
+
app.all('/', function(req, res) {
|
28
|
+
if (fileExists("front_page.txt")) {
|
29
|
+
textResponse(res, fs.readFileSync("front_page.txt"));
|
30
|
+
} else {
|
31
|
+
textResponse(res, "front page");
|
32
|
+
}
|
33
|
+
});
|
34
|
+
|
35
|
+
app.all('/parameters', function(req, res) {
|
36
|
+
bodyParser(req, res, function() {
|
37
|
+
var first = req.query.first || req.body.first;
|
38
|
+
var second = req.query.second || req.body.second;
|
39
|
+
textResponse(res, "Method: " + req.method + "\n" +
|
40
|
+
"First: " + first + "\n" +
|
41
|
+
"Second: " + second + "\n")
|
42
|
+
});
|
43
|
+
});
|
44
|
+
|
45
|
+
app.all('/chunked', function(req, res) {
|
46
|
+
res.setHeader("Content-Type", "text/plain");
|
47
|
+
res.setHeader("Transfer-Encoding", "chunked");
|
48
|
+
res.write("chunk1\n");
|
49
|
+
res.write("chunk2\n");
|
50
|
+
res.write("chunk3\n");
|
51
|
+
res.end();
|
52
|
+
});
|
53
|
+
|
54
|
+
app.all('/pid', function(req, res) {
|
55
|
+
textResponse(res, process.pid);
|
56
|
+
});
|
57
|
+
|
58
|
+
app.all(/^\/env/, function(req, res) {
|
59
|
+
var body = '';
|
60
|
+
var keys = [];
|
61
|
+
for (var key in req.cgiHeaders) {
|
62
|
+
keys.push(key);
|
63
|
+
}
|
64
|
+
keys.sort();
|
65
|
+
for (var i = 0; i < keys.length; i++) {
|
66
|
+
var val = req.cgiHeaders[keys[i]];
|
67
|
+
if (val === undefined) {
|
68
|
+
val = '';
|
69
|
+
}
|
70
|
+
body += keys[i] + " = " + val + "\n";
|
71
|
+
}
|
72
|
+
textResponse(res, body);
|
73
|
+
});
|
74
|
+
|
75
|
+
app.all('/touch_file', function(req, res) {
|
76
|
+
bodyParser(req, res, function() {
|
77
|
+
var filename = req.query.file || req.body.file;
|
78
|
+
fs.writeFileSync(filename, "");
|
79
|
+
textResponse(res, "ok")
|
80
|
+
});
|
81
|
+
});
|
82
|
+
|
83
|
+
app.all('/extra_header', function(req, res) {
|
84
|
+
res.setHeader("Content-Type", "text/html");
|
85
|
+
res.setHeader("Content-Length", "2");
|
86
|
+
res.setHeader("X-Foo", "Bar");
|
87
|
+
res.end("ok");
|
88
|
+
});
|
89
|
+
|
90
|
+
app.all('/cached', function(req, res) {
|
91
|
+
textResponse(res, "This is the uncached version of /cached");
|
92
|
+
});
|
93
|
+
|
94
|
+
app.all('/upload_with_params', function(req, res) {
|
95
|
+
bodyParser(req, res, function() {
|
96
|
+
var name1 = req.query.name1 || req.body.name1;
|
97
|
+
var name2 = req.query.name2 || req.body.name2;
|
98
|
+
var data = fs.readFileSync(req.files.data.path);
|
99
|
+
var body =
|
100
|
+
"name 1 = " + name1 + "\n" +
|
101
|
+
"name 2 = " + name2 + "\n" +
|
102
|
+
"data = ";
|
103
|
+
var bodyBuffer = new Buffer(body);
|
104
|
+
res.setHeader("Content-Type", "text/plain");
|
105
|
+
res.setHeader("Content-Length", bodyBuffer.length + data.length);
|
106
|
+
res.write(bodyBuffer);
|
107
|
+
res.write(data);
|
108
|
+
res.end();
|
109
|
+
});
|
110
|
+
});
|
111
|
+
|
112
|
+
app.all('/raw_upload_to_file', function(req, res) {
|
113
|
+
var filename = req.headers['x-output'];
|
114
|
+
var stream = fs.createWriteStream(filename);
|
115
|
+
req.on('data', function(data) {
|
116
|
+
stream.write(data);
|
117
|
+
});
|
118
|
+
req.on('end', function() {
|
119
|
+
stream.end(function() {
|
120
|
+
textResponse(res, "ok");
|
121
|
+
});
|
122
|
+
});
|
123
|
+
});
|
124
|
+
|
125
|
+
app.listen(3000);
|
File without changes
|
File without changes
|
data/test/stub/rack/config.ru
CHANGED
@@ -75,6 +75,25 @@ app = lambda do |env|
|
|
75
75
|
sleep 0.1 # Give HelperAgent the time to process stdout first.
|
76
76
|
STDERR.puts "hello stderr!"
|
77
77
|
text_response("ok")
|
78
|
+
when '/switch_protocol'
|
79
|
+
if env['HTTP_UPGRADE'] != 'raw' || env['HTTP_CONNECTION'].downcase != 'upgrade'
|
80
|
+
return [500, { "Content-Type" => "text/plain" }, ["Invalid headers"]]
|
81
|
+
end
|
82
|
+
env['rack.hijack'].call
|
83
|
+
io = env['rack.hijack_io']
|
84
|
+
begin
|
85
|
+
io.write("Status: 101 Switching Protocols\r\n")
|
86
|
+
io.write("Upgrade: raw\r\n")
|
87
|
+
io.write("Connection: Upgrade\r\n")
|
88
|
+
io.write("\r\n")
|
89
|
+
while !io.eof?
|
90
|
+
line = io.readline
|
91
|
+
io.write("Echo: #{line}")
|
92
|
+
io.flush
|
93
|
+
end
|
94
|
+
ensure
|
95
|
+
io.close
|
96
|
+
end
|
78
97
|
else
|
79
98
|
[404, { "Content-Type" => "text/plain" }, ["Unknown URI"]]
|
80
99
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import os, time, cgi
|
1
|
+
import os, sys, time, cgi
|
2
2
|
|
3
3
|
def file_exist(filename):
|
4
4
|
try:
|
@@ -7,6 +7,19 @@ def file_exist(filename):
|
|
7
7
|
except OSError:
|
8
8
|
return False
|
9
9
|
|
10
|
+
if sys.version_info[0] >= 3:
|
11
|
+
def bytes_to_str(b):
|
12
|
+
return b.decode()
|
13
|
+
|
14
|
+
def str_to_bytes(s):
|
15
|
+
return s.encode('latin-1')
|
16
|
+
else:
|
17
|
+
def bytes_to_str(b):
|
18
|
+
return b
|
19
|
+
|
20
|
+
def str_to_bytes(s):
|
21
|
+
return s
|
22
|
+
|
10
23
|
def application(env, start_response):
|
11
24
|
status = '200 OK'
|
12
25
|
body = None
|
@@ -131,6 +144,29 @@ def application(env, start_response):
|
|
131
144
|
elif path == '/oobw':
|
132
145
|
start_response(status, [('Content-Type', 'text/plain'), ('X-Passenger-Request-OOB-Work', 'true')])
|
133
146
|
return [str(os.getpid())]
|
147
|
+
elif path == '/switch_protocol':
|
148
|
+
if env['HTTP_UPGRADE'] != 'raw' or env['HTTP_CONNECTION'].lower() != 'upgrade':
|
149
|
+
status = '500 Internal Server Error'
|
150
|
+
body = str('Invalid headers')
|
151
|
+
start_response(status, [('Content-Type', 'text/plain'), ('Content-Length', len(body))])
|
152
|
+
return [body]
|
153
|
+
socket = env['passenger.hijack']()
|
154
|
+
io = socket.makefile()
|
155
|
+
socket.close()
|
156
|
+
try:
|
157
|
+
io.write(
|
158
|
+
b"HTTP/1.1 101 Switching Protocols\r\n" +
|
159
|
+
b"Upgrade: raw\r\n" +
|
160
|
+
b"Connection: Upgrade\r\n" +
|
161
|
+
b"\r\n")
|
162
|
+
io.flush()
|
163
|
+
line = io.readline()
|
164
|
+
while line != "":
|
165
|
+
io.write("Echo: " + line)
|
166
|
+
io.flush()
|
167
|
+
line = io.readline()
|
168
|
+
finally:
|
169
|
+
io.close()
|
134
170
|
else:
|
135
171
|
status = "404 Not Found"
|
136
172
|
body = "Unknown URI"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: passenger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.
|
4
|
+
version: 4.0.37
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Phusion - http://www.phusion.nl/
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-01-
|
11
|
+
date: 2014-01-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -2363,6 +2363,7 @@ files:
|
|
2363
2363
|
- lib/phusion_passenger/common_library.rb
|
2364
2364
|
- lib/phusion_passenger/config/about_command.rb
|
2365
2365
|
- lib/phusion_passenger/config/command.rb
|
2366
|
+
- lib/phusion_passenger/config/detach_process_command.rb
|
2366
2367
|
- lib/phusion_passenger/config/main.rb
|
2367
2368
|
- lib/phusion_passenger/config/restart_app_command.rb
|
2368
2369
|
- lib/phusion_passenger/config/utils.rb
|
@@ -2590,6 +2591,9 @@ files:
|
|
2590
2591
|
- test/stub/nginx/mime.types
|
2591
2592
|
- test/stub/nginx/nginx.conf.erb
|
2592
2593
|
- test/stub/nginx/win-utf
|
2594
|
+
- test/stub/node/app.js
|
2595
|
+
- test/stub/node/public/.gitignore
|
2596
|
+
- test/stub/node/tmp/.gitignore
|
2593
2597
|
- test/stub/rack/config.ru
|
2594
2598
|
- test/stub/rack/public/.gitignore
|
2595
2599
|
- test/stub/rack/start.rb
|