passenger 4.0.27 → 4.0.28
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.
- data.tar.gz.asc +7 -7
- data/.gitignore +1 -0
- data/NEWS +22 -0
- data/build/preprocessor.rb +10 -0
- data/build/rpm.rb +74 -65
- data/debian.template/rules.template +8 -0
- data/dev/copy_boost_headers.rb +11 -2
- data/doc/Users guide Apache.idmap.txt +161 -145
- data/doc/Users guide Apache.txt +12 -1
- data/doc/Users guide Nginx.idmap.txt +142 -126
- data/doc/Users guide Nginx.txt +14 -1
- data/doc/Users guide Standalone.txt +1 -0
- data/doc/users_guide_snippets/environment_variables.txt +1 -1
- data/doc/users_guide_snippets/installation.txt +2 -0
- data/doc/users_guide_snippets/tips.txt +118 -0
- data/ext/apache2/Configuration.cpp +0 -6
- data/ext/apache2/Configuration.hpp +0 -5
- data/ext/apache2/ConfigurationCommands.cpp +7 -0
- data/ext/apache2/ConfigurationFields.hpp +2 -0
- data/ext/apache2/ConfigurationSetters.cpp +24 -0
- data/ext/apache2/CreateDirConfig.cpp +1 -0
- data/ext/apache2/Hooks.cpp +0 -1
- data/ext/apache2/MergeDirConfig.cpp +7 -0
- data/ext/apache2/SetHeaders.cpp +5 -1
- data/ext/boost/cregex.hpp +39 -0
- data/ext/boost/libs/regex/src/c_regex_traits.cpp +193 -0
- data/ext/boost/libs/regex/src/cpp_regex_traits.cpp +117 -0
- data/ext/boost/libs/regex/src/cregex.cpp +660 -0
- data/ext/boost/libs/regex/src/instances.cpp +32 -0
- data/ext/boost/libs/regex/src/internals.hpp +35 -0
- data/ext/boost/libs/regex/src/posix_api.cpp +296 -0
- data/ext/boost/libs/regex/src/regex.cpp +227 -0
- data/ext/boost/libs/regex/src/regex_debug.cpp +59 -0
- data/ext/boost/libs/regex/src/regex_raw_buffer.cpp +72 -0
- data/ext/boost/libs/regex/src/regex_traits_defaults.cpp +692 -0
- data/ext/boost/libs/regex/src/static_mutex.cpp +179 -0
- data/ext/boost/libs/regex/src/wc_regex_traits.cpp +301 -0
- data/ext/boost/libs/regex/src/wide_posix_api.cpp +315 -0
- data/ext/boost/libs/regex/src/winstances.cpp +35 -0
- data/ext/boost/regex.h +100 -0
- data/ext/boost/regex.hpp +37 -0
- data/ext/boost/regex/concepts.hpp +1128 -0
- data/ext/boost/regex/config.hpp +435 -0
- data/ext/boost/regex/config/borland.hpp +72 -0
- data/ext/boost/regex/config/cwchar.hpp +207 -0
- data/ext/boost/regex/mfc.hpp +190 -0
- data/ext/boost/regex/pattern_except.hpp +100 -0
- data/ext/boost/regex/pending/object_cache.hpp +165 -0
- data/ext/boost/regex/pending/static_mutex.hpp +179 -0
- data/ext/boost/regex/pending/unicode_iterator.hpp +776 -0
- data/ext/boost/regex/regex_traits.hpp +35 -0
- data/ext/boost/regex/user.hpp +93 -0
- data/ext/boost/regex/v4/basic_regex.hpp +782 -0
- data/ext/boost/regex/v4/basic_regex_creator.hpp +1571 -0
- data/ext/boost/regex/v4/basic_regex_parser.hpp +2874 -0
- data/ext/boost/regex/v4/c_regex_traits.hpp +211 -0
- data/ext/boost/regex/v4/char_regex_traits.hpp +81 -0
- data/ext/boost/regex/v4/cpp_regex_traits.hpp +1099 -0
- data/ext/boost/regex/v4/cregex.hpp +330 -0
- data/ext/boost/regex/v4/error_type.hpp +59 -0
- data/ext/boost/regex/v4/fileiter.hpp +455 -0
- data/ext/boost/regex/v4/instances.hpp +222 -0
- data/ext/boost/regex/v4/iterator_category.hpp +91 -0
- data/ext/boost/regex/v4/iterator_traits.hpp +135 -0
- data/ext/boost/regex/v4/match_flags.hpp +138 -0
- data/ext/boost/regex/v4/match_results.hpp +702 -0
- data/ext/boost/regex/v4/mem_block_cache.hpp +99 -0
- data/ext/boost/regex/v4/perl_matcher.hpp +587 -0
- data/ext/boost/regex/v4/perl_matcher_common.hpp +996 -0
- data/ext/boost/regex/v4/perl_matcher_non_recursive.hpp +1642 -0
- data/ext/boost/regex/v4/perl_matcher_recursive.hpp +991 -0
- data/ext/boost/regex/v4/primary_transform.hpp +146 -0
- data/ext/boost/regex/v4/protected_call.hpp +81 -0
- data/ext/boost/regex/v4/regbase.hpp +180 -0
- data/ext/boost/regex/v4/regex.hpp +202 -0
- data/ext/boost/regex/v4/regex_format.hpp +1156 -0
- data/ext/boost/regex/v4/regex_fwd.hpp +73 -0
- data/ext/boost/regex/v4/regex_grep.hpp +155 -0
- data/ext/boost/regex/v4/regex_iterator.hpp +201 -0
- data/ext/boost/regex/v4/regex_match.hpp +382 -0
- data/ext/boost/regex/v4/regex_merge.hpp +93 -0
- data/ext/boost/regex/v4/regex_raw_buffer.hpp +210 -0
- data/ext/boost/regex/v4/regex_replace.hpp +99 -0
- data/ext/boost/regex/v4/regex_search.hpp +217 -0
- data/ext/boost/regex/v4/regex_split.hpp +172 -0
- data/ext/boost/regex/v4/regex_token_iterator.hpp +342 -0
- data/ext/boost/regex/v4/regex_traits.hpp +189 -0
- data/ext/boost/regex/v4/regex_traits_defaults.hpp +371 -0
- data/ext/boost/regex/v4/regex_workaround.hpp +232 -0
- data/ext/boost/regex/v4/states.hpp +301 -0
- data/ext/boost/regex/v4/sub_match.hpp +512 -0
- data/ext/boost/regex/v4/syntax_type.hpp +105 -0
- data/ext/boost/regex/v4/u32regex_iterator.hpp +193 -0
- data/ext/boost/regex/v4/u32regex_token_iterator.hpp +377 -0
- data/ext/boost/regex/v4/w32_regex_traits.hpp +741 -0
- data/ext/boost/regex_fwd.hpp +33 -0
- data/ext/common/AgentsStarter.h +0 -11
- data/ext/common/ApplicationPool2/Common.h +1 -7
- data/ext/common/ApplicationPool2/DirectSpawner.h +3 -3
- data/ext/common/ApplicationPool2/Group.h +166 -69
- data/ext/common/ApplicationPool2/Implementation.cpp +55 -10
- data/ext/common/ApplicationPool2/Options.h +45 -10
- data/ext/common/ApplicationPool2/PipeWatcher.h +1 -2
- data/ext/common/ApplicationPool2/Pool.h +29 -7
- data/ext/common/ApplicationPool2/Process.h +22 -3
- data/ext/common/ApplicationPool2/Session.h +1 -0
- data/ext/common/ApplicationPool2/SmartSpawner.h +5 -10
- data/ext/common/ApplicationPool2/Spawner.h +10 -15
- data/ext/common/ApplicationPool2/SuperGroup.h +10 -9
- data/ext/common/Constants.h +1 -3
- data/ext/common/Hooks.h +193 -0
- data/ext/common/Logging.cpp +67 -2
- data/ext/common/Logging.h +23 -1
- data/ext/common/Utils.cpp +0 -21
- data/ext/common/Utils.h +0 -42
- data/ext/common/Utils/CachedFileStat.hpp +1 -1
- data/ext/common/Utils/StrIntUtils.h +61 -14
- data/ext/common/Utils/StringMap.h +4 -0
- data/ext/common/agents/HelperAgent/AgentOptions.h +4 -4
- data/ext/common/agents/HelperAgent/Main.cpp +2 -3
- data/ext/common/agents/HelperAgent/RequestHandler.h +65 -2
- data/ext/common/agents/LoggingAgent/FilterSupport.h +3 -1
- data/ext/common/agents/Watchdog/Main.cpp +8 -72
- data/ext/nginx/CacheLocationConfig.c +29 -1
- data/ext/nginx/Configuration.c +0 -12
- data/ext/nginx/Configuration.h +0 -1
- data/ext/nginx/ConfigurationCommands.c +10 -0
- data/ext/nginx/ConfigurationFields.h +2 -0
- data/ext/nginx/CreateLocationConfig.c +4 -0
- data/ext/nginx/MergeLocationConfig.c +6 -0
- data/ext/oxt/system_calls.cpp +7 -1
- data/ext/oxt/system_calls.hpp +7 -7
- data/helper-scripts/node-loader.js +6 -2
- data/helper-scripts/rack-loader.rb +5 -2
- data/helper-scripts/rack-preloader.rb +5 -2
- data/lib/phusion_passenger.rb +1 -1
- data/lib/phusion_passenger/apache2/config_options.rb +8 -0
- data/lib/phusion_passenger/constants.rb +0 -1
- data/lib/phusion_passenger/nginx/config_options.rb +9 -2
- data/lib/phusion_passenger/platform_info/apache.rb +2 -1
- data/lib/phusion_passenger/platform_info/compiler.rb +15 -1
- data/lib/phusion_passenger/platform_info/cxx_portability.rb +2 -0
- data/node_lib/phusion_passenger/httplib_emulation.js +85 -17
- data/node_lib/phusion_passenger/request_handler.js +10 -2
- data/rpm/Vagrantfile +32 -0
- data/rpm/get_distro_id.py +4 -0
- data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +2 -2
- data/test/cxx/ApplicationPool2/PoolTest.cpp +60 -9
- data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +2 -6
- data/test/cxx/CachedFileStatTest.cpp +5 -5
- data/test/cxx/RequestHandlerTest.cpp +3 -6
- data/test/cxx/UtilsTest.cpp +30 -0
- data/test/node/httplib_emulation_spec.js +491 -0
- data/test/node/spec_helper.js +25 -0
- metadata +78 -2
- metadata.gz.asc +7 -7
@@ -153,6 +153,8 @@ private
|
|
153
153
|
flags << "-DPASSENGER_DEBUG -DBOOST_DISABLE_ASSERTS"
|
154
154
|
|
155
155
|
if cc_or_cxx == :cxx
|
156
|
+
flags << cxx_11_flag if cxx_11_flag
|
157
|
+
|
156
158
|
# There are too many implementations of of the hash map!
|
157
159
|
# Figure out the right one.
|
158
160
|
check_unordered_map(flags, "std::unordered_map", "unordered_map", "HAS_UNORDERED_MAP") ||
|
@@ -81,15 +81,13 @@ function createIncomingMessage(headers, socket, bodyBegin) {
|
|
81
81
|
message.url = headers['REQUEST_URI'];
|
82
82
|
message.connection.remoteAddress = headers['REMOTE_ADDR'];
|
83
83
|
message.connection.remotePort = parseInt(headers['REMOTE_PORT']);
|
84
|
+
message._mayHaveRequestBody = mayHaveRequestBody(headers);
|
85
|
+
message._emitEndEvent = IncomingMessage_emitEndEvent;
|
86
|
+
resetIncomingMessageOverridedMethods(message);
|
84
87
|
|
85
|
-
function
|
86
|
-
message.
|
87
|
-
}
|
88
|
-
|
89
|
-
function onSocketEnd() {
|
90
|
-
message.emit('end');
|
91
|
-
}
|
92
|
-
|
88
|
+
socket.on('end', function() {
|
89
|
+
message._emitEndEvent();
|
90
|
+
});
|
93
91
|
socket.on('drain', function() {
|
94
92
|
message.emit('drain');
|
95
93
|
});
|
@@ -104,23 +102,93 @@ function createIncomingMessage(headers, socket, bodyBegin) {
|
|
104
102
|
* to have a request body. For compatibility reasons we implement the
|
105
103
|
* same behavior as Node's HTTP parser.
|
106
104
|
*/
|
107
|
-
if (
|
108
|
-
socket.on('data', onSocketData);
|
109
|
-
socket.on('end', onSocketEnd);
|
105
|
+
if (message._mayHaveRequestBody) {
|
110
106
|
if (bodyBegin.length > 0) {
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
107
|
+
message.push(bodyBegin);
|
108
|
+
}
|
109
|
+
socket.ondata = function(buffer, offset, end) {
|
110
|
+
if (!message.push(buffer.slice(offset, end))) {
|
111
|
+
socket._handle.readStop();
|
112
|
+
}
|
115
113
|
}
|
116
114
|
} else {
|
117
|
-
|
118
|
-
process.nextTick(onSocketEnd);
|
115
|
+
message.push(null);
|
119
116
|
}
|
120
117
|
|
121
118
|
return message;
|
122
119
|
}
|
123
120
|
|
121
|
+
function IncomingMessage_pause() {
|
122
|
+
this._flowing = false;
|
123
|
+
this._orig_pause();
|
124
|
+
resetIncomingMessageOverridedMethods(this);
|
125
|
+
}
|
126
|
+
|
127
|
+
function IncomingMessage_resume() {
|
128
|
+
this._flowing = true;
|
129
|
+
this._orig_resume();
|
130
|
+
resetIncomingMessageOverridedMethods(this);
|
131
|
+
}
|
132
|
+
|
133
|
+
function IncomingMessage_on(event, listener) {
|
134
|
+
if (event == 'data') {
|
135
|
+
this._flowing = true;
|
136
|
+
installDataEventHandler(this);
|
137
|
+
} else if (event == 'readable') {
|
138
|
+
installReadableEventHandler(this);
|
139
|
+
}
|
140
|
+
this._orig_on.call(this, event, listener);
|
141
|
+
resetIncomingMessageOverridedMethods(this);
|
142
|
+
}
|
143
|
+
|
144
|
+
function IncomingMessage_emitEndEvent() {
|
145
|
+
if (!this._readableState.endEmitted) {
|
146
|
+
this._readableState.endEmitted = true;
|
147
|
+
this.emit('end');
|
148
|
+
}
|
149
|
+
}
|
150
|
+
|
151
|
+
/*
|
152
|
+
* Calling on(), pause() etc on the message object may cause our overrided
|
153
|
+
* methods to be set to something else. This is probably becaused by the code
|
154
|
+
* in Node.js responsible for switching a stream to flowing mode, e.g.
|
155
|
+
* emitDataEvents() in _stream_readable.js. Thus, this function
|
156
|
+
* should be called from on(), pause() etc.
|
157
|
+
*/
|
158
|
+
function resetIncomingMessageOverridedMethods(message) {
|
159
|
+
if (message.pause !== IncomingMessage_pause) {
|
160
|
+
message._orig_pause = message.pause;
|
161
|
+
message.pause = IncomingMessage_pause;
|
162
|
+
}
|
163
|
+
if (message.resume !== IncomingMessage_resume) {
|
164
|
+
message._orig_resume = message.resume;
|
165
|
+
message.resume = IncomingMessage_resume;
|
166
|
+
}
|
167
|
+
if (message.on !== IncomingMessage_on) {
|
168
|
+
message._orig_on = message.on;
|
169
|
+
message.on = IncomingMessage_on;
|
170
|
+
message.addListener = IncomingMessage_on;
|
171
|
+
}
|
172
|
+
}
|
173
|
+
|
174
|
+
function installDataEventHandler(message) {
|
175
|
+
if (!message._dataEventHandlerInstalled) {
|
176
|
+
message._dataEventHandlerInstalled = true;
|
177
|
+
message.socket.on('data', function(chunk) {
|
178
|
+
message.emit('data', chunk);
|
179
|
+
});
|
180
|
+
}
|
181
|
+
}
|
182
|
+
|
183
|
+
function installReadableEventHandler(message) {
|
184
|
+
if (!message._readableEventHandlerInstalled) {
|
185
|
+
message._readableEventHandlerInstalled = true;
|
186
|
+
message.socket.on('readable', function() {
|
187
|
+
message.emit('readable');
|
188
|
+
});
|
189
|
+
}
|
190
|
+
}
|
191
|
+
|
124
192
|
function createServerResponse(req) {
|
125
193
|
var res = new http.ServerResponse(req);
|
126
194
|
res.assignSocket(req.socket);
|
@@ -36,12 +36,20 @@ function RequestHandler(readyCallback, clientCallback) {
|
|
36
36
|
var state = 'PARSING_HEADER';
|
37
37
|
var parser = new SessionProtocolParser();
|
38
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
|
+
|
39
47
|
function handleData(data) {
|
40
48
|
if (state == 'PARSING_HEADER') {
|
41
49
|
var consumed = parser.feed(data);
|
42
50
|
if (parser.state == SessionProtocolParser.SPP_DONE) {
|
43
51
|
state = 'HEADER_SEEN';
|
44
|
-
socket.removeListener('
|
52
|
+
socket.removeListener('readable', handleReadable);
|
45
53
|
PhusionPassenger.emit('request', parser, socket, data.slice(consumed));
|
46
54
|
} else if (parser.state == SessionProtocolParser.SPP_ERROR) {
|
47
55
|
console.error('Header parse error');
|
@@ -52,7 +60,7 @@ function RequestHandler(readyCallback, clientCallback) {
|
|
52
60
|
}
|
53
61
|
}
|
54
62
|
|
55
|
-
socket.on('
|
63
|
+
socket.on('readable', handleReadable);
|
56
64
|
}
|
57
65
|
|
58
66
|
var server = net.createServer({ allowHalfOpen: true }, handleNewClient);
|
data/rpm/Vagrantfile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
# vi: set ft=ruby :
|
3
|
+
|
4
|
+
# This Vagrantfile sets up a CentOS VM, for the purpose of RPM development.
|
5
|
+
|
6
|
+
ROOT = File.expand_path(File.dirname(__FILE__) + "/..")
|
7
|
+
|
8
|
+
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
|
9
|
+
VAGRANTFILE_API_VERSION = "2"
|
10
|
+
|
11
|
+
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
12
|
+
config.vm.box = "centos-6.4-x86_64"
|
13
|
+
config.vm.box_url = "http://developer.nrel.gov/downloads/vagrant-boxes/CentOS-6.4-x86_64-v20130731.box"
|
14
|
+
config.vm.synced_folder ROOT, "/vagrant"
|
15
|
+
config.ssh.forward_agent = true
|
16
|
+
|
17
|
+
config.vm.provider :vmware_fusion do |f, override|
|
18
|
+
override.vm.box_url = "https://dl.dropbox.com/u/5721940/vagrant-boxes/vagrant-centos-6.4-x86_64-vmware_fusion.box"
|
19
|
+
end
|
20
|
+
|
21
|
+
pkg_cmd = %Q{
|
22
|
+
rpm -Uvh http://mirror.overthewire.com.au/pub/epel/6/i386/epel-release-6-8.noarch.rpm &&
|
23
|
+
yum update -y &&
|
24
|
+
yum install -y @development-tools fedora-packager git sudo nano &&
|
25
|
+
yum install -y gcc gcc-c++ ccache curl-devel openssl-devel zlib-devel &&
|
26
|
+
yum install -y ruby ruby-devel rubygems rubygem-rake httpd httpd-devel apr-devel apr-util-devel &&
|
27
|
+
usermod -a -G mock vagrant &&
|
28
|
+
sed -i 's/Defaults requiretty//' /etc/sudoers &&
|
29
|
+
sudo -u vagrant -H rpmdev-setuptree
|
30
|
+
}
|
31
|
+
config.vm.provision :shell, :inline => pkg_cmd
|
32
|
+
end
|
@@ -22,10 +22,12 @@ namespace tut {
|
|
22
22
|
PipeWatcher::onData = PipeWatcher::DataCallback();
|
23
23
|
gatherOutput = boost::bind(&ApplicationPool2_DirectSpawnerTest::_gatherOutput, this, _1, _2);
|
24
24
|
setLogLevel(LVL_ERROR); // TODO: change to LVL_WARN
|
25
|
+
setPrintAppOutputAsDebuggingMessages(true);
|
25
26
|
}
|
26
27
|
|
27
28
|
~ApplicationPool2_DirectSpawnerTest() {
|
28
29
|
setLogLevel(DEFAULT_LOG_LEVEL);
|
30
|
+
setPrintAppOutputAsDebuggingMessages(false);
|
29
31
|
unlink("stub/wsgi/passenger_wsgi.pyc");
|
30
32
|
PipeWatcher::onData = PipeWatcher::DataCallback();
|
31
33
|
}
|
@@ -63,7 +65,6 @@ namespace tut {
|
|
63
65
|
options.startTimeout = 300;
|
64
66
|
|
65
67
|
DirectSpawner spawner(bg.safe, *resourceLocator, generation);
|
66
|
-
spawner.getConfig()->forwardStderr = false;
|
67
68
|
|
68
69
|
try {
|
69
70
|
process = spawner.spawn(options);
|
@@ -86,7 +87,6 @@ namespace tut {
|
|
86
87
|
options.startupFile = ".";
|
87
88
|
|
88
89
|
DirectSpawner spawner(bg.safe, *resourceLocator, generation);
|
89
|
-
spawner.getConfig()->forwardStderr = false;
|
90
90
|
|
91
91
|
try {
|
92
92
|
process = spawner.spawn(options);
|
@@ -37,11 +37,12 @@ namespace tut {
|
|
37
37
|
spawnerConfig = boost::make_shared<SpawnerConfig>();
|
38
38
|
spawnerFactory = boost::make_shared<SpawnerFactory>(bg.safe, *resourceLocator,
|
39
39
|
generation, spawnerConfig);
|
40
|
-
pool = boost::make_shared<Pool>(
|
40
|
+
pool = boost::make_shared<Pool>(spawnerFactory);
|
41
41
|
pool->initialize();
|
42
42
|
bg.start();
|
43
43
|
callback = boost::bind(&ApplicationPool2_PoolTest::_callback, this, _1, _2);
|
44
44
|
setLogLevel(LVL_ERROR); // TODO: change to LVL_WARN
|
45
|
+
setPrintAppOutputAsDebuggingMessages(true);
|
45
46
|
}
|
46
47
|
|
47
48
|
~ApplicationPool2_PoolTest() {
|
@@ -55,6 +56,7 @@ namespace tut {
|
|
55
56
|
UPDATE_TRACE_POINT();
|
56
57
|
pool.reset();
|
57
58
|
setLogLevel(DEFAULT_LOG_LEVEL);
|
59
|
+
setPrintAppOutputAsDebuggingMessages(false);
|
58
60
|
SystemTime::releaseAll();
|
59
61
|
}
|
60
62
|
|
@@ -468,7 +470,7 @@ namespace tut {
|
|
468
470
|
pool->superGroups.get("test")->groups[0]->getWaitlist.size(), 1u);
|
469
471
|
|
470
472
|
// Close an existing session so that one process is no
|
471
|
-
// longer at full
|
473
|
+
// longer at full utilization.
|
472
474
|
sessions[0].reset();
|
473
475
|
ensure_equals("The get request has been removed from the wait list",
|
474
476
|
pool->superGroups.get("test")->groups[0]->getWaitlist.size(), 0u);
|
@@ -476,11 +478,11 @@ namespace tut {
|
|
476
478
|
}
|
477
479
|
|
478
480
|
TEST_METHOD(10) {
|
479
|
-
// If multiple matching processes exist, and all of them are at full
|
481
|
+
// If multiple matching processes exist, and all of them are at full utilization,
|
480
482
|
// and a new process may be spawned,
|
481
483
|
// then asyncGet() will put the action on the group's wait queue and spawn the
|
482
484
|
// new process.
|
483
|
-
// The process that first becomes not at full
|
485
|
+
// The process that first becomes not at full utilization
|
484
486
|
// or the newly spawned process
|
485
487
|
// will process the action, whichever is earlier.
|
486
488
|
// Here we test the case where an existing process is earlier.
|
@@ -1316,7 +1318,6 @@ namespace tut {
|
|
1316
1318
|
options.appRoot = "tmp.wsgi";
|
1317
1319
|
options.appType = "wsgi";
|
1318
1320
|
options.spawnMethod = "direct";
|
1319
|
-
spawnerConfig->forwardStderr = false;
|
1320
1321
|
|
1321
1322
|
writeFile("tmp.wsgi/passenger_wsgi.py",
|
1322
1323
|
"import sys\n"
|
@@ -1342,7 +1343,6 @@ namespace tut {
|
|
1342
1343
|
options.appType = "wsgi";
|
1343
1344
|
options.spawnMethod = "direct";
|
1344
1345
|
options.minProcesses = 4;
|
1345
|
-
spawnerConfig->forwardStderr = false;
|
1346
1346
|
|
1347
1347
|
writeFile("tmp.wsgi/counter", "0");
|
1348
1348
|
chmod("tmp.wsgi/counter", 0666);
|
@@ -1547,7 +1547,6 @@ namespace tut {
|
|
1547
1547
|
options.appRoot = "tmp.wsgi";
|
1548
1548
|
options.appType = "wsgi";
|
1549
1549
|
options.spawnMethod = "direct";
|
1550
|
-
spawnerConfig->forwardStderr = false;
|
1551
1550
|
pool->setMax(1);
|
1552
1551
|
|
1553
1552
|
writeFile("tmp.wsgi/passenger_wsgi.py",
|
@@ -1598,7 +1597,6 @@ namespace tut {
|
|
1598
1597
|
options.appType = "wsgi";
|
1599
1598
|
options.spawnMethod = "direct";
|
1600
1599
|
options.minProcesses = 2;
|
1601
|
-
spawnerConfig->forwardStderr = false;
|
1602
1600
|
|
1603
1601
|
// Spawn 2 processes.
|
1604
1602
|
retainSessions = true;
|
@@ -1722,6 +1720,59 @@ namespace tut {
|
|
1722
1720
|
debug->debugger->recv("Restarting aborted");
|
1723
1721
|
}
|
1724
1722
|
|
1723
|
+
TEST_METHOD(79) {
|
1724
|
+
// Test sticky sessions.
|
1725
|
+
|
1726
|
+
// Spawn 2 processes and get their sticky session IDs and PIDs.
|
1727
|
+
ensureMinProcesses(2);
|
1728
|
+
Options options = createOptions();
|
1729
|
+
SessionPtr session1 = pool->get(options, &ticket);
|
1730
|
+
SessionPtr session2 = pool->get(options, &ticket);
|
1731
|
+
int id1 = session1->getStickySessionId();
|
1732
|
+
int id2 = session2->getStickySessionId();
|
1733
|
+
pid_t pid1 = session1->getPid();
|
1734
|
+
pid_t pid2 = session2->getPid();
|
1735
|
+
session1.reset();
|
1736
|
+
session2.reset();
|
1737
|
+
|
1738
|
+
// Make two requests with id1 as sticky session ID. They should
|
1739
|
+
// both go to process pid1.
|
1740
|
+
options.stickySessionId = id1;
|
1741
|
+
session1 = pool->get(options, &ticket);
|
1742
|
+
ensure_equals("Request 1.1 goes to process 1", session1->getPid(), pid1);
|
1743
|
+
// The second request should be queued, and should not finish until
|
1744
|
+
// the first request is finished.
|
1745
|
+
ensure_equals(number, 1);
|
1746
|
+
pool->asyncGet(options, callback);
|
1747
|
+
SHOULD_NEVER_HAPPEN(100,
|
1748
|
+
result = number > 1;
|
1749
|
+
);
|
1750
|
+
session1.reset();
|
1751
|
+
EVENTUALLY(1,
|
1752
|
+
result = number == 2;
|
1753
|
+
);
|
1754
|
+
ensure_equals("Request 1.2 goes to process 1", currentSession->getPid(), pid1);
|
1755
|
+
currentSession.reset();
|
1756
|
+
|
1757
|
+
// Make two requests with id2 as sticky session ID. They should
|
1758
|
+
// both go to process pid2.
|
1759
|
+
options.stickySessionId = id2;
|
1760
|
+
session1 = pool->get(options, &ticket);
|
1761
|
+
ensure_equals("Request 2.1 goes to process 2", session1->getPid(), pid2);
|
1762
|
+
// The second request should be queued, and should not finish until
|
1763
|
+
// the first request is finished.
|
1764
|
+
pool->asyncGet(options, callback);
|
1765
|
+
SHOULD_NEVER_HAPPEN(100,
|
1766
|
+
result = number > 2;
|
1767
|
+
);
|
1768
|
+
session1.reset();
|
1769
|
+
EVENTUALLY(1,
|
1770
|
+
result = number == 3;
|
1771
|
+
);
|
1772
|
+
ensure_equals("Request 2.2 goes to process 2", currentSession->getPid(), pid2);
|
1773
|
+
currentSession.reset();
|
1774
|
+
}
|
1775
|
+
|
1725
1776
|
// TODO: Persistent connections.
|
1726
1777
|
// TODO: If one closes the session before it has reached EOF, and process's maximum concurrency
|
1727
1778
|
// has already been reached, then the pool should ping the process so that it can detect
|
@@ -1730,7 +1781,7 @@ namespace tut {
|
|
1730
1781
|
|
1731
1782
|
/*********** Test previously discovered bugs ***********/
|
1732
1783
|
|
1733
|
-
TEST_METHOD(
|
1784
|
+
TEST_METHOD(85) {
|
1734
1785
|
// Test detaching, then restarting. This should not violate any invariants.
|
1735
1786
|
TempDirCopy dir("stub/wsgi", "tmp.wsgi");
|
1736
1787
|
Options options = createOptions();
|
@@ -27,10 +27,12 @@ namespace tut {
|
|
27
27
|
PipeWatcher::onData = PipeWatcher::DataCallback();
|
28
28
|
gatherOutput = boost::bind(&ApplicationPool2_SmartSpawnerTest::_gatherOutput, this, _1, _2);
|
29
29
|
setLogLevel(LVL_ERROR); // TODO: should be LVL_WARN
|
30
|
+
setPrintAppOutputAsDebuggingMessages(true);
|
30
31
|
}
|
31
32
|
|
32
33
|
~ApplicationPool2_SmartSpawnerTest() {
|
33
34
|
setLogLevel(DEFAULT_LOG_LEVEL);
|
35
|
+
setPrintAppOutputAsDebuggingMessages(false);
|
34
36
|
unlink("stub/wsgi/passenger_wsgi.pyc");
|
35
37
|
PipeWatcher::onData = PipeWatcher::DataCallback();
|
36
38
|
}
|
@@ -128,8 +130,6 @@ namespace tut {
|
|
128
130
|
generation,
|
129
131
|
preloaderCommand,
|
130
132
|
options);
|
131
|
-
spawner.getConfig()->forwardStdout = false;
|
132
|
-
spawner.getConfig()->forwardStderr = false;
|
133
133
|
|
134
134
|
try {
|
135
135
|
process = spawner.spawn(options);
|
@@ -160,8 +160,6 @@ namespace tut {
|
|
160
160
|
generation,
|
161
161
|
preloaderCommand,
|
162
162
|
options);
|
163
|
-
spawner.getConfig()->forwardStdout = false;
|
164
|
-
spawner.getConfig()->forwardStderr = false;
|
165
163
|
|
166
164
|
try {
|
167
165
|
process = spawner.spawn(options);
|
@@ -192,8 +190,6 @@ namespace tut {
|
|
192
190
|
generation,
|
193
191
|
preloaderCommand,
|
194
192
|
options);
|
195
|
-
spawner.getConfig()->forwardStdout = false;
|
196
|
-
spawner.getConfig()->forwardStderr = false;
|
197
193
|
|
198
194
|
try {
|
199
195
|
process = spawner.spawn(options);
|
@@ -393,10 +393,10 @@ namespace tut {
|
|
393
393
|
stat.stat("test4.txt", &buf, 1);
|
394
394
|
stat.stat("test5.txt", &buf, 1);
|
395
395
|
stat.setMaxSize(2);
|
396
|
-
ensure(!stat.knows("test.txt"));
|
397
|
-
ensure(!stat.knows("test2.txt"));
|
398
|
-
ensure(!stat.knows("test3.txt"));
|
399
|
-
ensure(stat.knows("test4.txt"));
|
400
|
-
ensure(stat.knows("test5.txt"));
|
396
|
+
ensure("(1)", !stat.knows("test.txt"));
|
397
|
+
ensure("(2)", !stat.knows("test2.txt"));
|
398
|
+
ensure("(3)", !stat.knows("test3.txt"));
|
399
|
+
ensure("(4)", stat.knows("test4.txt"));
|
400
|
+
ensure("(5)", stat.knows("test5.txt"));
|
401
401
|
}
|
402
402
|
}
|
@@ -42,12 +42,13 @@ namespace tut {
|
|
42
42
|
RequestHandlerTest() {
|
43
43
|
createServerInstanceDirAndGeneration(serverInstanceDir, generation);
|
44
44
|
spawnerFactory = boost::make_shared<SpawnerFactory>(bg.safe, *resourceLocator, generation);
|
45
|
-
pool = boost::make_shared<Pool>(
|
45
|
+
pool = boost::make_shared<Pool>(spawnerFactory);
|
46
46
|
pool->initialize();
|
47
47
|
serverFilename = generation->getPath() + "/server";
|
48
48
|
requestSocket = createUnixServer(serverFilename);
|
49
49
|
setNonBlocking(requestSocket);
|
50
50
|
setLogLevel(LVL_ERROR); // TODO: set to LVL_WARN
|
51
|
+
setPrintAppOutputAsDebuggingMessages(true);
|
51
52
|
|
52
53
|
agentOptions.passengerRoot = resourceLocator->getRoot();
|
53
54
|
agentOptions.defaultUser = testConfig["default_user"].asString();
|
@@ -63,6 +64,7 @@ namespace tut {
|
|
63
64
|
|
64
65
|
~RequestHandlerTest() {
|
65
66
|
setLogLevel(DEFAULT_LOG_LEVEL);
|
67
|
+
setPrintAppOutputAsDebuggingMessages(false);
|
66
68
|
if (bg.isStarted()) {
|
67
69
|
bg.safe->runSync(boost::bind(&RequestHandlerTest::destroy, this));
|
68
70
|
} else {
|
@@ -332,7 +334,6 @@ namespace tut {
|
|
332
334
|
"STDERR.puts 'I have failed'");
|
333
335
|
|
334
336
|
setLogLevel(-2);
|
335
|
-
spawnerFactory->getConfig()->forwardStderr = false;
|
336
337
|
init();
|
337
338
|
connect();
|
338
339
|
sendHeaders(defaultHeaders,
|
@@ -357,7 +358,6 @@ namespace tut {
|
|
357
358
|
"STDERR.puts 'I have failed'\n");
|
358
359
|
|
359
360
|
setLogLevel(-2);
|
360
|
-
spawnerFactory->getConfig()->forwardStderr = false;
|
361
361
|
init();
|
362
362
|
connect();
|
363
363
|
sendHeaders(defaultHeaders,
|
@@ -380,7 +380,6 @@ namespace tut {
|
|
380
380
|
writeFile("tmp.handler/start.rb", "");
|
381
381
|
|
382
382
|
setLogLevel(-2);
|
383
|
-
spawnerFactory->getConfig()->forwardStderr = false;
|
384
383
|
init();
|
385
384
|
connect();
|
386
385
|
sendHeaders(defaultHeaders,
|
@@ -408,7 +407,6 @@ namespace tut {
|
|
408
407
|
"STDERR.puts 'I have failed'");
|
409
408
|
|
410
409
|
setLogLevel(-2);
|
411
|
-
spawnerFactory->getConfig()->forwardStderr = false;
|
412
410
|
init();
|
413
411
|
connect();
|
414
412
|
sendHeaders(defaultHeaders,
|
@@ -434,7 +432,6 @@ namespace tut {
|
|
434
432
|
"STDERR.puts 'I have failed'\n");
|
435
433
|
|
436
434
|
setLogLevel(-2);
|
437
|
-
spawnerFactory->getConfig()->forwardStderr = false;
|
438
435
|
init();
|
439
436
|
connect();
|
440
437
|
sendHeaders(defaultHeaders,
|