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.
- checksums.yaml +8 -8
- checksums.yaml.gz.asc +7 -7
- data.tar.gz.asc +7 -7
- data/.travis.yml +3 -0
- data/CHANGELOG +31 -0
- data/CONTRIBUTING.md +70 -10
- data/CONTRIBUTORS +4 -0
- data/README.md +1 -1
- data/Vagrantfile +50 -0
- data/bin/passenger-install-nginx-module +7 -2
- data/build/basics.rb +4 -1
- data/build/documentation.rb +6 -0
- data/build/node_tests.rb +7 -1
- data/build/packaging.rb +5 -0
- data/build/test_basics.rb +3 -3
- data/debian.template/copyright +1 -1
- data/debian.template/passenger.manpages +0 -1
- data/dev/rack.test/config.ru +5 -0
- data/dev/rack.test/public/asset.txt +1 -0
- data/dev/vagrant/apache_default_site.conf +35 -0
- data/dev/vagrant/apache_passenger.conf +5 -0
- data/dev/vagrant/apache_passenger.load +1 -0
- data/dev/vagrant/apache_ports.conf +24 -0
- data/dev/vagrant/apache_rack_test.conf +9 -0
- data/dev/vagrant/bashrc +21 -0
- data/dev/vagrant/nginx.conf +39 -0
- data/dev/vagrant/nginx_rakefile +34 -0
- data/dev/vagrant/nginx_start +32 -0
- data/dev/vagrant/provision.sh +115 -0
- data/dev/vagrant/sudoers.conf +5 -0
- data/doc/Design and Architecture.txt +515 -0
- data/doc/DeveloperQuickstart.md +70 -0
- data/doc/Users guide Apache.idmap.txt +24 -18
- data/doc/Users guide Apache.txt +200 -62
- data/doc/Users guide Nginx.idmap.txt +53 -45
- data/doc/Users guide Nginx.txt +501 -360
- data/doc/Users guide Standalone.txt +8 -0
- data/doc/images/direct_spawning.png +0 -0
- data/doc/images/direct_spawning.svg +16 -13
- data/doc/images/helper_agent_core_architecture.png +0 -0
- data/doc/images/passenger_architecture_overview.png +0 -0
- data/doc/images/smart_spawning.png +0 -0
- data/doc/images/{smart.svg → smart_spawning.svg} +23 -20
- data/doc/images/spawning_preparation_work.png +0 -0
- data/doc/images/startup_sequence.png +0 -0
- data/doc/users_guide_snippets/appendix_c_spawning_methods.txt +82 -121
- data/doc/users_guide_snippets/environment_variables.txt +1 -1
- data/doc/users_guide_snippets/support_information.txt +2 -0
- data/doc/users_guide_snippets/tips.txt +117 -9
- data/ext/apache2/Configuration.hpp +4 -2
- data/ext/apache2/ConfigurationCommands.cpp +14 -0
- data/ext/apache2/ConfigurationFields.hpp +4 -0
- data/ext/apache2/ConfigurationSetters.cpp +22 -0
- data/ext/apache2/CreateDirConfig.cpp +2 -0
- data/ext/apache2/Hooks.cpp +30 -14
- data/ext/apache2/MergeDirConfig.cpp +14 -0
- data/ext/apache2/SetHeaders.cpp +8 -0
- data/ext/common/ApplicationPool2/AppTypes.cpp +6 -1
- data/ext/common/ApplicationPool2/Implementation.cpp +1 -1
- data/ext/common/ApplicationPool2/Session.h +1 -1
- data/ext/common/Constants.h +9 -7
- data/ext/common/Utils/HttpHeaderBufferer.h +23 -4
- data/ext/common/Utils/StrIntUtils.h +35 -0
- data/ext/common/Utils/StringScanning.h +4 -10
- data/ext/common/agents/HelperAgent/RequestHandler.h +90 -49
- data/ext/nginx/CacheLocationConfig.c +40 -0
- data/ext/nginx/ConfigurationCommands.c +20 -0
- data/ext/nginx/ConfigurationFields.h +4 -0
- data/ext/nginx/ContentHandler.c +1 -1
- data/ext/nginx/CreateLocationConfig.c +9 -0
- data/ext/nginx/MergeLocationConfig.c +12 -0
- data/ext/nginx/config +2 -2
- data/ext/nginx/ngx_http_passenger_module.c +4 -4
- data/helper-scripts/node-loader.js +40 -27
- data/lib/phusion_passenger.rb +1 -1
- data/lib/phusion_passenger/apache2/config_options.rb +14 -2
- data/lib/phusion_passenger/constants.rb +7 -6
- data/lib/phusion_passenger/loader_shared_helpers.rb +11 -1
- data/lib/phusion_passenger/nginx/config_options.rb +8 -0
- data/lib/phusion_passenger/packaging.rb +8 -3
- data/lib/phusion_passenger/platform_info/apache.rb +3 -0
- data/lib/phusion_passenger/platform_info/ruby.rb +4 -1
- data/lib/phusion_passenger/standalone/command.rb +0 -1
- data/lib/phusion_passenger/standalone/package_runtime_command.rb +1 -0
- data/lib/phusion_passenger/standalone/start_command.rb +80 -62
- data/lib/phusion_passenger/standalone/status_command.rb +1 -0
- data/lib/phusion_passenger/standalone/stop_command.rb +1 -0
- data/man/passenger-config.1 +1 -1
- data/man/passenger-memory-stats.8 +1 -1
- data/man/passenger-status.8 +1 -1
- data/npm-shrinkwrap.json +229 -0
- data/package.json +28 -0
- data/resources/templates/standalone/config.erb +2 -0
- data/rpm/Vagrantfile +0 -3
- data/test/config.json.vagrant +30 -0
- data/test/cxx/HttpHeaderBuffererTest.cpp +64 -10
- data/test/cxx/RequestHandlerTest.cpp +35 -13
- data/test/integration_tests/apache2_tests.rb +1 -0
- data/test/stub/node/app.js +26 -18
- metadata +28 -13
- metadata.gz.asc +7 -7
- data/doc/Architectural overview.idmap.txt +0 -36
- data/doc/Architectural overview.txt +0 -410
- data/doc/images/smart.png +0 -0
- data/ext/common/ApplicationPool2/README.md +0 -56
- data/man/passenger-stress-test.1 +0 -43
- data/node_lib/phusion_passenger/httplib_emulation.js +0 -215
- data/node_lib/phusion_passenger/request_handler.js +0 -73
- data/node_lib/phusion_passenger/session_protocol_parser.js +0 -113
- data/test/node/httplib_emulation_spec.js +0 -623
data/doc/images/smart.png
DELETED
Binary file
|
@@ -1,56 +0,0 @@
|
|
1
|
-
# Overview
|
2
|
-
|
3
|
-
ApplicationPool2 is a subsystem in Phusion Passenger that takes care of
|
4
|
-
dynamically calculating how many processes are needed, spawning application
|
5
|
-
processes, shutting down processes, restarting processes, forwarding requests to
|
6
|
-
the right process, etc. Pretty much all important application process management
|
7
|
-
is encapculated in this subsystem.
|
8
|
-
|
9
|
-
It does not handle the actual request/response I/O with the application
|
10
|
-
processes: that's left to the caller of the ApplicationPool2 subsystem.
|
11
|
-
|
12
|
-
Here's a quick rundown of the available classes:
|
13
|
-
|
14
|
-
* Pool
|
15
|
-
This is the core of the subsystem. It contains high-level process management
|
16
|
-
logic but not the low-level details of spawning processes. The code is
|
17
|
-
further divided into the following classes, each of which contain the core
|
18
|
-
code managing its respective domain:
|
19
|
-
* SuperGroup
|
20
|
-
A logical collection of different applications. Can contain one or more
|
21
|
-
Groups. In the current version of Phusion Passenger, a SuperGroup only
|
22
|
-
contains exactly 1 Group.
|
23
|
-
* Group
|
24
|
-
Represents an application and can contains multiple processes, all
|
25
|
-
belonging to the same application.
|
26
|
-
* Process
|
27
|
-
Represents an OS process; an instance of a certain application. A process
|
28
|
-
may have multiple server sockets on which it listens. This is represented
|
29
|
-
by the `Socket` class:
|
30
|
-
* Socket
|
31
|
-
|
32
|
-
* Spawner
|
33
|
-
Encapsulates all low-level process spawning logic. Pool calls Spawner
|
34
|
-
whenever it needs to spawn another application process.
|
35
|
-
|
36
|
-
Spawner is an interface. There are multiple implementations that all
|
37
|
-
spawn processes in a different way. These are:
|
38
|
-
* DirectSpawner
|
39
|
-
* SmartSpawner
|
40
|
-
* DummySpawner
|
41
|
-
|
42
|
-
The spawn method is user-configurable. To avoid convoluting the Pool code
|
43
|
-
with spawner implementation selection logic, we have:
|
44
|
-
* SpawnerFactory
|
45
|
-
|
46
|
-
* Session
|
47
|
-
A session represents a single interaction with an application process, e.g.
|
48
|
-
a single request/response session.
|
49
|
-
|
50
|
-
* Options
|
51
|
-
A configuration object for the Pool::get() method.
|
52
|
-
|
53
|
-
The `Pool` class's `get` method is the main interface into the ApplicationPool2
|
54
|
-
subsystem. When an HTTP request comes in, call `Pool::get()` with the
|
55
|
-
appropriate arguments, and it will automatically spawn a process for you when
|
56
|
-
needed, open a session with that process and give you the session object.
|
data/man/passenger-stress-test.1
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
.TH "passenger-stress-test" "1" "2.0" "Phusion Passenger" "User Commands"
|
2
|
-
.SH "NAME"
|
3
|
-
.LP
|
4
|
-
passenger\-stress\-test \- stress tests a Phusion Passenger powered website.
|
5
|
-
.SH "SYNOPSIS"
|
6
|
-
.LP
|
7
|
-
\fBpassenger\-stress\-test\fR <\fIhostname\fR> <\fIapp_roo\fRt> [\fIoptions\fR]
|
8
|
-
.SH "DESCRIPTION"
|
9
|
-
.LP
|
10
|
-
Stress test the given (Phusion Passenger\-powered) website by
|
11
|
-
.LP
|
12
|
-
\- crawling it with multiple concurrently running crawlers.
|
13
|
-
.LP
|
14
|
-
\- gracefully restarting Apache at random times
|
15
|
-
.LP
|
16
|
-
\- restarting the target (Phusion Passenger\-powered) application at random times
|
17
|
-
.SH "OPTIONS"
|
18
|
-
.LP
|
19
|
-
.TP
|
20
|
-
\fB\-c, \-\-concurrency\fR <\fInumber\fR>
|
21
|
-
Number of crawlers to start (default = 20)
|
22
|
-
.TP
|
23
|
-
\fB\-p, \-\-apache\-restart\-interval\fR <\fIinterval\fR>
|
24
|
-
Gracefully restart Apache after <\fIinterval\fR> minutes (default = 1440)
|
25
|
-
.TP
|
26
|
-
\fB\-a, \-\-app\-restart\-interval\fR <\fIinterval\fR>
|
27
|
-
Restart the application after <\fIinterval\fR> minutes (default = 55)
|
28
|
-
.TP
|
29
|
-
\fB\-h, \-\-help\fR
|
30
|
-
Output help information and exit.
|
31
|
-
|
32
|
-
.SH "SEE ALSO"
|
33
|
-
.LP
|
34
|
-
passenger\-config(1), passenger\-memory\-stats(8), passenger\-status(8)
|
35
|
-
.LP
|
36
|
-
User guide at http://www.modrails.com/documentation.html
|
37
|
-
.SH "AUTHOR"
|
38
|
-
.LP
|
39
|
-
Phusion Passenger is written by Phusion (http://www.phusion.nl)
|
40
|
-
.LP
|
41
|
-
"Phusion" and "Phusion Passenger" are trademarks of Hongli Lai & Ninh Bui.
|
42
|
-
.LP
|
43
|
-
This manual page was written by Neil Wilson <neil@brightbox.co.uk> for the Ubuntu project (but may be used by others).
|
@@ -1,215 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2013-2014 Phusion
|
4
|
-
*
|
5
|
-
* "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
|
6
|
-
*
|
7
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
-
* of this software and associated documentation files (the "Software"), to deal
|
9
|
-
* in the Software without restriction, including without limitation the rights
|
10
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
-
* copies of the Software, and to permit persons to whom the Software is
|
12
|
-
* furnished to do so, subject to the following conditions:
|
13
|
-
*
|
14
|
-
* The above copyright notice and this permission notice shall be included in
|
15
|
-
* all copies or substantial portions of the Software.
|
16
|
-
*
|
17
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23
|
-
* THE SOFTWARE.
|
24
|
-
*/
|
25
|
-
|
26
|
-
/**
|
27
|
-
* Provides helper functions for emulating the http.Server API.
|
28
|
-
*/
|
29
|
-
|
30
|
-
var http = require('http');
|
31
|
-
|
32
|
-
const HTTP_HEADERS_WITHOUT_PREFIX = {
|
33
|
-
'CONTENT_LENGTH': true,
|
34
|
-
'CONTENT_TYPE': true
|
35
|
-
};
|
36
|
-
|
37
|
-
function cgiKeyToHttpHeader(key) {
|
38
|
-
if (HTTP_HEADERS_WITHOUT_PREFIX[key]) {
|
39
|
-
return key.toLowerCase().replace(/_/g, '-');
|
40
|
-
} else if (key.match(/^HTTP_/)) {
|
41
|
-
return key.replace(/^HTTP_/, '').toLowerCase().replace(/_/g, '-');
|
42
|
-
} else {
|
43
|
-
return undefined;
|
44
|
-
}
|
45
|
-
}
|
46
|
-
|
47
|
-
function setHttpHeaders(httpHeaders, cgiHeaders) {
|
48
|
-
for (var i = 0; i < cgiHeaders.keys.length; i++) {
|
49
|
-
var key = cgiHeaders.keys[i];
|
50
|
-
var httpHeader = cgiKeyToHttpHeader(key);
|
51
|
-
if (httpHeader !== undefined) {
|
52
|
-
httpHeaders[httpHeader] = cgiHeaders[key];
|
53
|
-
}
|
54
|
-
}
|
55
|
-
|
56
|
-
if (cgiHeaders['HTTPS']) {
|
57
|
-
httpHeaders['x-forwarded-proto'] = 'https';
|
58
|
-
}
|
59
|
-
if (!httpHeaders['x-forwarded-for']) {
|
60
|
-
httpHeaders['x-forwarded-for'] = cgiHeaders['REMOTE_ADDR'];
|
61
|
-
}
|
62
|
-
}
|
63
|
-
|
64
|
-
function inferHttpVersion(protocolDescription) {
|
65
|
-
var match = protocolDescription.match(/^HTTP\/(.+)/);
|
66
|
-
if (match) {
|
67
|
-
return match[1];
|
68
|
-
}
|
69
|
-
}
|
70
|
-
|
71
|
-
function createIncomingMessage(headers, socket, bodyBegin) {
|
72
|
-
/* Node's HTTP parser simulates an 'end' event if it determines that
|
73
|
-
* the request should not have a request body. Currently (Node 0.10.18),
|
74
|
-
* it thinks GET requests without an Upgrade header should not have a
|
75
|
-
* request body, even though technically such GET requests are allowed
|
76
|
-
* to have a request body. For compatibility reasons we implement the
|
77
|
-
* same behavior as Node's HTTP parser.
|
78
|
-
*/
|
79
|
-
|
80
|
-
var message = new http.IncomingMessage(socket);
|
81
|
-
setHttpHeaders(message.headers, headers);
|
82
|
-
message.cgiHeaders = headers;
|
83
|
-
message.httpVersion = inferHttpVersion(headers['SERVER_PROTOCOL']);
|
84
|
-
message.method = headers['REQUEST_METHOD'];
|
85
|
-
message.url = headers['REQUEST_URI'];
|
86
|
-
message.connection.remoteAddress = headers['REMOTE_ADDR'];
|
87
|
-
message.connection.remotePort = parseInt(headers['REMOTE_PORT']);
|
88
|
-
message.upgrade = !!headers['HTTP_UPGRADE'];
|
89
|
-
|
90
|
-
if (message.upgrade) {
|
91
|
-
// Emit end event as described above.
|
92
|
-
message.push(null);
|
93
|
-
return message;
|
94
|
-
}
|
95
|
-
|
96
|
-
message._emitEndEvent = IncomingMessage_emitEndEvent;
|
97
|
-
resetIncomingMessageOverridedMethods(message);
|
98
|
-
|
99
|
-
socket.on('end', function() {
|
100
|
-
message._emitEndEvent();
|
101
|
-
});
|
102
|
-
socket.on('drain', function() {
|
103
|
-
message.emit('drain');
|
104
|
-
});
|
105
|
-
socket.on('timeout', function() {
|
106
|
-
message.emit('timeout');
|
107
|
-
});
|
108
|
-
|
109
|
-
if (headers['REQUEST_METHOD'] != 'GET') {
|
110
|
-
if (bodyBegin.length > 0) {
|
111
|
-
message.push(bodyBegin);
|
112
|
-
}
|
113
|
-
socket.ondata = function(buffer, offset, end) {
|
114
|
-
if (!message.push(buffer.slice(offset, end))) {
|
115
|
-
socket._handle.readStop();
|
116
|
-
}
|
117
|
-
}
|
118
|
-
} else {
|
119
|
-
// Emit end event as described above.
|
120
|
-
message.push(null);
|
121
|
-
}
|
122
|
-
|
123
|
-
return message;
|
124
|
-
}
|
125
|
-
|
126
|
-
function IncomingMessage_pause() {
|
127
|
-
this._flowing = false;
|
128
|
-
this._orig_pause();
|
129
|
-
resetIncomingMessageOverridedMethods(this);
|
130
|
-
}
|
131
|
-
|
132
|
-
function IncomingMessage_resume() {
|
133
|
-
this._flowing = true;
|
134
|
-
this._orig_resume();
|
135
|
-
resetIncomingMessageOverridedMethods(this);
|
136
|
-
}
|
137
|
-
|
138
|
-
function IncomingMessage_on(event, listener) {
|
139
|
-
if (event == 'data') {
|
140
|
-
this._flowing = true;
|
141
|
-
installDataEventHandler(this);
|
142
|
-
} else if (event == 'readable') {
|
143
|
-
installReadableEventHandler(this);
|
144
|
-
}
|
145
|
-
this._orig_on.call(this, event, listener);
|
146
|
-
resetIncomingMessageOverridedMethods(this);
|
147
|
-
return this;
|
148
|
-
}
|
149
|
-
|
150
|
-
function IncomingMessage_emitEndEvent() {
|
151
|
-
if (!this._readableState.endEmitted) {
|
152
|
-
this._readableState.endEmitted = true;
|
153
|
-
this.emit('end');
|
154
|
-
}
|
155
|
-
}
|
156
|
-
|
157
|
-
/*
|
158
|
-
* Calling on(), pause() etc on the message object may cause our overrided
|
159
|
-
* methods to be set to something else. This is probably becaused by the code
|
160
|
-
* in Node.js responsible for switching a stream to flowing mode, e.g.
|
161
|
-
* emitDataEvents() in _stream_readable.js. Thus, this function
|
162
|
-
* should be called from on(), pause() etc.
|
163
|
-
*/
|
164
|
-
function resetIncomingMessageOverridedMethods(message) {
|
165
|
-
if (message.pause !== IncomingMessage_pause) {
|
166
|
-
message._orig_pause = message.pause;
|
167
|
-
message.pause = IncomingMessage_pause;
|
168
|
-
}
|
169
|
-
if (message.resume !== IncomingMessage_resume) {
|
170
|
-
message._orig_resume = message.resume;
|
171
|
-
message.resume = IncomingMessage_resume;
|
172
|
-
}
|
173
|
-
if (message.on !== IncomingMessage_on) {
|
174
|
-
message._orig_on = message.on;
|
175
|
-
message.on = IncomingMessage_on;
|
176
|
-
message.addListener = IncomingMessage_on;
|
177
|
-
}
|
178
|
-
}
|
179
|
-
|
180
|
-
function installDataEventHandler(message) {
|
181
|
-
if (!message._dataEventHandlerInstalled) {
|
182
|
-
message._dataEventHandlerInstalled = true;
|
183
|
-
message.socket.on('data', function(chunk) {
|
184
|
-
message.emit('data', chunk);
|
185
|
-
});
|
186
|
-
}
|
187
|
-
}
|
188
|
-
|
189
|
-
function installReadableEventHandler(message) {
|
190
|
-
if (!message._readableEventHandlerInstalled) {
|
191
|
-
message._readableEventHandlerInstalled = true;
|
192
|
-
message.socket.on('readable', function() {
|
193
|
-
message.emit('readable');
|
194
|
-
});
|
195
|
-
}
|
196
|
-
}
|
197
|
-
|
198
|
-
function createServerResponse(req) {
|
199
|
-
var res = new http.ServerResponse(req);
|
200
|
-
res.assignSocket(req.socket);
|
201
|
-
res.shouldKeepAlive = false;
|
202
|
-
req.socket.on('drain', function() {
|
203
|
-
res.emit('drain');
|
204
|
-
});
|
205
|
-
req.socket.on('timeout', function() {
|
206
|
-
res.emit('timeout');
|
207
|
-
});
|
208
|
-
res.once('finish', function() {
|
209
|
-
req.socket.destroySoon();
|
210
|
-
});
|
211
|
-
return res;
|
212
|
-
}
|
213
|
-
|
214
|
-
exports.createIncomingMessage = createIncomingMessage;
|
215
|
-
exports.createServerResponse = createServerResponse;
|
@@ -1,73 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2012-2013 Phusion
|
4
|
-
*
|
5
|
-
* "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
|
6
|
-
*
|
7
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
-
* of this software and associated documentation files (the "Software"), to deal
|
9
|
-
* in the Software without restriction, including without limitation the rights
|
10
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
-
* copies of the Software, and to permit persons to whom the Software is
|
12
|
-
* furnished to do so, subject to the following conditions:
|
13
|
-
*
|
14
|
-
* The above copyright notice and this permission notice shall be included in
|
15
|
-
* all copies or substantial portions of the Software.
|
16
|
-
*
|
17
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23
|
-
* THE SOFTWARE.
|
24
|
-
*/
|
25
|
-
|
26
|
-
var net = require('net');
|
27
|
-
var SessionProtocolParser = require('./session_protocol_parser').SessionProtocolParser;
|
28
|
-
|
29
|
-
/**
|
30
|
-
* Handles incoming Phusion Passenger requests and emits events.
|
31
|
-
*/
|
32
|
-
function RequestHandler(readyCallback, clientCallback) {
|
33
|
-
var self = this;
|
34
|
-
|
35
|
-
function handleNewClient(socket) {
|
36
|
-
var state = 'PARSING_HEADER';
|
37
|
-
var parser = new SessionProtocolParser();
|
38
|
-
|
39
|
-
function handleReadable() {
|
40
|
-
// read(n) returns null unless the buffer is at least n bytes.
|
41
|
-
// We just want to read whatever we can we poke into its buffer.
|
42
|
-
// Hope they don't change the this.
|
43
|
-
var len = socket._readableState.length;
|
44
|
-
handleData(socket.read(len));
|
45
|
-
}
|
46
|
-
|
47
|
-
function handleData(data) {
|
48
|
-
if (state == 'PARSING_HEADER') {
|
49
|
-
var consumed = parser.feed(data);
|
50
|
-
if (parser.state == SessionProtocolParser.SPP_DONE) {
|
51
|
-
state = 'HEADER_SEEN';
|
52
|
-
socket.removeListener('readable', handleReadable);
|
53
|
-
PhusionPassenger.emit('request', parser, socket, data.slice(consumed));
|
54
|
-
} else if (parser.state == SessionProtocolParser.SPP_ERROR) {
|
55
|
-
console.error('Header parse error');
|
56
|
-
socket.destroySoon();
|
57
|
-
}
|
58
|
-
} else {
|
59
|
-
// Do nothing.
|
60
|
-
}
|
61
|
-
}
|
62
|
-
|
63
|
-
socket.on('readable', handleReadable);
|
64
|
-
}
|
65
|
-
|
66
|
-
var server = net.createServer({ allowHalfOpen: true }, handleNewClient);
|
67
|
-
this.server = server;
|
68
|
-
server.listen(0, function() {
|
69
|
-
readyCallback(self);
|
70
|
-
});
|
71
|
-
}
|
72
|
-
|
73
|
-
exports.RequestHandler = RequestHandler;
|
@@ -1,113 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2012-2013 Phusion
|
4
|
-
*
|
5
|
-
* "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
|
6
|
-
*
|
7
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
-
* of this software and associated documentation files (the "Software"), to deal
|
9
|
-
* in the Software without restriction, including without limitation the rights
|
10
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
-
* copies of the Software, and to permit persons to whom the Software is
|
12
|
-
* furnished to do so, subject to the following conditions:
|
13
|
-
*
|
14
|
-
* The above copyright notice and this permission notice shall be included in
|
15
|
-
* all copies or substantial portions of the Software.
|
16
|
-
*
|
17
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23
|
-
* THE SOFTWARE.
|
24
|
-
*/
|
25
|
-
|
26
|
-
const SPP_PARSING_SIZE = SessionProtocolParser.SPP_PARSING_SIZE = 0;
|
27
|
-
const SPP_PARSING_HEADERS = SessionProtocolParser.SPP_PARSING_HEADERS = 1;
|
28
|
-
const SPP_DONE = SessionProtocolParser.SPP_DONE = 10;
|
29
|
-
const SPP_ERROR = SessionProtocolParser.SPP_ERROR = 11;
|
30
|
-
|
31
|
-
const ENCODING = 'binary';
|
32
|
-
|
33
|
-
function SessionProtocolParser() {
|
34
|
-
this.state = SPP_PARSING_SIZE;
|
35
|
-
this.processed = 0;
|
36
|
-
this.size = 0;
|
37
|
-
this.keys = [];
|
38
|
-
}
|
39
|
-
|
40
|
-
SessionProtocolParser.prototype.feed = function(buffer) {
|
41
|
-
var consumed = 0;
|
42
|
-
var locallyConsumed;
|
43
|
-
|
44
|
-
while (consumed < buffer.length && this.state != SPP_ERROR && this.state != SPP_DONE) {
|
45
|
-
switch (this.state) {
|
46
|
-
case SPP_PARSING_SIZE:
|
47
|
-
this.size += buffer[consumed] * Math.pow(256, 3 - this.processed);
|
48
|
-
locallyConsumed = 1;
|
49
|
-
this.processed++;
|
50
|
-
if (this.processed == 4) {
|
51
|
-
this.state = SPP_PARSING_HEADERS;
|
52
|
-
this.buffer = new Buffer(this.size);
|
53
|
-
this.processed = 0;
|
54
|
-
}
|
55
|
-
break;
|
56
|
-
|
57
|
-
case SPP_PARSING_HEADERS:
|
58
|
-
locallyConsumed = Math.min(buffer.length - consumed, this.buffer.length - this.processed);
|
59
|
-
buffer.copy(this.buffer, this.processed, consumed, consumed + locallyConsumed);
|
60
|
-
this.processed += locallyConsumed;
|
61
|
-
if (this.processed == this.buffer.length) {
|
62
|
-
this.state = SPP_DONE;
|
63
|
-
this.parse();
|
64
|
-
}
|
65
|
-
break;
|
66
|
-
|
67
|
-
default:
|
68
|
-
console.assert(false);
|
69
|
-
break;
|
70
|
-
}
|
71
|
-
|
72
|
-
consumed += locallyConsumed;
|
73
|
-
}
|
74
|
-
|
75
|
-
return consumed;
|
76
|
-
}
|
77
|
-
|
78
|
-
SessionProtocolParser.prototype.parse = function() {
|
79
|
-
function findZero(buffer, start) {
|
80
|
-
while (start < buffer.length) {
|
81
|
-
if (buffer[start] == 0) {
|
82
|
-
return start;
|
83
|
-
} else {
|
84
|
-
start++;
|
85
|
-
}
|
86
|
-
}
|
87
|
-
return -1;
|
88
|
-
}
|
89
|
-
|
90
|
-
var start = 0;
|
91
|
-
var key, value;
|
92
|
-
|
93
|
-
while (start < this.buffer.length) {
|
94
|
-
var keyEnd = findZero(this.buffer, start);
|
95
|
-
if (keyEnd != -1 && keyEnd + 1 < this.buffer.length) {
|
96
|
-
var valueStart = keyEnd + 1;
|
97
|
-
var valueEnd = findZero(this.buffer, valueStart);
|
98
|
-
if (valueEnd != -1) {
|
99
|
-
key = this.buffer.toString(ENCODING, start, keyEnd);
|
100
|
-
value = this.buffer.toString(ENCODING, valueStart, valueEnd);
|
101
|
-
start = valueEnd + 1;
|
102
|
-
this.keys.push(key);
|
103
|
-
this[key] = value;
|
104
|
-
} else {
|
105
|
-
start = this.buffer.length;
|
106
|
-
}
|
107
|
-
} else {
|
108
|
-
start = this.buffer.length;
|
109
|
-
}
|
110
|
-
}
|
111
|
-
}
|
112
|
-
|
113
|
-
exports.SessionProtocolParser = SessionProtocolParser;
|