passenger 3.9.2.beta → 4.0.0.rc4
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/.travis.yml +3 -0
- data/NEWS +77 -7
- data/README.md +3 -11
- data/bin/passenger-install-apache2-module +24 -20
- data/bin/passenger-install-nginx-module +25 -23
- data/build/agents.rb +11 -0
- data/build/apache2.rb +9 -5
- data/build/basics.rb +37 -30
- data/build/common_library.rb +4 -1
- data/build/cplusplus_support.rb +5 -5
- data/build/cxx_tests.rb +28 -8
- data/build/integration_tests.rb +6 -3
- data/build/nginx.rb +3 -3
- data/build/packaging.rb +95 -57
- data/build/ruby_extension.rb +34 -21
- data/build/ruby_tests.rb +4 -2
- data/build/test_basics.rb +1 -1
- data/dev/run_travis.sh +36 -1
- data/doc/Users guide Apache.html +425 -308
- data/doc/Users guide Apache.idmap.txt +78 -70
- data/doc/Users guide Apache.index.sqlite3 +0 -0
- data/doc/Users guide Apache.txt +33 -92
- data/doc/Users guide Nginx.html +519 -220
- data/doc/Users guide Nginx.idmap.txt +78 -60
- data/doc/Users guide Nginx.txt +115 -26
- data/doc/Users guide Standalone.html +8 -2
- data/doc/users_guide_snippets/analysis_and_system_maintenance.txt +1 -7
- data/doc/users_guide_snippets/installation.txt +167 -22
- data/doc/users_guide_snippets/rackup_specifications.txt +4 -0
- data/doc/users_guide_snippets/since_version.txt +1 -0
- data/doc/users_guide_snippets/support_information.txt +3 -7
- data/doc/users_guide_snippets/tips.txt +0 -24
- data/ext/apache2/Configuration.cpp +11 -33
- data/ext/apache2/Configuration.hpp +3 -18
- data/ext/apache2/DirectoryMapper.h +20 -70
- data/ext/apache2/Hooks.cpp +2 -2
- data/ext/common/AgentsStarter.cpp +0 -2
- data/ext/common/AgentsStarter.h +0 -1
- data/ext/common/AgentsStarter.hpp +1 -3
- data/ext/common/ApplicationPool2/AppTypes.cpp +74 -0
- data/ext/common/ApplicationPool2/AppTypes.h +202 -0
- data/ext/common/ApplicationPool2/Common.h +12 -10
- data/ext/common/ApplicationPool2/DirectSpawner.h +256 -0
- data/ext/common/ApplicationPool2/DummySpawner.h +90 -0
- data/ext/common/ApplicationPool2/Group.h +311 -94
- data/ext/common/ApplicationPool2/Implementation.cpp +405 -145
- data/ext/common/ApplicationPool2/Options.h +24 -26
- data/ext/common/ApplicationPool2/PipeWatcher.h +20 -13
- data/ext/common/ApplicationPool2/Pool.h +326 -183
- data/ext/common/ApplicationPool2/Process.h +205 -55
- data/ext/common/ApplicationPool2/README.md +1 -1
- data/ext/common/ApplicationPool2/Session.h +21 -10
- data/ext/common/ApplicationPool2/SmartSpawner.h +801 -0
- data/ext/common/ApplicationPool2/Spawner.h +141 -1149
- data/ext/common/ApplicationPool2/SpawnerFactory.h +132 -0
- data/ext/common/ApplicationPool2/SuperGroup.h +146 -223
- data/ext/common/Constants.h +4 -2
- data/ext/common/Exceptions.h +23 -1
- data/ext/common/Logging.cpp +17 -6
- data/ext/common/Logging.h +37 -7
- data/ext/common/ResourceLocator.h +1 -1
- data/ext/common/Utils.cpp +49 -1
- data/ext/common/Utils.h +13 -4
- data/ext/common/{AnsiColorConstants.h → Utils/AnsiColorConstants.h} +0 -0
- data/ext/common/{BCrypt.cpp → Utils/BCrypt.cpp} +0 -0
- data/ext/common/{BCrypt.h → Utils/BCrypt.h} +0 -0
- data/ext/common/{Blowfish.c → Utils/Blowfish.c} +0 -0
- data/ext/common/{Blowfish.h → Utils/Blowfish.h} +0 -0
- data/ext/common/Utils/CachedFileStat.hpp +27 -25
- data/ext/common/Utils/Curl.h +184 -0
- data/ext/common/{HttpConstants.h → Utils/HttpConstants.h} +3 -0
- data/ext/common/Utils/IOUtils.cpp +6 -2
- data/ext/common/{IniFile.h → Utils/IniFile.h} +0 -0
- data/ext/common/Utils/LargeFiles.cpp +30 -0
- data/ext/common/Utils/LargeFiles.h +40 -0
- data/ext/common/Utils/StrIntUtils.cpp +72 -8
- data/ext/common/Utils/StrIntUtils.h +24 -2
- data/ext/common/Utils/StringMap.h +12 -2
- data/ext/common/Utils/VariantMap.h +51 -2
- data/ext/common/Utils/jsoncpp.cpp +1 -1
- data/ext/common/agents/Base.cpp +147 -11
- data/ext/common/agents/HelperAgent/AgentOptions.h +14 -6
- data/ext/common/agents/HelperAgent/Main.cpp +79 -19
- data/ext/common/agents/HelperAgent/RequestHandler.h +36 -16
- data/ext/common/agents/LoggingAgent/LoggingServer.h +3 -5
- data/ext/common/agents/LoggingAgent/Main.cpp +2 -4
- data/ext/common/agents/LoggingAgent/RemoteSender.h +18 -24
- data/ext/common/agents/SpawnPreparer.cpp +7 -0
- data/ext/common/agents/Watchdog/Main.cpp +96 -38
- data/ext/nginx/Configuration.c +26 -22
- data/ext/nginx/Configuration.h +4 -2
- data/ext/nginx/ContentHandler.c +23 -52
- data/ext/nginx/ContentHandler.h +5 -11
- data/ext/nginx/config +10 -3
- data/ext/nginx/ngx_http_passenger_module.c +21 -6
- data/ext/nginx/ngx_http_passenger_module.h +4 -1
- data/ext/oxt/dynamic_thread_group.hpp +9 -1
- data/ext/oxt/system_calls.cpp +2 -2
- data/ext/ruby/extconf.rb +2 -1
- data/helper-scripts/backtrace-sanitizer.rb +2 -0
- data/helper-scripts/wsgi-loader.py +54 -21
- data/lib/phusion_passenger.rb +5 -3
- data/lib/phusion_passenger/abstract_installer.rb +18 -41
- data/lib/phusion_passenger/admin_tools/memory_stats.rb +2 -2
- data/lib/phusion_passenger/admin_tools/server_instance.rb +2 -2
- data/lib/phusion_passenger/common_library.rb +23 -3
- data/lib/phusion_passenger/debug_logging.rb +10 -3
- data/lib/phusion_passenger/packaging.rb +1 -0
- data/lib/phusion_passenger/platform_info.rb +113 -115
- data/lib/phusion_passenger/platform_info/compiler.rb +224 -134
- data/lib/phusion_passenger/platform_info/cxx_portability.rb +143 -0
- data/lib/phusion_passenger/platform_info/depcheck.rb +371 -0
- data/lib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +124 -0
- data/lib/phusion_passenger/platform_info/depcheck_specs/compiler_toolchain.rb +97 -0
- data/lib/phusion_passenger/platform_info/depcheck_specs/gems.rb +39 -0
- data/lib/phusion_passenger/platform_info/depcheck_specs/libs.rb +118 -0
- data/lib/phusion_passenger/platform_info/depcheck_specs/ruby.rb +137 -0
- data/lib/phusion_passenger/platform_info/depcheck_specs/utilities.rb +15 -0
- data/lib/phusion_passenger/platform_info/operating_system.rb +6 -5
- data/lib/phusion_passenger/platform_info/ruby.rb +45 -34
- data/lib/phusion_passenger/request_handler.rb +35 -22
- data/lib/phusion_passenger/request_handler/thread_handler.rb +5 -6
- data/lib/phusion_passenger/ruby_core_enhancements.rb +7 -1
- data/lib/phusion_passenger/standalone/runtime_installer.rb +43 -34
- data/lib/phusion_passenger/utils/robust_interruption.rb +34 -18
- data/passenger.gemspec +25 -0
- data/resources/templates/standalone/config.erb +3 -1
- data/test/config.json.travis +2 -2
- data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +37 -5
- data/test/cxx/ApplicationPool2/PoolTest.cpp +143 -50
- data/test/cxx/ApplicationPool2/ProcessTest.cpp +8 -0
- data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +28 -17
- data/test/cxx/ApplicationPool2/SpawnerTestCases.cpp +31 -26
- data/test/cxx/RequestHandlerTest.cpp +17 -1
- data/test/cxx/UtilsTest.cpp +84 -10
- data/test/integration_tests/apache2_tests.rb +49 -163
- data/test/integration_tests/hello_world_wsgi_spec.rb +2 -2
- data/test/integration_tests/mycook_spec.rb +1 -1
- data/test/integration_tests/nginx_tests.rb +37 -19
- data/test/ruby/request_handler_spec.rb +1 -0
- data/test/ruby/spec_helper.rb +52 -1
- data/test/stub/nginx/nginx.conf.erb +2 -0
- data/test/stub/rack/start.rb +5 -0
- data/test/stub/rails3.0/Gemfile.lock +30 -30
- data/test/stub/rails3.1/Gemfile +1 -1
- data/test/stub/rails3.1/Gemfile.lock +3 -3
- data/test/stub/rails3.2/Gemfile +1 -1
- data/test/stub/rails3.2/Gemfile.lock +4 -4
- data/test/stub/rails_apps/2.3/mycook/app/controllers/welcome_controller.rb +1 -1
- data/test/stub/rails_apps/2.3/mycook/app/helpers/recipes_helper.rb +2 -0
- data/test/stub/rails_apps/2.3/mycook/app/helpers/test_helper.rb +2 -0
- data/test/stub/rails_apps/2.3/mycook/app/helpers/uploads_helper.rb +2 -0
- data/test/stub/rails_apps/2.3/mycook/app/helpers/welcome_helper.rb +2 -0
- data/test/support/nginx_controller.rb +2 -1
- metadata +160 -156
- data/build/gempackagetask.rb +0 -99
- data/build/packagetask.rb +0 -186
- data/ext/common/StringListCreator.h +0 -83
- data/lib/phusion_passenger/dependencies.rb +0 -657
data/ext/common/AgentsStarter.h
CHANGED
@@ -62,7 +62,6 @@ int agents_starter_start(AgentsStarter *as,
|
|
62
62
|
unsigned short unionStationGatewayPort,
|
63
63
|
const char *unionStationGatewayCert,
|
64
64
|
const char *unionStationProxyAddress,
|
65
|
-
const char *unionStationProxyType,
|
66
65
|
const char **prestartURLs, unsigned int prestartURLsCount,
|
67
66
|
const AfterForkCallback afterFork,
|
68
67
|
void *callbackArgument,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2010-
|
3
|
+
* Copyright (c) 2010-2013 Phusion
|
4
4
|
*
|
5
5
|
* "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
|
6
6
|
*
|
@@ -385,7 +385,6 @@ public:
|
|
385
385
|
unsigned short unionStationGatewayPort,
|
386
386
|
const string &unionStationGatewayCert,
|
387
387
|
const string &unionStationProxyAddress,
|
388
|
-
const string &unionStationProxyType,
|
389
388
|
const set<string> &prestartURLs,
|
390
389
|
const function<void ()> &afterFork = function<void ()>())
|
391
390
|
{
|
@@ -426,7 +425,6 @@ public:
|
|
426
425
|
.setInt ("union_station_gateway_port", unionStationGatewayPort)
|
427
426
|
.set ("union_station_gateway_cert", realUnionStationGatewayCert)
|
428
427
|
.set ("union_station_proxy_address", unionStationProxyAddress)
|
429
|
-
.set ("union_station_proxy_type", unionStationProxyType)
|
430
428
|
.set ("prestart_urls", serializePrestartURLs(prestartURLs));
|
431
429
|
|
432
430
|
SocketPair fds;
|
@@ -0,0 +1,74 @@
|
|
1
|
+
/*
|
2
|
+
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
+
* Copyright (c) 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
|
+
#include <ApplicationPool2/AppTypes.h>
|
26
|
+
|
27
|
+
namespace Passenger {
|
28
|
+
namespace ApplicationPool2 {
|
29
|
+
|
30
|
+
// Don't forget to update ApplicationPool2::Options::getStartCommand() too.
|
31
|
+
const AppTypeDefinition appTypeDefinitions[] = {
|
32
|
+
{ PAT_RACK, "rack", "config.ru", "Passenger RackApp" },
|
33
|
+
{ PAT_WSGI, "wsgi", "passenger_wsgi.py", "Passenger WsgiApp" },
|
34
|
+
{ PAT_CLASSIC_RAILS, "classic-rails", "config/environment.rb", "Passenger ClassicRailsApp" },
|
35
|
+
{ PAT_NONE, NULL, NULL, NULL }
|
36
|
+
};
|
37
|
+
|
38
|
+
} // namespace ApplicationPool2
|
39
|
+
} // namespace Passenger
|
40
|
+
|
41
|
+
|
42
|
+
using namespace Passenger;
|
43
|
+
using namespace Passenger::ApplicationPool2;
|
44
|
+
|
45
|
+
PassengerAppTypeDetector *
|
46
|
+
passenger_app_type_detector_new() {
|
47
|
+
return new AppTypeDetector();
|
48
|
+
}
|
49
|
+
|
50
|
+
void
|
51
|
+
passenger_app_type_detector_free(PassengerAppTypeDetector *detector) {
|
52
|
+
delete (AppTypeDetector *) detector;
|
53
|
+
}
|
54
|
+
|
55
|
+
PassengerAppType
|
56
|
+
passenger_app_type_detector_check_document_root(PassengerAppTypeDetector *_detector,
|
57
|
+
const char *documentRoot, unsigned int len, int resolveFirstSymlink)
|
58
|
+
{
|
59
|
+
AppTypeDetector *detector = (AppTypeDetector *) _detector;
|
60
|
+
return detector->checkDocumentRoot(StaticString(documentRoot, len), resolveFirstSymlink);
|
61
|
+
}
|
62
|
+
|
63
|
+
PassengerAppType
|
64
|
+
passenger_app_type_detector_check_app_root(PassengerAppTypeDetector *_detector,
|
65
|
+
const char *appRoot, unsigned int len)
|
66
|
+
{
|
67
|
+
AppTypeDetector *detector = (AppTypeDetector *) _detector;
|
68
|
+
return detector->checkAppRoot(StaticString(appRoot, len));
|
69
|
+
}
|
70
|
+
|
71
|
+
const char *
|
72
|
+
passenger_get_app_type_name(PassengerAppType type) {
|
73
|
+
return getAppTypeName(type);
|
74
|
+
}
|
@@ -0,0 +1,202 @@
|
|
1
|
+
/*
|
2
|
+
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
+
* Copyright (c) 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
|
+
#ifndef _PASSENGER_APPLICATION_POOL2_APP_TYPES_H_
|
26
|
+
#define _PASSENGER_APPLICATION_POOL2_APP_TYPES_H_
|
27
|
+
|
28
|
+
#ifdef __cplusplus
|
29
|
+
extern "C" {
|
30
|
+
#endif /* __cplusplus */
|
31
|
+
|
32
|
+
typedef enum {
|
33
|
+
PAT_RACK,
|
34
|
+
PAT_WSGI,
|
35
|
+
PAT_CLASSIC_RAILS,
|
36
|
+
PAT_NONE
|
37
|
+
} PassengerAppType;
|
38
|
+
|
39
|
+
typedef void PassengerAppTypeDetector;
|
40
|
+
|
41
|
+
PassengerAppTypeDetector *passenger_app_type_detector_new();
|
42
|
+
void passenger_app_type_detector_free(PassengerAppTypeDetector *detector);
|
43
|
+
PassengerAppType passenger_app_type_detector_check_document_root(PassengerAppTypeDetector *detector,
|
44
|
+
const char *documentRoot, unsigned int len, int resolveFirstSymlink);
|
45
|
+
PassengerAppType passenger_app_type_detector_check_app_root(PassengerAppTypeDetector *detector,
|
46
|
+
const char *appRoot, unsigned int len);
|
47
|
+
|
48
|
+
const char *passenger_get_app_type_name(PassengerAppType type);
|
49
|
+
|
50
|
+
#ifdef __cplusplus
|
51
|
+
}
|
52
|
+
#endif /* __cplusplus */
|
53
|
+
|
54
|
+
|
55
|
+
#ifdef __cplusplus
|
56
|
+
#include <oxt/macros.hpp>
|
57
|
+
#include <oxt/backtrace.hpp>
|
58
|
+
#include <cstdlib>
|
59
|
+
#include <Logging.h>
|
60
|
+
#include <StaticString.h>
|
61
|
+
#include <Utils.h>
|
62
|
+
#include <Utils/StrIntUtils.h>
|
63
|
+
#include <Utils/CachedFileStat.hpp>
|
64
|
+
|
65
|
+
namespace Passenger {
|
66
|
+
namespace ApplicationPool2 {
|
67
|
+
|
68
|
+
|
69
|
+
struct AppTypeDefinition {
|
70
|
+
const PassengerAppType type;
|
71
|
+
const char * const name;
|
72
|
+
const char * const startupFile;
|
73
|
+
const char * const processTitle;
|
74
|
+
};
|
75
|
+
|
76
|
+
extern const AppTypeDefinition appTypeDefinitions[];
|
77
|
+
|
78
|
+
|
79
|
+
class AppTypeDetector {
|
80
|
+
private:
|
81
|
+
CachedFileStat *cstat;
|
82
|
+
unsigned int throttleRate;
|
83
|
+
bool ownsCstat;
|
84
|
+
|
85
|
+
bool check(char *buf, const char *end, const StaticString &appRoot, const char *name) {
|
86
|
+
char *pos = buf;
|
87
|
+
pos = appendData(pos, end, appRoot);
|
88
|
+
pos = appendData(pos, end, "/");
|
89
|
+
pos = appendData(pos, end, name);
|
90
|
+
if (OXT_UNLIKELY(pos == end)) {
|
91
|
+
TRACE_POINT();
|
92
|
+
P_CRITICAL("BUG: buffer overflow");
|
93
|
+
abort();
|
94
|
+
}
|
95
|
+
return fileExists(StaticString(buf, pos - buf), cstat, throttleRate);
|
96
|
+
}
|
97
|
+
|
98
|
+
public:
|
99
|
+
AppTypeDetector() {
|
100
|
+
cstat = new CachedFileStat();
|
101
|
+
ownsCstat = true;
|
102
|
+
throttleRate = 1;
|
103
|
+
}
|
104
|
+
|
105
|
+
AppTypeDetector(CachedFileStat *_cstat, unsigned int _throttleRate) {
|
106
|
+
cstat = _cstat;
|
107
|
+
ownsCstat = false;
|
108
|
+
throttleRate = _throttleRate;
|
109
|
+
}
|
110
|
+
|
111
|
+
~AppTypeDetector() {
|
112
|
+
if (ownsCstat) {
|
113
|
+
delete cstat;
|
114
|
+
}
|
115
|
+
}
|
116
|
+
|
117
|
+
PassengerAppType checkDocumentRoot(const StaticString &documentRoot, bool resolveFirstSymlink = false) {
|
118
|
+
if (!resolveFirstSymlink) {
|
119
|
+
return checkAppRoot(extractDirNameStatic(documentRoot));
|
120
|
+
} else {
|
121
|
+
char ntDocRoot[documentRoot.size() + 1];
|
122
|
+
memcpy(ntDocRoot, documentRoot.data(), documentRoot.size());
|
123
|
+
ntDocRoot[documentRoot.size()] = '\0';
|
124
|
+
string resolvedDocumentRoot = resolveSymlink(ntDocRoot);
|
125
|
+
return checkAppRoot(extractDirNameStatic(resolvedDocumentRoot));
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
PassengerAppType checkAppRoot(const StaticString &appRoot) {
|
130
|
+
char buf[appRoot.size() + 32];
|
131
|
+
const char *end = buf + appRoot.size() + 32;
|
132
|
+
const AppTypeDefinition *definition = &appTypeDefinitions[0];
|
133
|
+
|
134
|
+
while (definition->type != PAT_NONE) {
|
135
|
+
if (check(buf, end, appRoot, definition->startupFile)) {
|
136
|
+
return definition->type;
|
137
|
+
}
|
138
|
+
definition++;
|
139
|
+
}
|
140
|
+
return PAT_NONE;
|
141
|
+
}
|
142
|
+
};
|
143
|
+
|
144
|
+
|
145
|
+
inline const char *
|
146
|
+
getAppTypeName(PassengerAppType type) {
|
147
|
+
const AppTypeDefinition *definition = &appTypeDefinitions[0];
|
148
|
+
|
149
|
+
while (definition->type != PAT_NONE) {
|
150
|
+
if (definition->type == type) {
|
151
|
+
return definition->name;
|
152
|
+
}
|
153
|
+
definition++;
|
154
|
+
}
|
155
|
+
return NULL;
|
156
|
+
}
|
157
|
+
|
158
|
+
inline PassengerAppType
|
159
|
+
getAppType(const StaticString &name) {
|
160
|
+
const AppTypeDefinition *definition = &appTypeDefinitions[0];
|
161
|
+
|
162
|
+
while (definition->type != PAT_NONE) {
|
163
|
+
if (name == definition->name) {
|
164
|
+
return definition->type;
|
165
|
+
}
|
166
|
+
definition++;
|
167
|
+
}
|
168
|
+
return PAT_NONE;
|
169
|
+
}
|
170
|
+
|
171
|
+
inline const char *
|
172
|
+
getAppTypeStartupFile(PassengerAppType type) {
|
173
|
+
const AppTypeDefinition *definition = &appTypeDefinitions[0];
|
174
|
+
|
175
|
+
while (definition->type != PAT_NONE) {
|
176
|
+
if (definition->type == type) {
|
177
|
+
return definition->startupFile;
|
178
|
+
}
|
179
|
+
definition++;
|
180
|
+
}
|
181
|
+
return NULL;
|
182
|
+
}
|
183
|
+
|
184
|
+
inline const char *
|
185
|
+
getAppTypeProcessTitle(PassengerAppType type) {
|
186
|
+
const AppTypeDefinition *definition = &appTypeDefinitions[0];
|
187
|
+
|
188
|
+
while (definition->type != PAT_NONE) {
|
189
|
+
if (definition->type == type) {
|
190
|
+
return definition->processTitle;
|
191
|
+
}
|
192
|
+
definition++;
|
193
|
+
}
|
194
|
+
return NULL;
|
195
|
+
}
|
196
|
+
|
197
|
+
|
198
|
+
} // namespace ApplicationPool2
|
199
|
+
} // namespace Passenger
|
200
|
+
#endif /* __cplusplus */
|
201
|
+
|
202
|
+
#endif /* _PASSENGER_APPLICATION_POOL2_APP_TYPES_H_ */
|
@@ -111,29 +111,31 @@ struct Ticket {
|
|
111
111
|
|
112
112
|
struct SpawnerConfig {
|
113
113
|
// Used by SmartSpawner and DirectSpawner.
|
114
|
-
/** Whether to
|
114
|
+
/** Whether to print the preloader's and application's stdout. */
|
115
115
|
bool forwardStdout;
|
116
|
-
/** Whether to
|
116
|
+
/** Whether to print the preloader's and application's stderr. */
|
117
117
|
bool forwardStderr;
|
118
|
-
/**
|
119
|
-
|
120
|
-
/** Where to forward the preloader process's stderr to. */
|
121
|
-
int forwardStderrTo;
|
118
|
+
/** A random generator to use. */
|
119
|
+
RandomGeneratorPtr randomGenerator;
|
122
120
|
|
123
121
|
// Used by DummySpawner and SpawnerFactory.
|
124
122
|
unsigned int concurrency;
|
125
123
|
unsigned int spawnerCreationSleepTime;
|
126
124
|
unsigned int spawnTime;
|
127
125
|
|
128
|
-
SpawnerConfig()
|
126
|
+
SpawnerConfig(const RandomGeneratorPtr &randomGenerator = RandomGeneratorPtr())
|
129
127
|
: forwardStdout(true),
|
130
128
|
forwardStderr(true),
|
131
|
-
forwardStdoutTo(STDOUT_FILENO),
|
132
|
-
forwardStderrTo(STDERR_FILENO),
|
133
129
|
concurrency(1),
|
134
130
|
spawnerCreationSleepTime(0),
|
135
131
|
spawnTime(0)
|
136
|
-
|
132
|
+
{
|
133
|
+
if (randomGenerator != NULL) {
|
134
|
+
this->randomGenerator = randomGenerator;
|
135
|
+
} else {
|
136
|
+
this->randomGenerator = make_shared<RandomGenerator>();
|
137
|
+
}
|
138
|
+
}
|
137
139
|
};
|
138
140
|
|
139
141
|
typedef shared_ptr<SpawnerConfig> SpawnerConfigPtr;
|
@@ -0,0 +1,256 @@
|
|
1
|
+
/*
|
2
|
+
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
+
* Copyright (c) 2011-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
|
+
#ifndef _PASSENGER_APPLICATION_POOL2_DIRECT_SPAWNER_H_
|
26
|
+
#define _PASSENGER_APPLICATION_POOL2_DIRECT_SPAWNER_H_
|
27
|
+
|
28
|
+
#include <ApplicationPool2/Spawner.h>
|
29
|
+
#include <limits.h> // for PTHREAD_STACK_MIN
|
30
|
+
#include <pthread.h>
|
31
|
+
|
32
|
+
|
33
|
+
namespace Passenger {
|
34
|
+
namespace ApplicationPool2 {
|
35
|
+
|
36
|
+
using namespace std;
|
37
|
+
using namespace boost;
|
38
|
+
using namespace oxt;
|
39
|
+
|
40
|
+
|
41
|
+
class DirectSpawner: public Spawner {
|
42
|
+
private:
|
43
|
+
SafeLibevPtr libev;
|
44
|
+
|
45
|
+
static int startBackgroundThread(void *(*mainFunction)(void *), void *arg) {
|
46
|
+
// Using raw pthread API because we don't want to register such
|
47
|
+
// trivial threads on the oxt::thread list.
|
48
|
+
pthread_t thr;
|
49
|
+
pthread_attr_t attr;
|
50
|
+
size_t stack_size = 96 * 1024;
|
51
|
+
|
52
|
+
unsigned long min_stack_size;
|
53
|
+
bool stack_min_size_defined;
|
54
|
+
bool round_stack_size;
|
55
|
+
int ret;
|
56
|
+
|
57
|
+
#ifdef PTHREAD_STACK_MIN
|
58
|
+
// PTHREAD_STACK_MIN may not be a constant macro so we need
|
59
|
+
// to evaluate it dynamically.
|
60
|
+
min_stack_size = PTHREAD_STACK_MIN;
|
61
|
+
stack_min_size_defined = true;
|
62
|
+
#else
|
63
|
+
// Assume minimum stack size is 128 KB.
|
64
|
+
min_stack_size = 128 * 1024;
|
65
|
+
stack_min_size_defined = false;
|
66
|
+
#endif
|
67
|
+
if (stack_size != 0 && stack_size < min_stack_size) {
|
68
|
+
stack_size = min_stack_size;
|
69
|
+
round_stack_size = !stack_min_size_defined;
|
70
|
+
} else {
|
71
|
+
round_stack_size = true;
|
72
|
+
}
|
73
|
+
|
74
|
+
if (round_stack_size) {
|
75
|
+
// Round stack size up to page boundary.
|
76
|
+
long page_size;
|
77
|
+
#if defined(_SC_PAGESIZE)
|
78
|
+
page_size = sysconf(_SC_PAGESIZE);
|
79
|
+
#elif defined(_SC_PAGE_SIZE)
|
80
|
+
page_size = sysconf(_SC_PAGE_SIZE);
|
81
|
+
#elif defined(PAGESIZE)
|
82
|
+
page_size = sysconf(PAGESIZE);
|
83
|
+
#elif defined(PAGE_SIZE)
|
84
|
+
page_size = sysconf(PAGE_SIZE);
|
85
|
+
#else
|
86
|
+
page_size = getpagesize();
|
87
|
+
#endif
|
88
|
+
if (stack_size % page_size != 0) {
|
89
|
+
stack_size = stack_size - (stack_size % page_size) + page_size;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
pthread_attr_init(&attr);
|
94
|
+
pthread_attr_setdetachstate(&attr, 1);
|
95
|
+
pthread_attr_setstacksize(&attr, stack_size);
|
96
|
+
ret = pthread_create(&thr, &attr, mainFunction, arg);
|
97
|
+
pthread_attr_destroy(&attr);
|
98
|
+
return ret;
|
99
|
+
}
|
100
|
+
|
101
|
+
static void *detachProcessMain(void *arg) {
|
102
|
+
this_thread::disable_syscall_interruption dsi;
|
103
|
+
pid_t pid = (pid_t) (long) arg;
|
104
|
+
syscalls::waitpid(pid, NULL, 0);
|
105
|
+
return NULL;
|
106
|
+
}
|
107
|
+
|
108
|
+
void detachProcess(pid_t pid) {
|
109
|
+
startBackgroundThread(detachProcessMain, (void *) (long) pid);
|
110
|
+
}
|
111
|
+
|
112
|
+
vector<string> createCommand(const Options &options, shared_array<const char *> &args) const {
|
113
|
+
vector<string> startCommandArgs;
|
114
|
+
string processTitle;
|
115
|
+
string agentsDir = resourceLocator.getAgentsDir();
|
116
|
+
vector<string> command;
|
117
|
+
|
118
|
+
split(options.getStartCommand(resourceLocator), '\1', startCommandArgs);
|
119
|
+
if (startCommandArgs.empty()) {
|
120
|
+
throw RuntimeException("No startCommand given");
|
121
|
+
}
|
122
|
+
if (options.getProcessTitle().empty()) {
|
123
|
+
processTitle = startCommandArgs[0];
|
124
|
+
} else {
|
125
|
+
processTitle = options.getProcessTitle() + ": " + options.appRoot;
|
126
|
+
}
|
127
|
+
|
128
|
+
if (options.loadShellEnvvars) {
|
129
|
+
command.push_back("bash");
|
130
|
+
command.push_back("bash");
|
131
|
+
command.push_back("-lc");
|
132
|
+
command.push_back("exec \"$@\"");
|
133
|
+
command.push_back("SpawnPreparerShell");
|
134
|
+
} else {
|
135
|
+
command.push_back(agentsDir + "/SpawnPreparer");
|
136
|
+
}
|
137
|
+
command.push_back(agentsDir + "/SpawnPreparer");
|
138
|
+
command.push_back(serializeEnvvarsFromPoolOptions(options));
|
139
|
+
command.push_back(startCommandArgs[0]);
|
140
|
+
command.push_back(processTitle);
|
141
|
+
for (unsigned int i = 1; i < startCommandArgs.size(); i++) {
|
142
|
+
command.push_back(startCommandArgs[i]);
|
143
|
+
}
|
144
|
+
|
145
|
+
createCommandArgs(command, args);
|
146
|
+
return command;
|
147
|
+
}
|
148
|
+
|
149
|
+
public:
|
150
|
+
DirectSpawner(const SafeLibevPtr &_libev,
|
151
|
+
const ResourceLocator &_resourceLocator,
|
152
|
+
const ServerInstanceDir::GenerationPtr &_generation,
|
153
|
+
const SpawnerConfigPtr &_config = SpawnerConfigPtr())
|
154
|
+
: Spawner(_resourceLocator),
|
155
|
+
libev(_libev)
|
156
|
+
{
|
157
|
+
generation = _generation;
|
158
|
+
if (_config == NULL) {
|
159
|
+
config = make_shared<SpawnerConfig>();
|
160
|
+
} else {
|
161
|
+
config = _config;
|
162
|
+
}
|
163
|
+
}
|
164
|
+
|
165
|
+
virtual ProcessPtr spawn(const Options &options) {
|
166
|
+
TRACE_POINT();
|
167
|
+
this_thread::disable_interruption di;
|
168
|
+
this_thread::disable_syscall_interruption dsi;
|
169
|
+
P_DEBUG("Spawning new process: appRoot=" << options.appRoot);
|
170
|
+
possiblyRaiseInternalError(options);
|
171
|
+
|
172
|
+
shared_array<const char *> args;
|
173
|
+
vector<string> command = createCommand(options, args);
|
174
|
+
SpawnPreparationInfo preparation = prepareSpawn(options);
|
175
|
+
SocketPair adminSocket = createUnixSocketPair();
|
176
|
+
Pipe errorPipe = createPipe();
|
177
|
+
DebugDirPtr debugDir = make_shared<DebugDir>(preparation.uid, preparation.gid);
|
178
|
+
pid_t pid;
|
179
|
+
|
180
|
+
pid = syscalls::fork();
|
181
|
+
if (pid == 0) {
|
182
|
+
setenv("PASSENGER_DEBUG_DIR", debugDir->getPath().c_str(), 1);
|
183
|
+
purgeStdio(stdout);
|
184
|
+
purgeStdio(stderr);
|
185
|
+
resetSignalHandlersAndMask();
|
186
|
+
disableMallocDebugging();
|
187
|
+
int adminSocketCopy = dup2(adminSocket.first, 3);
|
188
|
+
int errorPipeCopy = dup2(errorPipe.second, 4);
|
189
|
+
dup2(adminSocketCopy, 0);
|
190
|
+
dup2(adminSocketCopy, 1);
|
191
|
+
dup2(errorPipeCopy, 2);
|
192
|
+
closeAllFileDescriptors(2);
|
193
|
+
setChroot(preparation);
|
194
|
+
switchUser(preparation);
|
195
|
+
setWorkingDirectory(preparation);
|
196
|
+
execvp(args[0], (char * const *) args.get());
|
197
|
+
|
198
|
+
int e = errno;
|
199
|
+
printf("!> Error\n");
|
200
|
+
printf("!> \n");
|
201
|
+
printf("Cannot execute \"%s\": %s (errno=%d)\n", command[0].c_str(),
|
202
|
+
strerror(e), e);
|
203
|
+
fprintf(stderr, "Cannot execute \"%s\": %s (errno=%d)\n",
|
204
|
+
command[0].c_str(), strerror(e), e);
|
205
|
+
fflush(stdout);
|
206
|
+
fflush(stderr);
|
207
|
+
_exit(1);
|
208
|
+
|
209
|
+
} else if (pid == -1) {
|
210
|
+
int e = errno;
|
211
|
+
throw SystemException("Cannot fork a new process", e);
|
212
|
+
|
213
|
+
} else {
|
214
|
+
UPDATE_TRACE_POINT();
|
215
|
+
ScopeGuard guard(boost::bind(nonInterruptableKillAndWaitpid, pid));
|
216
|
+
P_DEBUG("Process forked for appRoot=" << options.appRoot << ": PID " << pid);
|
217
|
+
adminSocket.first.close();
|
218
|
+
errorPipe.second.close();
|
219
|
+
|
220
|
+
NegotiationDetails details;
|
221
|
+
details.preparation = &preparation;
|
222
|
+
details.libev = libev;
|
223
|
+
details.stderrCapturer =
|
224
|
+
make_shared<BackgroundIOCapturer>(
|
225
|
+
errorPipe.first,
|
226
|
+
string("[App ") + toString(pid) + " stderr] ",
|
227
|
+
config->forwardStderr);
|
228
|
+
details.stderrCapturer->start();
|
229
|
+
details.pid = pid;
|
230
|
+
details.adminSocket = adminSocket.second;
|
231
|
+
details.io = BufferedIO(adminSocket.second);
|
232
|
+
details.errorPipe = errorPipe.first;
|
233
|
+
details.options = &options;
|
234
|
+
details.forwardStderr = config->forwardStderr;
|
235
|
+
details.debugDir = debugDir;
|
236
|
+
|
237
|
+
ProcessPtr process;
|
238
|
+
{
|
239
|
+
this_thread::restore_interruption ri(di);
|
240
|
+
this_thread::restore_syscall_interruption rsi(dsi);
|
241
|
+
process = negotiateSpawn(details);
|
242
|
+
}
|
243
|
+
detachProcess(process->pid);
|
244
|
+
guard.clear();
|
245
|
+
P_DEBUG("Process spawning done: appRoot=" << options.appRoot <<
|
246
|
+
", pid=" << process->pid);
|
247
|
+
return process;
|
248
|
+
}
|
249
|
+
}
|
250
|
+
};
|
251
|
+
|
252
|
+
|
253
|
+
} // namespace ApplicationPool2
|
254
|
+
} // namespace Passenger
|
255
|
+
|
256
|
+
#endif /* _PASSENGER_APPLICATION_POOL2_DIRECT_SPAWNER_H_ */
|