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.

Files changed (159) hide show
  1. data/.travis.yml +3 -0
  2. data/NEWS +77 -7
  3. data/README.md +3 -11
  4. data/bin/passenger-install-apache2-module +24 -20
  5. data/bin/passenger-install-nginx-module +25 -23
  6. data/build/agents.rb +11 -0
  7. data/build/apache2.rb +9 -5
  8. data/build/basics.rb +37 -30
  9. data/build/common_library.rb +4 -1
  10. data/build/cplusplus_support.rb +5 -5
  11. data/build/cxx_tests.rb +28 -8
  12. data/build/integration_tests.rb +6 -3
  13. data/build/nginx.rb +3 -3
  14. data/build/packaging.rb +95 -57
  15. data/build/ruby_extension.rb +34 -21
  16. data/build/ruby_tests.rb +4 -2
  17. data/build/test_basics.rb +1 -1
  18. data/dev/run_travis.sh +36 -1
  19. data/doc/Users guide Apache.html +425 -308
  20. data/doc/Users guide Apache.idmap.txt +78 -70
  21. data/doc/Users guide Apache.index.sqlite3 +0 -0
  22. data/doc/Users guide Apache.txt +33 -92
  23. data/doc/Users guide Nginx.html +519 -220
  24. data/doc/Users guide Nginx.idmap.txt +78 -60
  25. data/doc/Users guide Nginx.txt +115 -26
  26. data/doc/Users guide Standalone.html +8 -2
  27. data/doc/users_guide_snippets/analysis_and_system_maintenance.txt +1 -7
  28. data/doc/users_guide_snippets/installation.txt +167 -22
  29. data/doc/users_guide_snippets/rackup_specifications.txt +4 -0
  30. data/doc/users_guide_snippets/since_version.txt +1 -0
  31. data/doc/users_guide_snippets/support_information.txt +3 -7
  32. data/doc/users_guide_snippets/tips.txt +0 -24
  33. data/ext/apache2/Configuration.cpp +11 -33
  34. data/ext/apache2/Configuration.hpp +3 -18
  35. data/ext/apache2/DirectoryMapper.h +20 -70
  36. data/ext/apache2/Hooks.cpp +2 -2
  37. data/ext/common/AgentsStarter.cpp +0 -2
  38. data/ext/common/AgentsStarter.h +0 -1
  39. data/ext/common/AgentsStarter.hpp +1 -3
  40. data/ext/common/ApplicationPool2/AppTypes.cpp +74 -0
  41. data/ext/common/ApplicationPool2/AppTypes.h +202 -0
  42. data/ext/common/ApplicationPool2/Common.h +12 -10
  43. data/ext/common/ApplicationPool2/DirectSpawner.h +256 -0
  44. data/ext/common/ApplicationPool2/DummySpawner.h +90 -0
  45. data/ext/common/ApplicationPool2/Group.h +311 -94
  46. data/ext/common/ApplicationPool2/Implementation.cpp +405 -145
  47. data/ext/common/ApplicationPool2/Options.h +24 -26
  48. data/ext/common/ApplicationPool2/PipeWatcher.h +20 -13
  49. data/ext/common/ApplicationPool2/Pool.h +326 -183
  50. data/ext/common/ApplicationPool2/Process.h +205 -55
  51. data/ext/common/ApplicationPool2/README.md +1 -1
  52. data/ext/common/ApplicationPool2/Session.h +21 -10
  53. data/ext/common/ApplicationPool2/SmartSpawner.h +801 -0
  54. data/ext/common/ApplicationPool2/Spawner.h +141 -1149
  55. data/ext/common/ApplicationPool2/SpawnerFactory.h +132 -0
  56. data/ext/common/ApplicationPool2/SuperGroup.h +146 -223
  57. data/ext/common/Constants.h +4 -2
  58. data/ext/common/Exceptions.h +23 -1
  59. data/ext/common/Logging.cpp +17 -6
  60. data/ext/common/Logging.h +37 -7
  61. data/ext/common/ResourceLocator.h +1 -1
  62. data/ext/common/Utils.cpp +49 -1
  63. data/ext/common/Utils.h +13 -4
  64. data/ext/common/{AnsiColorConstants.h → Utils/AnsiColorConstants.h} +0 -0
  65. data/ext/common/{BCrypt.cpp → Utils/BCrypt.cpp} +0 -0
  66. data/ext/common/{BCrypt.h → Utils/BCrypt.h} +0 -0
  67. data/ext/common/{Blowfish.c → Utils/Blowfish.c} +0 -0
  68. data/ext/common/{Blowfish.h → Utils/Blowfish.h} +0 -0
  69. data/ext/common/Utils/CachedFileStat.hpp +27 -25
  70. data/ext/common/Utils/Curl.h +184 -0
  71. data/ext/common/{HttpConstants.h → Utils/HttpConstants.h} +3 -0
  72. data/ext/common/Utils/IOUtils.cpp +6 -2
  73. data/ext/common/{IniFile.h → Utils/IniFile.h} +0 -0
  74. data/ext/common/Utils/LargeFiles.cpp +30 -0
  75. data/ext/common/Utils/LargeFiles.h +40 -0
  76. data/ext/common/Utils/StrIntUtils.cpp +72 -8
  77. data/ext/common/Utils/StrIntUtils.h +24 -2
  78. data/ext/common/Utils/StringMap.h +12 -2
  79. data/ext/common/Utils/VariantMap.h +51 -2
  80. data/ext/common/Utils/jsoncpp.cpp +1 -1
  81. data/ext/common/agents/Base.cpp +147 -11
  82. data/ext/common/agents/HelperAgent/AgentOptions.h +14 -6
  83. data/ext/common/agents/HelperAgent/Main.cpp +79 -19
  84. data/ext/common/agents/HelperAgent/RequestHandler.h +36 -16
  85. data/ext/common/agents/LoggingAgent/LoggingServer.h +3 -5
  86. data/ext/common/agents/LoggingAgent/Main.cpp +2 -4
  87. data/ext/common/agents/LoggingAgent/RemoteSender.h +18 -24
  88. data/ext/common/agents/SpawnPreparer.cpp +7 -0
  89. data/ext/common/agents/Watchdog/Main.cpp +96 -38
  90. data/ext/nginx/Configuration.c +26 -22
  91. data/ext/nginx/Configuration.h +4 -2
  92. data/ext/nginx/ContentHandler.c +23 -52
  93. data/ext/nginx/ContentHandler.h +5 -11
  94. data/ext/nginx/config +10 -3
  95. data/ext/nginx/ngx_http_passenger_module.c +21 -6
  96. data/ext/nginx/ngx_http_passenger_module.h +4 -1
  97. data/ext/oxt/dynamic_thread_group.hpp +9 -1
  98. data/ext/oxt/system_calls.cpp +2 -2
  99. data/ext/ruby/extconf.rb +2 -1
  100. data/helper-scripts/backtrace-sanitizer.rb +2 -0
  101. data/helper-scripts/wsgi-loader.py +54 -21
  102. data/lib/phusion_passenger.rb +5 -3
  103. data/lib/phusion_passenger/abstract_installer.rb +18 -41
  104. data/lib/phusion_passenger/admin_tools/memory_stats.rb +2 -2
  105. data/lib/phusion_passenger/admin_tools/server_instance.rb +2 -2
  106. data/lib/phusion_passenger/common_library.rb +23 -3
  107. data/lib/phusion_passenger/debug_logging.rb +10 -3
  108. data/lib/phusion_passenger/packaging.rb +1 -0
  109. data/lib/phusion_passenger/platform_info.rb +113 -115
  110. data/lib/phusion_passenger/platform_info/compiler.rb +224 -134
  111. data/lib/phusion_passenger/platform_info/cxx_portability.rb +143 -0
  112. data/lib/phusion_passenger/platform_info/depcheck.rb +371 -0
  113. data/lib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +124 -0
  114. data/lib/phusion_passenger/platform_info/depcheck_specs/compiler_toolchain.rb +97 -0
  115. data/lib/phusion_passenger/platform_info/depcheck_specs/gems.rb +39 -0
  116. data/lib/phusion_passenger/platform_info/depcheck_specs/libs.rb +118 -0
  117. data/lib/phusion_passenger/platform_info/depcheck_specs/ruby.rb +137 -0
  118. data/lib/phusion_passenger/platform_info/depcheck_specs/utilities.rb +15 -0
  119. data/lib/phusion_passenger/platform_info/operating_system.rb +6 -5
  120. data/lib/phusion_passenger/platform_info/ruby.rb +45 -34
  121. data/lib/phusion_passenger/request_handler.rb +35 -22
  122. data/lib/phusion_passenger/request_handler/thread_handler.rb +5 -6
  123. data/lib/phusion_passenger/ruby_core_enhancements.rb +7 -1
  124. data/lib/phusion_passenger/standalone/runtime_installer.rb +43 -34
  125. data/lib/phusion_passenger/utils/robust_interruption.rb +34 -18
  126. data/passenger.gemspec +25 -0
  127. data/resources/templates/standalone/config.erb +3 -1
  128. data/test/config.json.travis +2 -2
  129. data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +37 -5
  130. data/test/cxx/ApplicationPool2/PoolTest.cpp +143 -50
  131. data/test/cxx/ApplicationPool2/ProcessTest.cpp +8 -0
  132. data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +28 -17
  133. data/test/cxx/ApplicationPool2/SpawnerTestCases.cpp +31 -26
  134. data/test/cxx/RequestHandlerTest.cpp +17 -1
  135. data/test/cxx/UtilsTest.cpp +84 -10
  136. data/test/integration_tests/apache2_tests.rb +49 -163
  137. data/test/integration_tests/hello_world_wsgi_spec.rb +2 -2
  138. data/test/integration_tests/mycook_spec.rb +1 -1
  139. data/test/integration_tests/nginx_tests.rb +37 -19
  140. data/test/ruby/request_handler_spec.rb +1 -0
  141. data/test/ruby/spec_helper.rb +52 -1
  142. data/test/stub/nginx/nginx.conf.erb +2 -0
  143. data/test/stub/rack/start.rb +5 -0
  144. data/test/stub/rails3.0/Gemfile.lock +30 -30
  145. data/test/stub/rails3.1/Gemfile +1 -1
  146. data/test/stub/rails3.1/Gemfile.lock +3 -3
  147. data/test/stub/rails3.2/Gemfile +1 -1
  148. data/test/stub/rails3.2/Gemfile.lock +4 -4
  149. data/test/stub/rails_apps/2.3/mycook/app/controllers/welcome_controller.rb +1 -1
  150. data/test/stub/rails_apps/2.3/mycook/app/helpers/recipes_helper.rb +2 -0
  151. data/test/stub/rails_apps/2.3/mycook/app/helpers/test_helper.rb +2 -0
  152. data/test/stub/rails_apps/2.3/mycook/app/helpers/uploads_helper.rb +2 -0
  153. data/test/stub/rails_apps/2.3/mycook/app/helpers/welcome_helper.rb +2 -0
  154. data/test/support/nginx_controller.rb +2 -1
  155. metadata +160 -156
  156. data/build/gempackagetask.rb +0 -99
  157. data/build/packagetask.rb +0 -186
  158. data/ext/common/StringListCreator.h +0 -83
  159. data/lib/phusion_passenger/dependencies.rb +0 -657
@@ -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-2012 Phusion
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 forward the preloader process's stdout to our stdout. */
114
+ /** Whether to print the preloader's and application's stdout. */
115
115
  bool forwardStdout;
116
- /** Whether to forward the preloader process's stderr to our stderr. */
116
+ /** Whether to print the preloader's and application's stderr. */
117
117
  bool forwardStderr;
118
- /** Where to forward the preloader process's stdout to. */
119
- int forwardStdoutTo;
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_ */