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
@@ -21,7 +21,7 @@
21
21
  spawner = createSpawner(options)
22
22
 
23
23
  #define RUN_USER_SWITCHING_TEST() \
24
- spawner->spawn(options); \
24
+ process = spawner->spawn(options); \
25
25
  BufferedIO io(FileDescriptor(open("/tmp/info.txt", O_RDONLY))); \
26
26
  uid_t uid = (uid_t) atol(io.readLine().c_str()); \
27
27
  gid_t gid = (gid_t) atol(io.readLine().c_str()); \
@@ -73,16 +73,6 @@
73
73
  return getgrgid(gid)->gr_name;
74
74
  }
75
75
 
76
- static string strip(const string &str) {
77
- if (!str.empty() && str[str.size() - 1] == '\n') {
78
- string result = str;
79
- result.erase(str.size() - 1, 1);
80
- return result;
81
- } else {
82
- return str;
83
- }
84
- }
85
-
86
76
  TEST_METHOD(1) {
87
77
  // Basic spawning test.
88
78
  Options options = createOptions();
@@ -90,7 +80,7 @@
90
80
  options.startCommand = "ruby\1" "start.rb";
91
81
  options.startupFile = "start.rb";
92
82
  SpawnerPtr spawner = createSpawner(options);
93
- ProcessPtr process = spawner->spawn(options);
83
+ process = spawner->spawn(options);
94
84
  ensure_equals(process->sockets->size(), 1u);
95
85
 
96
86
  Connection conn = process->sockets->front().checkoutConnection();
@@ -178,7 +168,7 @@
178
168
  options.startCommand = "ruby\1" "start.rb";
179
169
  options.startupFile = "start.rb";
180
170
  SpawnerPtr spawner = createSpawner(options);
181
- ProcessPtr process = spawner->spawn(options);
171
+ process = spawner->spawn(options);
182
172
  ensure_equals(process->sockets->size(), 1u);
183
173
 
184
174
  Connection conn = process->sockets->front().checkoutConnection();
@@ -196,7 +186,7 @@
196
186
  options.environmentVariables.push_back(make_pair("PASSENGER_FOO", "foo"));
197
187
  options.environmentVariables.push_back(make_pair("PASSENGER_BAR", "bar"));
198
188
  SpawnerPtr spawner = createSpawner(options);
199
- ProcessPtr process = spawner->spawn(options);
189
+ process = spawner->spawn(options);
200
190
  ensure_equals(process->sockets->size(), 1u);
201
191
 
202
192
  Connection conn = process->sockets->front().checkoutConnection();
@@ -245,7 +235,7 @@
245
235
  runShellCommand("chmod 600 tmp.check/a");
246
236
 
247
237
  try {
248
- spawner->spawn(options);
238
+ process = spawner->spawn(options);
249
239
  fail("SpawnException expected");
250
240
  } catch (const SpawnException &e) {
251
241
  ensure("(1)", containsSubstring(e.getErrorPage(),
@@ -254,7 +244,7 @@
254
244
 
255
245
  runShellCommand("chmod 700 tmp.check/a");
256
246
  try {
257
- spawner->spawn(options);
247
+ process = spawner->spawn(options);
258
248
  fail("SpawnException expected");
259
249
  } catch (const SpawnException &e) {
260
250
  ensure("(2)", containsSubstring(e.getErrorPage(),
@@ -263,7 +253,7 @@
263
253
 
264
254
  runShellCommand("chmod 700 tmp.check/a/b/c");
265
255
  try {
266
- spawner->spawn(options);
256
+ process = spawner->spawn(options);
267
257
  fail("SpawnException expected");
268
258
  } catch (const SpawnException &e) {
269
259
  ensure("(3)", containsSubstring(e.getErrorPage(),
@@ -271,7 +261,7 @@
271
261
  }
272
262
 
273
263
  runShellCommand("chmod 700 tmp.check/a/b/c/d");
274
- spawner->spawn(options); // Should not throw.
264
+ process = spawner->spawn(options); // Should not throw.
275
265
  }
276
266
  }
277
267
 
@@ -279,19 +269,19 @@
279
269
  // It forwards all stdout and stderr output, even after the corresponding
280
270
  // Process object has been destroyed.
281
271
  DeleteFileEventually d("tmp.output");
282
- FileDescriptor output(open("tmp.output", O_WRONLY | O_CREAT | O_TRUNC, 0600));
272
+ PipeWatcher::onData = gatherOutput;
283
273
 
284
274
  Options options = createOptions();
285
275
  options.appRoot = "stub/rack";
286
276
  options.appType = "rack";
287
277
  SpawnerPtr spawner = createSpawner(options);
288
- spawner->getConfig()->forwardStdoutTo = output;
289
- spawner->getConfig()->forwardStderrTo = output;
290
- ProcessPtr process = spawner->spawn(options);
278
+ process = spawner->spawn(options);
279
+ process->requiresShutdown = false;
291
280
 
292
281
  SessionPtr session = process->newSession();
293
282
  session->initiate();
294
283
 
284
+ setLogLevel(LVL_ERROR); // TODO: should be LVL_WARN
295
285
  const char header[] =
296
286
  "REQUEST_METHOD\0GET\0"
297
287
  "PATH_INFO\0/print_stdout_and_stderr\0";
@@ -304,10 +294,14 @@
304
294
  writeScalarMessage(session->fd(), data);
305
295
  shutdown(session->fd(), SHUT_WR);
306
296
  readAll(session->fd());
297
+ session->close(true);
298
+ session.reset();
299
+ process.reset();
300
+
307
301
  EVENTUALLY(2,
308
- string data = readAll("tmp.output");
309
- result = data.find("hello stdout!\n") != string::npos
310
- && data.find("hello stderr!\n") != string::npos;
302
+ lock_guard<boost::mutex> l(gatheredOutputSyncher);
303
+ result = gatheredOutput.find("hello stdout!\n") != string::npos
304
+ && gatheredOutput.find("hello stderr!\n") != string::npos;
311
305
  );
312
306
  }
313
307
 
@@ -762,6 +756,17 @@
762
756
  RUN_USER_SWITCHING_TEST();
763
757
  runShellCommand(("groups " + testConfig["normal_user_1"].asString() + " > /tmp/info2.txt").c_str());
764
758
  string defaultGroups = strip(readAll("/tmp/info2.txt"));
765
- // default_groups.gsub!(/.*: */, '')
759
+
760
+ // On Linux, the 'groups' output is prepended by the group name so
761
+ // get rid of that.
762
+ string::size_type pos = defaultGroups.find(':');
763
+ if (pos != string::npos) {
764
+ pos++;
765
+ while (pos < defaultGroups.size() && defaultGroups[pos] == ' ') {
766
+ pos++;
767
+ }
768
+ defaultGroups.erase(0, pos);
769
+ }
770
+
766
771
  ensure_equals(groups, defaultGroups);
767
772
  }
@@ -41,9 +41,11 @@ namespace tut {
41
41
  createServerInstanceDirAndGeneration(serverInstanceDir, generation);
42
42
  spawnerFactory = make_shared<SpawnerFactory>(bg.safe, *resourceLocator, generation);
43
43
  pool = make_shared<Pool>(bg.safe.get(), spawnerFactory);
44
+ pool->initialize();
44
45
  serverFilename = generation->getPath() + "/server";
45
46
  requestSocket = createUnixServer(serverFilename);
46
47
  setNonBlocking(requestSocket);
48
+ setLogLevel(LVL_ERROR); // TODO: set to LVL_WARN
47
49
 
48
50
  agentOptions.passengerRoot = resourceLocator->getRoot();
49
51
  root = resourceLocator->getRoot();
@@ -56,7 +58,7 @@ namespace tut {
56
58
  }
57
59
 
58
60
  ~RequestHandlerTest() {
59
- setLogLevel(0);
61
+ setLogLevel(DEFAULT_LOG_LEVEL);
60
62
  unlink(serverFilename.c_str());
61
63
  handler.reset();
62
64
  pool->destroy();
@@ -832,6 +834,20 @@ namespace tut {
832
834
  }
833
835
  }
834
836
 
837
+ TEST_METHOD(47) {
838
+ set_test_name("The RequestHandler should append a Date header if the app doesn't output one.");
839
+
840
+ init();
841
+ connect();
842
+ sendHeaders(defaultHeaders,
843
+ "PASSENGER_APP_ROOT", wsgiAppPath.c_str(),
844
+ "PATH_INFO", "/pid",
845
+ NULL);
846
+
847
+ string result = readAll(connection);
848
+ ensure(result.find("Date: ") != string::npos);
849
+ }
850
+
835
851
  // Test small response buffering.
836
852
  // Test large response buffering.
837
853
  }
@@ -1,7 +1,7 @@
1
- #include "TestSupport.h"
2
- #include "Utils.h"
3
- #include "Utils/StrIntUtils.h"
4
- #include "Utils/MemZeroGuard.h"
1
+ #include <TestSupport.h>
2
+ #include <Utils.h>
3
+ #include <Utils/StrIntUtils.h>
4
+ #include <Utils/MemZeroGuard.h>
5
5
  #include <sys/types.h>
6
6
  #include <sys/stat.h>
7
7
  #include <stdio.h>
@@ -49,14 +49,20 @@ namespace tut {
49
49
 
50
50
  TEST_METHOD(1) {
51
51
  split("", ':', output);
52
- ensure_equals(output.size(), 1u);
53
- ensure_equals(output[0], "");
52
+ ensure_equals(output.size(), 0u);
53
+
54
+ splitIncludeSep("", ':', output);
55
+ ensure_equals(output.size(), 0u);
54
56
  }
55
57
 
56
58
  TEST_METHOD(2) {
57
59
  split("hello world", ':', output);
58
60
  ensure_equals(output.size(), 1u);
59
61
  ensure_equals(output[0], "hello world");
62
+
63
+ splitIncludeSep("hello world", ':', output);
64
+ ensure_equals(output.size(), 1u);
65
+ ensure_equals(output[0], "hello world");
60
66
  }
61
67
 
62
68
  TEST_METHOD(3) {
@@ -64,13 +70,22 @@ namespace tut {
64
70
  ensure_equals(output.size(), 2u);
65
71
  ensure_equals(output[0], "hello world");
66
72
  ensure_equals(output[1], "foo bar");
73
+
74
+ splitIncludeSep("hello world:foo bar", ':', output);
75
+ ensure_equals(output.size(), 2u);
76
+ ensure_equals(output[0], "hello world:");
77
+ ensure_equals(output[1], "foo bar");
67
78
  }
68
79
 
69
80
  TEST_METHOD(4) {
70
81
  split("hello world:", ':', output);
71
- ensure_equals(output.size(), 2u);
72
- ensure_equals(output[0], "hello world");
73
- ensure_equals(output[1], "");
82
+ ensure_equals("(1)", output.size(), 2u);
83
+ ensure_equals("(2)", output[0], "hello world");
84
+ ensure_equals("(3)", output[1], "");
85
+
86
+ splitIncludeSep("hello world:", ':', output);
87
+ ensure_equals("(4)", output.size(), 1u);
88
+ ensure_equals("(5)", output[0], "hello world:");
74
89
  }
75
90
 
76
91
  TEST_METHOD(5) {
@@ -78,6 +93,11 @@ namespace tut {
78
93
  ensure_equals(output.size(), 2u);
79
94
  ensure_equals(output[0], "");
80
95
  ensure_equals(output[1], "hello world");
96
+
97
+ splitIncludeSep(":hello world", ':', output);
98
+ ensure_equals(output.size(), 2u);
99
+ ensure_equals(output[0], ":");
100
+ ensure_equals(output[1], "hello world");
81
101
  }
82
102
 
83
103
  TEST_METHOD(6) {
@@ -87,6 +107,13 @@ namespace tut {
87
107
  ensure_equals(output[1], "def");
88
108
  ensure_equals(output[2], "");
89
109
  ensure_equals(output[3], "ghi");
110
+
111
+ splitIncludeSep("abc:def::ghi", ':', output);
112
+ ensure_equals(output.size(), 4u);
113
+ ensure_equals(output[0], "abc:");
114
+ ensure_equals(output[1], "def:");
115
+ ensure_equals(output[2], ":");
116
+ ensure_equals(output[3], "ghi");
90
117
  }
91
118
 
92
119
  TEST_METHOD(7) {
@@ -96,6 +123,13 @@ namespace tut {
96
123
  ensure_equals(output[1], "");
97
124
  ensure_equals(output[2], "");
98
125
  ensure_equals(output[3], "def");
126
+
127
+ splitIncludeSep("abc:::def", ':', output);
128
+ ensure_equals(output.size(), 4u);
129
+ ensure_equals(output[0], "abc:");
130
+ ensure_equals(output[1], ":");
131
+ ensure_equals(output[2], ":");
132
+ ensure_equals(output[3], "def");
99
133
  }
100
134
 
101
135
 
@@ -167,11 +201,30 @@ namespace tut {
167
201
  ensure_equals("Test 8", extractDirName(".."), ".");
168
202
  ensure_equals("Test 9", extractDirName("./foo"), ".");
169
203
  ensure_equals("Test 10", extractDirName("../foo"), "..");
204
+ ensure_equals("Test 11", extractDirName(""), ".");
205
+ ensure_equals("Test 12", extractDirName(".///"), ".");
206
+ ensure_equals("Test 13", extractDirName("foo//bar"), "foo");
207
+ }
208
+
209
+ TEST_METHOD(27) {
210
+ ensure_equals("Test 1", extractDirNameStatic("/usr/lib"), "/usr");
211
+ ensure_equals("Test 2", extractDirNameStatic("/usr/lib/"), "/usr");
212
+ ensure_equals("Test 3", extractDirNameStatic("/usr/"), "/");
213
+ ensure_equals("Test 4", extractDirNameStatic("usr"), ".");
214
+ ensure_equals("Test 5", extractDirNameStatic("/"), "/");
215
+ ensure_equals("Test 6", extractDirNameStatic("///"), "/");
216
+ ensure_equals("Test 7", extractDirNameStatic("."), ".");
217
+ ensure_equals("Test 8", extractDirNameStatic(".."), ".");
218
+ ensure_equals("Test 9", extractDirNameStatic("./foo"), ".");
219
+ ensure_equals("Test 10", extractDirNameStatic("../foo"), "..");
220
+ ensure_equals("Test 11", extractDirNameStatic(""), ".");
221
+ ensure_equals("Test 12", extractDirNameStatic(".///"), ".");
222
+ ensure_equals("Test 13", extractDirNameStatic("foo//bar"), "foo");
170
223
  }
171
224
 
172
225
  /***** Test resolveSymlink() *****/
173
226
 
174
- TEST_METHOD(27) {
227
+ TEST_METHOD(28) {
175
228
  TempDir d("tmp.symlinks");
176
229
  runShellCommand("touch tmp.symlinks/foo.txt");
177
230
  runShellCommand("ln -s /usr/bin tmp.symlinks/absolute_symlink");
@@ -585,4 +638,25 @@ namespace tut {
585
638
  ensure_equals(absolutizePath("../../foo", "/usr/local/bin"), "/usr/foo");
586
639
  ensure_equals(absolutizePath("../.././foo/bar", "/usr/local/bin"), "/usr/foo/bar");
587
640
  }
641
+
642
+ /***** Test constantTimeCompare() *****/
643
+
644
+ TEST_METHOD(54) {
645
+ ensure("(1)", constantTimeCompare("", ""));
646
+ ensure("(2)", constantTimeCompare("a", "a"));
647
+ ensure("(3)", constantTimeCompare("aa", "aa"));
648
+ ensure("(4)", constantTimeCompare("abc", "abc"));
649
+
650
+ ensure("(5)", !constantTimeCompare("", "a"));
651
+ ensure("(6)", !constantTimeCompare("", "abcd"));
652
+ ensure("(7)", !constantTimeCompare("ab", "cd"));
653
+ ensure("(8)", !constantTimeCompare("ab", "abc"));
654
+ ensure("(9)", !constantTimeCompare("ab", "abcd"));
655
+
656
+ ensure("(10)", !constantTimeCompare("a", ""));
657
+ ensure("(11)", !constantTimeCompare("abcd", ""));
658
+ ensure("(12)", !constantTimeCompare("cd", "ab"));
659
+ ensure("(13)", !constantTimeCompare("abc", "ab"));
660
+ ensure("(14)", !constantTimeCompare("abcd", "ab"));
661
+ }
588
662
  }
@@ -11,27 +11,19 @@ require 'integration_tests/cgi_environment_spec'
11
11
  require 'integration_tests/hello_world_rack_spec'
12
12
  require 'integration_tests/hello_world_wsgi_spec'
13
13
 
14
- # TODO: test the 'RailsUserSwitching' and 'RailsDefaultUser' option.
14
+ # TODO: test the 'PassengerUserSwitching' and 'PassengerDefaultUser' option.
15
15
  # TODO: test custom page caching directory
16
16
 
17
17
  describe "Apache 2 module" do
18
18
  before :all do
19
19
  check_hosts_configuration
20
- @apache2 = Apache2Controller.new
21
20
  @passenger_temp_dir = "/tmp/passenger-test.#{$$}"
22
21
  Dir.mkdir(@passenger_temp_dir)
23
22
  ENV['PASSENGER_TEMP_DIR'] = @passenger_temp_dir
24
- @apache2.set(:passenger_temp_dir => @passenger_temp_dir)
25
- if Process.uid == 0
26
- @apache2.set(
27
- :www_user => CONFIG['normal_user_1'],
28
- :www_group => Etc.getgrgid(Etc.getpwnam(CONFIG['normal_user_1']).gid).name
29
- )
30
- end
31
23
  end
32
24
 
33
25
  after :all do
34
- @apache2.stop
26
+ @apache2.stop if @apache2
35
27
  FileUtils.chmod_R(0777, @passenger_temp_dir)
36
28
  FileUtils.rm_rf(@passenger_temp_dir)
37
29
  end
@@ -40,23 +32,36 @@ describe "Apache 2 module" do
40
32
  File.open("test.log", "a") do |f|
41
33
  # Make sure that all Apache log output is prepended by the test description
42
34
  # so that we know which messages are associated with which tests.
43
- f.puts "\n#### #{self.class.description} : #{description}"
35
+ f.puts "\n#### #{Time.now}: #{example.full_description}"
36
+ end
37
+ end
38
+
39
+ def create_apache2_controller
40
+ @apache2 = Apache2Controller.new
41
+ @apache2.set(:passenger_temp_dir => @passenger_temp_dir)
42
+ if Process.uid == 0
43
+ @apache2.set(
44
+ :www_user => CONFIG['normal_user_1'],
45
+ :www_group => Etc.getgrgid(Etc.getpwnam(CONFIG['normal_user_1']).gid).name
46
+ )
44
47
  end
45
48
  end
46
49
 
47
50
  describe ": MyCook(tm) beta running on root URI" do
48
51
  before :all do
52
+ create_apache2_controller
49
53
  @web_server_supports_chunked_transfer_encoding = true
50
54
  @base_uri = ""
51
55
  @server = "http://passenger.test:#{@apache2.port}"
52
56
  @apache2 << "RailsMaxPoolSize 1"
53
- @stub = RailsStub.new('2.3/mycook')
57
+ @stub = ClassicRailsStub.new('rails_apps/2.3/mycook')
54
58
  @apache2.set_vhost("passenger.test", "#{@stub.full_app_root}/public")
55
59
  @apache2.start
56
60
  end
57
61
 
58
62
  after :all do
59
63
  @stub.destroy
64
+ @apache2.stop if @apache2
60
65
  end
61
66
 
62
67
  before :each do
@@ -64,7 +69,7 @@ describe "Apache 2 module" do
64
69
  end
65
70
 
66
71
  it_should_behave_like "MyCook(tm) beta"
67
- include_shared_example_group "CGI environment variables compliance"
72
+ include_examples "CGI environment variables compliance"
68
73
 
69
74
  it "doesn't block Rails while an upload is in progress" do
70
75
  get('/') # Force spawning so that the timeout below is enough.
@@ -123,9 +128,10 @@ describe "Apache 2 module" do
123
128
 
124
129
  describe ": MyCook(tm) beta running in a sub-URI" do
125
130
  before :all do
131
+ create_apache2_controller
126
132
  @web_server_supports_chunked_transfer_encoding = true
127
133
  @base_uri = "/mycook"
128
- @stub = RailsStub.new('2.3/mycook')
134
+ @stub = ClassicRailsStub.new('rails_apps/2.3/mycook')
129
135
  FileUtils.rm_rf('tmp.webdir')
130
136
  FileUtils.mkdir_p('tmp.webdir')
131
137
  FileUtils.cp_r('stub/zsfa/.', 'tmp.webdir')
@@ -140,6 +146,7 @@ describe "Apache 2 module" do
140
146
  after :all do
141
147
  FileUtils.rm_rf('tmp.webdir')
142
148
  @stub.destroy
149
+ @apache2.stop if @apache2
143
150
  end
144
151
 
145
152
  before :each do
@@ -148,7 +155,7 @@ describe "Apache 2 module" do
148
155
  end
149
156
 
150
157
  it_should_behave_like "MyCook(tm) beta"
151
- include_shared_example_group "CGI environment variables compliance"
158
+ include_examples "CGI environment variables compliance"
152
159
 
153
160
  it "does not interfere with the root website" do
154
161
  @server = "http://passenger.test:#{@apache2.port}"
@@ -158,9 +165,10 @@ describe "Apache 2 module" do
158
165
 
159
166
  describe "compatibility with other modules" do
160
167
  before :all do
168
+ create_apache2_controller
161
169
  @apache2 << "RailsMaxPoolSize 1"
162
170
 
163
- @mycook = RailsStub.new('2.3/mycook')
171
+ @mycook = ClassicRailsStub.new('rails_apps/2.3/mycook')
164
172
  @mycook_url_root = "http://1.passenger.test:#{@apache2.port}"
165
173
  @apache2.set_vhost("1.passenger.test", "#{@mycook.full_app_root}/public") do |vhost|
166
174
  vhost << "RewriteEngine on"
@@ -172,6 +180,7 @@ describe "Apache 2 module" do
172
180
 
173
181
  after :all do
174
182
  @mycook.destroy
183
+ @apache2.stop if @apache2
175
184
  end
176
185
 
177
186
  before :each do
@@ -208,18 +217,16 @@ describe "Apache 2 module" do
208
217
 
209
218
  describe "configuration options" do
210
219
  before :all do
220
+ create_apache2_controller
211
221
  @apache2 << "PassengerMaxPoolSize 3"
212
222
 
213
- @mycook = RailsStub.new('2.3/mycook')
223
+ @mycook = ClassicRailsStub.new('rails_apps/2.3/mycook')
214
224
  @mycook_url_root = "http://1.passenger.test:#{@apache2.port}"
215
225
  @apache2.set_vhost('1.passenger.test', "#{@mycook.full_app_root}/public") do |vhost|
216
226
  vhost << "AllowEncodedSlashes on"
217
227
  end
218
- @apache2.set_vhost('2.passenger.test', "#{@mycook.full_app_root}/public") do |vhost|
219
- vhost << "RailsAutoDetect off"
220
- end
221
228
 
222
- @foobar = RailsStub.new('2.3/foobar')
229
+ @foobar = ClassicRailsStub.new('rails2.3')
223
230
  @foobar_url_root = "http://3.passenger.test:#{@apache2.port}"
224
231
  @apache2.set_vhost('3.passenger.test', "#{@foobar.full_app_root}/public") do |vhost|
225
232
  vhost << "RailsEnv development"
@@ -227,26 +234,12 @@ describe "Apache 2 module" do
227
234
  vhost << "PassengerRestartDir #{@foobar.full_app_root}/public"
228
235
  end
229
236
 
230
- @mycook2 = RailsStub.new('2.3/mycook')
237
+ @mycook2 = ClassicRailsStub.new('rails_apps/2.3/mycook')
231
238
  @mycook2_url_root = "http://4.passenger.test:#{@apache2.port}"
232
239
  @apache2.set_vhost('4.passenger.test', "#{@mycook2.full_app_root}/sites/some.site/public") do |vhost|
233
240
  vhost << "PassengerAppRoot #{@mycook2.full_app_root}"
234
241
  end
235
242
 
236
- # These are used by global queueing tests.
237
- @mycook3 = RailsStub.new('2.3/mycook')
238
- @mycook3_url_root = "http://5.passenger.test:#{@apache2.port}"
239
- @apache2.set_vhost('5.passenger.test', "#{@mycook3.full_app_root}/sites/some.site/public") do |vhost|
240
- vhost << "PassengerAppRoot #{@mycook3.full_app_root}"
241
- vhost << "PassengerMinInstances 3"
242
- end
243
- @mycook4 = RailsStub.new('2.3/mycook')
244
- @mycook4_url_root = "http://6.passenger.test:#{@apache2.port}"
245
- @apache2.set_vhost('6.passenger.test', "#{@mycook4.full_app_root}/public") do |vhost|
246
- vhost << "PassengerUseGlobalQueue on"
247
- vhost << "PassengerMinInstances 3"
248
- end
249
-
250
243
  @apache2.start
251
244
  end
252
245
 
@@ -254,26 +247,13 @@ describe "Apache 2 module" do
254
247
  @mycook.destroy
255
248
  @foobar.destroy
256
249
  @mycook2.destroy
257
- @mycook3.destroy
258
- @mycook4.destroy
250
+ @apache2.stop if @apache2
259
251
  end
260
252
 
261
253
  before :each do
262
254
  @mycook.reset
263
255
  @foobar.reset
264
256
  @mycook2.reset
265
- @mycook3.reset
266
- @mycook4.reset
267
- end
268
-
269
- it "ignores the Rails application if RailsAutoDetect is off" do
270
- @server = "http://2.passenger.test:#{@apache2.port}"
271
- get('/').should_not =~ /MyCook/
272
- end
273
-
274
- specify "setting RailsAutoDetect for one virtual host should not interfere with others" do
275
- @server = @mycook_url_root
276
- get('/').should =~ /MyCook/
277
257
  end
278
258
 
279
259
  specify "RailsEnv is per-virtual host" do
@@ -284,18 +264,6 @@ describe "Apache 2 module" do
284
264
  get('/foo/rails_env').should == "development"
285
265
  end
286
266
 
287
- it "supports conservative spawning" do
288
- @server = @foobar_url_root
289
- # TODO: I think this assertion is no longer valid now that
290
- # smart-lv2 is the default spawn method...
291
- get('/foo/backtrace').should_not =~ /framework_spawner/
292
- end
293
-
294
- specify "PassengerSpawnMethod spawning is per-virtual host" do
295
- @server = @mycook_url_root
296
- get('/welcome/backtrace').should =~ /application_spawner/
297
- end
298
-
299
267
  it "looks for restart.txt in the directory specified by PassengerRestartDir" do
300
268
  @server = @foobar_url_root
301
269
  controller = "#{@foobar.app_root}/app/controllers/bar_controller.rb"
@@ -325,88 +293,6 @@ describe "Apache 2 module" do
325
293
  get('/bar').should == "oh hai"
326
294
  end
327
295
 
328
- describe "PassengerUseGlobalQueue" do
329
- before :each do
330
-
331
- end
332
-
333
- after :each do
334
- # Restart Apache in order to reset the application pool's state.
335
- @apache2.stop
336
- end
337
-
338
- it "works and is per-virtual host" do
339
- @server = @mycook4_url_root
340
-
341
- # Spawn 3 application processes.
342
- get('/')
343
- eventually do
344
- inspect_server(:processes).size == 3
345
- end
346
-
347
- # Reserve all application pool slots.
348
- threads = []
349
- 3.times do |i|
350
- thread = Thread.new do
351
- File.unlink("#{@mycook4.app_root}/#{i}.txt") rescue nil
352
- get("/welcome/sleep_until_exists?name=#{i}.txt")
353
- end
354
- threads << thread
355
- end
356
-
357
- # Wait until all application instances are waiting
358
- # for the quit file.
359
- eventually(5) do
360
- File.exist?("#{@mycook4.app_root}/waiting_0.txt") &&
361
- File.exist?("#{@mycook4.app_root}/waiting_1.txt") &&
362
- File.exist?("#{@mycook4.app_root}/waiting_2.txt")
363
- end
364
- processes = inspect_server(:processes)
365
- processes.should have(3).items
366
- processes.each do |process|
367
- process.sessions.should == 1
368
- end
369
- inspect_server(:global_queue_size).should == 0
370
-
371
- # While all slots are reserved, make two more requests.
372
- first_request_done = false
373
- second_request_done = false
374
- thread = Thread.new do
375
- get("/")
376
- first_request_done = true
377
- end
378
- threads << thread
379
- thread = Thread.new do
380
- get("/")
381
- second_request_done = true
382
- end
383
- threads << thread
384
-
385
- # These requests should both be waiting on the global queue.
386
- sleep 1
387
- processes = inspect_server(:processes)
388
- processes.should have(3).items
389
- processes.each do |process|
390
- process.sessions.should == 1
391
- end
392
- inspect_server(:global_queue_size).should == 2
393
-
394
- # Both requests should be processed if one application instance frees up.
395
- File.touch("#{@mycook4.app_root}/2.txt")
396
- eventually(5) do
397
- first_request_done && second_request_done
398
- end
399
- inspect_server(:global_queue_size).should == 0
400
-
401
- File.touch("#{@mycook4.app_root}/0.txt")
402
- File.touch("#{@mycook4.app_root}/1.txt")
403
- File.touch("#{@mycook4.app_root}/2.txt")
404
- threads.each do |thread|
405
- thread.join
406
- end
407
- end
408
- end
409
-
410
296
  describe "PassengerAppRoot" do
411
297
  before :each do
412
298
  @server = @mycook2_url_root
@@ -454,16 +340,16 @@ describe "Apache 2 module" do
454
340
 
455
341
  describe "error handling" do
456
342
  before :all do
343
+ create_apache2_controller
457
344
  FileUtils.rm_rf('tmp.webdir')
458
345
  FileUtils.mkdir_p('tmp.webdir')
459
346
  @webdir = File.expand_path('tmp.webdir')
460
347
  @apache2.set_vhost('1.passenger.test', @webdir) do |vhost|
461
348
  vhost << "RailsBaseURI /app-with-nonexistant-rails-version/public"
462
349
  vhost << "RailsBaseURI /app-that-crashes-during-startup/public"
463
- vhost << "RailsBaseURI /app-with-crashing-vendor-rails/public"
464
350
  end
465
351
 
466
- @mycook = RailsStub.new('2.3/mycook')
352
+ @mycook = ClassicRailsStub.new('rails_apps/2.3/mycook')
467
353
  @mycook_url_root = "http://2.passenger.test:#{@apache2.port}"
468
354
  @apache2.set_vhost('2.passenger.test', "#{@mycook.full_app_root}/public")
469
355
 
@@ -473,6 +359,7 @@ describe "Apache 2 module" do
473
359
  after :all do
474
360
  FileUtils.rm_rf('tmp.webdir')
475
361
  @mycook.destroy
362
+ @apache2.stop if @apache2
476
363
  end
477
364
 
478
365
  before :each do
@@ -482,7 +369,7 @@ describe "Apache 2 module" do
482
369
  end
483
370
 
484
371
  it "displays an error page if the Rails application requires a nonexistant Rails version" do
485
- RailsStub.use('2.3/foobar', "#{@webdir}/app-with-nonexistant-rails-version") do |stub|
372
+ ClassicRailsStub.use('rails2.3', "#{@webdir}/app-with-nonexistant-rails-version") do |stub|
486
373
  File.write(stub.environment_rb) do |content|
487
374
  content.sub(/^RAILS_GEM_VERSION = .*$/, "RAILS_GEM_VERSION = '1.9.1234'")
488
375
  end
@@ -491,7 +378,7 @@ describe "Apache 2 module" do
491
378
  end
492
379
 
493
380
  it "displays an error page if the Rails application crashes during startup" do
494
- RailsStub.use('2.3/foobar', "#{@webdir}/app-that-crashes-during-startup") do |stub|
381
+ ClassicRailsStub.use('rails2.3', "#{@webdir}/app-that-crashes-during-startup") do |stub|
495
382
  File.prepend(stub.environment_rb, "raise 'app crash'")
496
383
  result = get("/app-that-crashes-during-startup/public")
497
384
  result.should =~ @error_page_signature
@@ -499,17 +386,6 @@ describe "Apache 2 module" do
499
386
  end
500
387
  end
501
388
 
502
- it "displays an error page if the Rails application's vendor'ed Rails crashes" do
503
- RailsStub.use('2.3/foobar', "#{@webdir}/app-with-crashing-vendor-rails") do |stub|
504
- stub.use_vendor_rails('minimal')
505
- File.append("#{stub.app_root}/vendor/rails/railties/lib/initializer.rb",
506
- "raise 'vendor crash'")
507
- result = get("/app-with-crashing-vendor-rails/public")
508
- result.should =~ @error_page_signature
509
- result.should =~ /vendor crash/
510
- end
511
- end
512
-
513
389
  it "displays an error if a filesystem permission error was encountered while autodetecting the application type" do
514
390
  @server = @mycook_url_root
515
391
  # This test used to fail because we were improperly blocking mod_autoindex,
@@ -522,7 +398,7 @@ describe "Apache 2 module" do
522
398
  end
523
399
 
524
400
  it "doesn't display a Ruby spawn error page if PassengerFriendlyErrorPages is off" do
525
- RailsStub.use('2.3/foobar', "#{@webdir}/app-that-crashes-during-startup") do |stub|
401
+ ClassicRailsStub.use('rails2.3', "#{@webdir}/app-that-crashes-during-startup") do |stub|
526
402
  File.write("#{stub.app_root}/public/.htaccess", "PassengerFriendlyErrorPages off")
527
403
  File.prepend(stub.environment_rb, "raise 'app crash'")
528
404
  result = get("/app-that-crashes-during-startup/public")
@@ -536,7 +412,8 @@ describe "Apache 2 module" do
536
412
  AdminTools = PhusionPassenger::AdminTools
537
413
 
538
414
  before :all do
539
- @mycook = RailsStub.new('2.3/mycook')
415
+ create_apache2_controller
416
+ @mycook = ClassicRailsStub.new('rails_apps/2.3/mycook')
540
417
  @mycook_url_root = "http://1.passenger.test:#{@apache2.port}"
541
418
  @apache2.set_vhost('1.passenger.test', "#{@mycook.full_app_root}/public")
542
419
  @apache2.start
@@ -545,6 +422,7 @@ describe "Apache 2 module" do
545
422
 
546
423
  after :all do
547
424
  @mycook.destroy
425
+ @apache2.stop if @apache2
548
426
  end
549
427
 
550
428
  before :each do
@@ -584,13 +462,14 @@ describe "Apache 2 module" do
584
462
  instance.processes
585
463
  end
586
464
  processes.should have(1).item
587
- processes[0].group.name.should == @mycook.full_app_root
465
+ processes[0].group.name.should == @mycook.full_app_root + "#default"
588
466
  processes[0].processed.should == 1
589
467
  end
590
468
  end
591
469
 
592
470
  describe "Rack application running in root URI" do
593
471
  before :all do
472
+ create_apache2_controller
594
473
  @stub = RackStub.new('rack')
595
474
  @apache2.set_vhost('passenger.test', @stub.full_app_root + "/public")
596
475
  @apache2.start
@@ -599,6 +478,7 @@ describe "Apache 2 module" do
599
478
 
600
479
  after :all do
601
480
  @stub.destroy
481
+ @apache2.stop if @apache2
602
482
  end
603
483
 
604
484
  it_should_behave_like "HelloWorld Rack application"
@@ -606,6 +486,7 @@ describe "Apache 2 module" do
606
486
 
607
487
  describe "Rack application running in sub-URI" do
608
488
  before :all do
489
+ create_apache2_controller
609
490
  FileUtils.rm_rf('tmp.webdir')
610
491
  FileUtils.mkdir_p('tmp.webdir')
611
492
  @stub = RackStub.new('rack')
@@ -620,6 +501,7 @@ describe "Apache 2 module" do
620
501
  after :all do
621
502
  @stub.destroy
622
503
  FileUtils.rm_rf('tmp.webdir')
504
+ @apache2.stop if @apache2
623
505
  end
624
506
 
625
507
  it_should_behave_like "HelloWorld Rack application"
@@ -627,7 +509,8 @@ describe "Apache 2 module" do
627
509
 
628
510
  describe "Rack application running within Rails directory structure" do
629
511
  before :all do
630
- @stub = RailsStub.new('2.3/mycook')
512
+ create_apache2_controller
513
+ @stub = ClassicRailsStub.new('rails_apps/2.3/mycook')
631
514
  FileUtils.cp_r("stub/rack/.", @stub.app_root)
632
515
  @apache2.set_vhost('passenger.test', @stub.full_app_root + "/public")
633
516
  @apache2.start
@@ -636,6 +519,7 @@ describe "Apache 2 module" do
636
519
 
637
520
  after :all do
638
521
  @stub.destroy
522
+ @apache2.stop if @apache2
639
523
  end
640
524
 
641
525
  it_should_behave_like "HelloWorld Rack application"
@@ -643,6 +527,7 @@ describe "Apache 2 module" do
643
527
 
644
528
  describe "WSGI application running in root URI" do
645
529
  before :all do
530
+ create_apache2_controller
646
531
  @stub = Stub.new('wsgi')
647
532
  @apache2.set_vhost('passenger.test', @stub.full_app_root + "/public")
648
533
  @apache2.start
@@ -651,6 +536,7 @@ describe "Apache 2 module" do
651
536
 
652
537
  after :all do
653
538
  @stub.destroy
539
+ @apache2.stop if @apache2
654
540
  end
655
541
 
656
542
  it_should_behave_like "HelloWorld WSGI application"