passenger 4.0.48 → 4.0.49

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 (218) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/.editorconfig +36 -2
  5. data/.travis.yml +1 -1
  6. data/CHANGELOG +16 -0
  7. data/Rakefile +0 -1
  8. data/build/apache2.rb +4 -4
  9. data/build/common_library.rb +18 -18
  10. data/build/cplusplus_support.rb +2 -2
  11. data/build/documentation.rb +1 -1
  12. data/build/integration_tests.rb +12 -4
  13. data/build/misc.rb +12 -7
  14. data/build/packaging.rb +14 -14
  15. data/build/preprocessor.rb +10 -10
  16. data/build/rake_extensions.rb +11 -11
  17. data/build/ruby_extension.rb +2 -2
  18. data/dev/ci/inituidgid +24 -0
  19. data/dev/ci/run_jenkins.sh +57 -0
  20. data/dev/ci/run_rpm_tests.sh +77 -0
  21. data/dev/{run_travis.sh → ci/run_travis.sh} +60 -4
  22. data/doc/Users guide Nginx.txt +2 -2
  23. data/doc/users_guide_snippets/environment_variables.txt +0 -2
  24. data/doc/users_guide_snippets/tips.txt +20 -1
  25. data/ext/apache2/Bucket.cpp +18 -18
  26. data/ext/apache2/Bucket.h +4 -4
  27. data/ext/apache2/Configuration.cpp +7 -7
  28. data/ext/apache2/Configuration.hpp +43 -43
  29. data/ext/apache2/DirectoryMapper.h +5 -5
  30. data/ext/apache2/Hooks.cpp +142 -142
  31. data/ext/apache2/MergeDirConfig.cpp +40 -40
  32. data/ext/common/Account.h +17 -17
  33. data/ext/common/AccountsDatabase.h +9 -9
  34. data/ext/common/AgentsStarter.cpp +2 -2
  35. data/ext/common/AgentsStarter.h +40 -40
  36. data/ext/common/ApplicationPool2/Common.h +10 -6
  37. data/ext/common/ApplicationPool2/ComponentInfo.h +2 -2
  38. data/ext/common/ApplicationPool2/DirectSpawner.h +17 -17
  39. data/ext/common/ApplicationPool2/DummySpawner.h +5 -5
  40. data/ext/common/ApplicationPool2/Group.h +54 -38
  41. data/ext/common/ApplicationPool2/Implementation.cpp +76 -49
  42. data/ext/common/ApplicationPool2/Options.h +98 -91
  43. data/ext/common/ApplicationPool2/Pool.h +70 -69
  44. data/ext/common/ApplicationPool2/Process.h +21 -21
  45. data/ext/common/ApplicationPool2/Session.h +11 -11
  46. data/ext/common/ApplicationPool2/SmartSpawner.h +60 -60
  47. data/ext/common/ApplicationPool2/Socket.h +19 -19
  48. data/ext/common/ApplicationPool2/Spawner.h +64 -72
  49. data/ext/common/ApplicationPool2/SpawnerFactory.h +4 -4
  50. data/ext/common/ApplicationPool2/SuperGroup.h +41 -41
  51. data/ext/common/BackgroundEventLoop.cpp +1 -1
  52. data/ext/common/BackgroundEventLoop.h +2 -2
  53. data/ext/common/Constants.h +1 -1
  54. data/ext/common/EventedBufferedInput.h +5 -5
  55. data/ext/common/EventedClient.h +51 -51
  56. data/ext/common/EventedMessageServer.h +39 -39
  57. data/ext/common/EventedServer.h +32 -32
  58. data/ext/common/Exceptions.h +23 -23
  59. data/ext/common/FileDescriptor.h +18 -18
  60. data/ext/common/Logging.cpp +1 -1
  61. data/ext/common/MessageClient.h +27 -27
  62. data/ext/common/MessageReadersWriters.h +79 -79
  63. data/ext/common/MessageServer.h +59 -59
  64. data/ext/common/RandomGenerator.h +12 -12
  65. data/ext/common/ResourceLocator.h +8 -8
  66. data/ext/common/SafeLibev.h +54 -25
  67. data/ext/common/ServerInstanceDir.h +31 -31
  68. data/ext/common/StaticString.h +50 -48
  69. data/ext/common/Utils.cpp +73 -78
  70. data/ext/common/Utils.h +6 -6
  71. data/ext/common/Utils/Base64.cpp +3 -3
  72. data/ext/common/Utils/Base64.h +7 -7
  73. data/ext/common/Utils/BlockingQueue.h +9 -9
  74. data/ext/common/Utils/BufferedIO.h +17 -17
  75. data/ext/common/Utils/CachedFileStat.hpp +16 -16
  76. data/ext/common/Utils/Dechunker.h +25 -25
  77. data/ext/common/Utils/FileChangeChecker.h +10 -10
  78. data/ext/common/Utils/MemZeroGuard.h +5 -5
  79. data/ext/common/Utils/MemoryBarrier.h +1 -1
  80. data/ext/common/Utils/MessageIO.h +61 -61
  81. data/ext/common/Utils/ProcessMetricsCollector.h +40 -40
  82. data/ext/common/Utils/ScopeGuard.h +7 -7
  83. data/ext/common/Utils/SpeedMeter.h +1 -1
  84. data/ext/common/Utils/StrIntUtils.cpp +13 -13
  85. data/ext/common/Utils/StrIntUtils.h +3 -3
  86. data/ext/common/Utils/StringScanning.h +5 -5
  87. data/ext/common/Utils/SystemMetricsCollector.h +2 -2
  88. data/ext/common/Utils/SystemTime.h +10 -10
  89. data/ext/common/Utils/Template.h +2 -2
  90. data/ext/common/Utils/Timer.h +6 -6
  91. data/ext/common/Utils/VariantMap.h +29 -29
  92. data/ext/common/agents/Base.cpp +19 -19
  93. data/ext/common/agents/HelperAgent/AgentOptions.h +1 -1
  94. data/ext/common/agents/HelperAgent/FileBackedPipe.h +6 -6
  95. data/ext/common/agents/HelperAgent/Main.cpp +44 -43
  96. data/ext/common/agents/HelperAgent/RequestHandler.cpp +4 -4
  97. data/ext/common/agents/HelperAgent/RequestHandler.h +29 -28
  98. data/ext/common/agents/HelperAgent/ScgiRequestParser.h +56 -50
  99. data/ext/common/agents/LoggingAgent/AdminController.h +8 -8
  100. data/ext/common/agents/LoggingAgent/DataStoreId.h +17 -17
  101. data/ext/common/agents/LoggingAgent/FilterSupport.h +167 -167
  102. data/ext/common/agents/LoggingAgent/LoggingServer.h +122 -122
  103. data/ext/common/agents/LoggingAgent/Main.cpp +7 -7
  104. data/ext/common/agents/LoggingAgent/RemoteSender.h +54 -54
  105. data/ext/common/agents/SpawnPreparer.cpp +4 -4
  106. data/ext/common/agents/TempDirToucher.c +2 -2
  107. data/ext/common/agents/Watchdog/AgentWatcher.cpp +47 -47
  108. data/ext/common/agents/Watchdog/HelperAgentWatcher.cpp +7 -7
  109. data/ext/common/agents/Watchdog/LoggingAgentWatcher.cpp +7 -7
  110. data/ext/common/agents/Watchdog/Main.cpp +22 -22
  111. data/ext/common/agents/Watchdog/ServerInstanceDirToucher.cpp +9 -9
  112. data/ext/libeio/eio.c +1 -1
  113. data/ext/nginx/Configuration.c +30 -30
  114. data/ext/nginx/Configuration.h +1 -1
  115. data/ext/nginx/ContentHandler.c +54 -54
  116. data/ext/nginx/ContentHandler.h +3 -3
  117. data/ext/nginx/StaticContentHandler.c +2 -2
  118. data/ext/nginx/ngx_http_passenger_module.c +21 -21
  119. data/ext/oxt/detail/backtrace_enabled.hpp +1 -1
  120. data/ext/oxt/detail/context.hpp +1 -1
  121. data/ext/oxt/detail/spin_lock_darwin.hpp +4 -4
  122. data/ext/oxt/detail/spin_lock_gcc_x86.hpp +3 -3
  123. data/ext/oxt/detail/spin_lock_pthreads.hpp +4 -4
  124. data/ext/oxt/detail/tracable_exception_disabled.hpp +1 -1
  125. data/ext/oxt/dynamic_thread_group.hpp +18 -18
  126. data/ext/oxt/implementation.cpp +9 -8
  127. data/ext/oxt/macros.hpp +2 -2
  128. data/ext/oxt/system_calls.cpp +11 -11
  129. data/ext/oxt/system_calls.hpp +13 -13
  130. data/ext/oxt/thread.hpp +22 -14
  131. data/ext/ruby/passenger_native_support.c +55 -55
  132. data/lib/phusion_passenger.rb +24 -24
  133. data/lib/phusion_passenger/common_library.rb +2 -0
  134. data/lib/phusion_passenger/loader_shared_helpers.rb +18 -18
  135. data/lib/phusion_passenger/packaging.rb +9 -4
  136. data/lib/phusion_passenger/platform_info/apache.rb +45 -31
  137. data/lib/phusion_passenger/platform_info/compiler.rb +11 -11
  138. data/lib/phusion_passenger/rack/thread_handler_extension.rb +1 -1
  139. data/lib/phusion_passenger/request_handler/thread_handler.rb +8 -8
  140. data/lib/phusion_passenger/standalone/app_finder.rb +16 -16
  141. data/lib/phusion_passenger/standalone/command.rb +22 -22
  142. data/packaging/rpm/LICENSE.txt +19 -0
  143. data/packaging/rpm/Makefile +13 -0
  144. data/packaging/rpm/README.md +41 -0
  145. data/packaging/rpm/Vagrantfile +38 -0
  146. data/{rpm/Vagrantfile → packaging/rpm/Vagrantfile.centos} +0 -0
  147. data/packaging/rpm/build +170 -0
  148. data/packaging/rpm/create_project +41 -0
  149. data/packaging/rpm/git_update +88 -0
  150. data/packaging/rpm/image/Dockerfile +37 -0
  151. data/packaging/rpm/image/Gemfile +3 -0
  152. data/packaging/rpm/image/Gemfile.lock +12 -0
  153. data/packaging/rpm/image/RPM-GPG-KEY-amazon-ga +19 -0
  154. data/packaging/rpm/image/amazon2014-i386.cfg +96 -0
  155. data/packaging/rpm/image/amazon2014-x86_64.cfg +96 -0
  156. data/packaging/rpm/image/site-defaults.cfg +168 -0
  157. data/packaging/rpm/internal/build_tasks.rb +238 -0
  158. data/packaging/rpm/internal/dummygpg +11 -0
  159. data/packaging/rpm/internal/exec_build +42 -0
  160. data/packaging/rpm/internal/get_distro_arch +14 -0
  161. data/packaging/rpm/internal/get_distro_id +10 -0
  162. data/packaging/rpm/internal/git_update +27 -0
  163. data/packaging/rpm/internal/inituidgid +17 -0
  164. data/packaging/rpm/internal/my_init +344 -0
  165. data/packaging/rpm/internal/python27 +3 -0
  166. data/packaging/rpm/internal/repo_update +46 -0
  167. data/packaging/rpm/internal/setuser +26 -0
  168. data/packaging/rpm/internal/tracking_helper +40 -0
  169. data/packaging/rpm/jenkins_release +99 -0
  170. data/packaging/rpm/lib/build_tasks_support.rb +402 -0
  171. data/packaging/rpm/lib/preprocessor.rb +341 -0
  172. data/packaging/rpm/nginx_spec/404.html +119 -0
  173. data/packaging/rpm/nginx_spec/50x.html +119 -0
  174. data/packaging/rpm/nginx_spec/index.html +116 -0
  175. data/packaging/rpm/nginx_spec/nginx-auto-cc-gcc.patch +13 -0
  176. data/packaging/rpm/nginx_spec/nginx-logo.png +0 -0
  177. data/packaging/rpm/nginx_spec/nginx-upgrade +13 -0
  178. data/packaging/rpm/nginx_spec/nginx-upgrade.8 +151 -0
  179. data/packaging/rpm/nginx_spec/nginx.conf +131 -0
  180. data/packaging/rpm/nginx_spec/nginx.init +144 -0
  181. data/packaging/rpm/nginx_spec/nginx.logrotate +13 -0
  182. data/packaging/rpm/nginx_spec/nginx.service +15 -0
  183. data/packaging/rpm/nginx_spec/nginx.spec.template +559 -0
  184. data/packaging/rpm/nginx_spec/nginx.sysconfig +4 -0
  185. data/packaging/rpm/nginx_spec/passenger.conf +9 -0
  186. data/packaging/rpm/nginx_spec/poweredby.png +0 -0
  187. data/{rpm → packaging/rpm/passenger_spec}/apache-passenger.conf.in +0 -0
  188. data/{rpm → packaging/rpm/passenger_spec}/config.json +0 -0
  189. data/{rpm → packaging/rpm/passenger_spec}/passenger.logrotate +0 -0
  190. data/{rpm → packaging/rpm/passenger_spec}/passenger.spec.template +58 -31
  191. data/{rpm → packaging/rpm/passenger_spec}/passenger_dynamic_thread_group.patch +0 -0
  192. data/{rpm → packaging/rpm/passenger_spec}/passenger_tests_default_config_example.patch +0 -0
  193. data/{rpm → packaging/rpm/passenger_spec}/rubygem-passenger-4.0.18-GLIBC_HAVE_LONG_LONG.patch +0 -0
  194. data/{rpm → packaging/rpm/passenger_spec}/rubygem-passenger-4.0.18-gcc47-include-sys_types.patch +0 -0
  195. data/packaging/rpm/repo_update +114 -0
  196. data/packaging/rpm/setup-system +60 -0
  197. data/packaging/rpm/shell +10 -0
  198. data/resources/templates/standalone/config.erb +3 -1
  199. data/test/config.json.rpm-automation +1 -1
  200. data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +11 -11
  201. data/test/cxx/ApplicationPool2/OptionsTest.cpp +5 -5
  202. data/test/cxx/ApplicationPool2/PoolTest.cpp +129 -89
  203. data/test/cxx/ApplicationPool2/ProcessTest.cpp +15 -15
  204. data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +22 -22
  205. data/test/cxx/ApplicationPool2/SpawnerTestCases.cpp +11 -11
  206. data/test/cxx/ScgiRequestParserTest.cpp +75 -61
  207. data/test/cxx/UtilsTest.cpp +86 -85
  208. data/test/gdbinit.example +3 -0
  209. data/test/integration_tests/nginx_tests.rb +3 -3
  210. data/test/integration_tests/source_packaging_test.rb +3 -1
  211. data/test/stub/nginx/nginx.conf.erb +8 -1
  212. data/test/support/nginx_controller.rb +7 -7
  213. metadata +62 -17
  214. metadata.gz.asc +7 -7
  215. data/build/rpm.rb +0 -128
  216. data/dev/rpmtool +0 -21
  217. data/dev/test_rpm_packaging.sh +0 -28
  218. data/rpm/get_distro_id.py +0 -4
@@ -13,39 +13,39 @@ namespace tut {
13
13
  SocketPair adminSocket;
14
14
  Pipe errorPipe;
15
15
  FileDescriptor server1, server2, server3;
16
-
16
+
17
17
  ApplicationPool2_ProcessTest() {
18
18
  bg.start();
19
-
19
+
20
20
  struct sockaddr_in addr;
21
21
  socklen_t len = sizeof(addr);
22
22
  sockets = boost::make_shared<SocketList>();
23
-
23
+
24
24
  server1 = createTcpServer("127.0.0.1", 0);
25
25
  getsockname(server1, (struct sockaddr *) &addr, &len);
26
26
  sockets->add("main1",
27
27
  "tcp://127.0.0.1:" + toString(addr.sin_port),
28
28
  "session", 3);
29
-
29
+
30
30
  server2 = createTcpServer("127.0.0.1", 0);
31
31
  getsockname(server2, (struct sockaddr *) &addr, &len);
32
32
  sockets->add("main2",
33
33
  "tcp://127.0.0.1:" + toString(addr.sin_port),
34
34
  "session", 3);
35
-
35
+
36
36
  server3 = createTcpServer("127.0.0.1", 0);
37
37
  getsockname(server3, (struct sockaddr *) &addr, &len);
38
38
  sockets->add("main3",
39
39
  "tcp://127.0.0.1:" + toString(addr.sin_port),
40
40
  "session", 3);
41
-
41
+
42
42
  adminSocket = createUnixSocketPair();
43
43
  errorPipe = createPipe();
44
44
  }
45
45
  };
46
-
46
+
47
47
  DEFINE_TEST_GROUP(ApplicationPool2_ProcessTest);
48
-
48
+
49
49
  TEST_METHOD(1) {
50
50
  // Test initial state.
51
51
  ProcessPtr process = boost::make_shared<Process>(
@@ -56,7 +56,7 @@ namespace tut {
56
56
  ensure_equals(process->busyness(), 0);
57
57
  ensure(!process->isTotallyBusy());
58
58
  }
59
-
59
+
60
60
  TEST_METHOD(2) {
61
61
  // Test opening and closing sessions.
62
62
  ProcessPtr process = boost::make_shared<Process>(
@@ -72,7 +72,7 @@ namespace tut {
72
72
  process->sessionClosed(session2.get());
73
73
  ensure_equals(process->sessions, 0);
74
74
  }
75
-
75
+
76
76
  TEST_METHOD(3) {
77
77
  // newSession() checks out the socket with the smallest busyness number
78
78
  // and sessionClosed() restores the session busyness statistics.
@@ -81,7 +81,7 @@ namespace tut {
81
81
  errorPipe[0], sockets, 0, 0);
82
82
  process->dummy = true;
83
83
  process->requiresShutdown = false;
84
-
84
+
85
85
  // The first 3 newSession() commands check out an idle socket.
86
86
  SessionPtr session1 = process->newSession();
87
87
  SessionPtr session2 = process->newSession();
@@ -89,12 +89,12 @@ namespace tut {
89
89
  ensure(session1->getSocket()->name != session2->getSocket()->name);
90
90
  ensure(session1->getSocket()->name != session3->getSocket()->name);
91
91
  ensure(session2->getSocket()->name != session3->getSocket()->name);
92
-
92
+
93
93
  // The next 2 newSession() commands check out sockets with sessions == 1.
94
94
  SessionPtr session4 = process->newSession();
95
95
  SessionPtr session5 = process->newSession();
96
96
  ensure(session4->getSocket()->name != session5->getSocket()->name);
97
-
97
+
98
98
  // There should now be 1 process with 1 session
99
99
  // and 2 processes with 2 sessions.
100
100
  map<int, int> sessionCount;
@@ -105,7 +105,7 @@ namespace tut {
105
105
  ensure_equals(sessionCount.size(), 2u);
106
106
  ensure_equals(sessionCount[1], 1);
107
107
  ensure_equals(sessionCount[2], 2);
108
-
108
+
109
109
  // Closing the first 3 sessions will result in no processes having 1 session
110
110
  // and 1 process having 2 sessions.
111
111
  process->sessionClosed(session1.get());
@@ -118,7 +118,7 @@ namespace tut {
118
118
  ensure_equals(sessionCount[0], 1);
119
119
  ensure_equals(sessionCount[1], 2);
120
120
  }
121
-
121
+
122
122
  TEST_METHOD(4) {
123
123
  // If all sockets are at their full capacity then newSession() will fail.
124
124
  ProcessPtr process = boost::make_shared<Process>(
@@ -19,7 +19,7 @@ namespace tut {
19
19
  PipeWatcher::DataCallback gatherOutput;
20
20
  string gatheredOutput;
21
21
  boost::mutex gatheredOutputSyncher;
22
-
22
+
23
23
  ApplicationPool2_SmartSpawnerTest() {
24
24
  createServerInstanceDirAndGeneration(serverInstanceDir, generation);
25
25
  PipeWatcher::onData = PipeWatcher::DataCallback();
@@ -27,32 +27,32 @@ namespace tut {
27
27
  setLogLevel(LVL_ERROR); // TODO: should be LVL_WARN
28
28
  setPrintAppOutputAsDebuggingMessages(true);
29
29
  }
30
-
30
+
31
31
  ~ApplicationPool2_SmartSpawnerTest() {
32
32
  setLogLevel(DEFAULT_LOG_LEVEL);
33
33
  setPrintAppOutputAsDebuggingMessages(false);
34
34
  unlink("stub/wsgi/passenger_wsgi.pyc");
35
35
  PipeWatcher::onData = PipeWatcher::DataCallback();
36
36
  }
37
-
37
+
38
38
  boost::shared_ptr<SmartSpawner> createSpawner(const Options &options, bool exitImmediately = false) {
39
39
  char buf[PATH_MAX + 1];
40
40
  getcwd(buf, PATH_MAX);
41
-
41
+
42
42
  vector<string> command;
43
43
  command.push_back("ruby");
44
44
  command.push_back(string(buf) + "/support/placebo-preloader.rb");
45
45
  if (exitImmediately) {
46
46
  command.push_back("exit-immediately");
47
47
  }
48
-
48
+
49
49
  return boost::make_shared<SmartSpawner>(
50
50
  generation,
51
51
  command,
52
52
  options,
53
53
  make_shared<SpawnerConfig>(*resourceLocator));
54
54
  }
55
-
55
+
56
56
  Options createOptions() {
57
57
  Options options;
58
58
  options.spawnMethod = "smart";
@@ -65,11 +65,11 @@ namespace tut {
65
65
  gatheredOutput.append(data, size);
66
66
  }
67
67
  };
68
-
68
+
69
69
  DEFINE_TEST_GROUP_WITH_LIMIT(ApplicationPool2_SmartSpawnerTest, 90);
70
-
70
+
71
71
  #include "SpawnerTestCases.cpp"
72
-
72
+
73
73
  TEST_METHOD(80) {
74
74
  // If the preloader has crashed then SmartSpawner will
75
75
  // restart it and try again.
@@ -81,16 +81,16 @@ namespace tut {
81
81
  setLogLevel(LVL_CRIT);
82
82
  process = spawner->spawn(options);
83
83
  process->requiresShutdown = false;
84
-
84
+
85
85
  kill(spawner->getPreloaderPid(), SIGTERM);
86
86
  // Give it some time to exit.
87
87
  usleep(300000);
88
-
88
+
89
89
  // No exception at next spawn.
90
90
  process = spawner->spawn(options);
91
91
  process->requiresShutdown = false;
92
92
  }
93
-
93
+
94
94
  TEST_METHOD(81) {
95
95
  // If the preloader still crashes after the restart then
96
96
  // SmartSpawner will throw an exception.
@@ -108,7 +108,7 @@ namespace tut {
108
108
  // Pass.
109
109
  }
110
110
  }
111
-
111
+
112
112
  TEST_METHOD(82) {
113
113
  // If the preloader didn't start within the timeout
114
114
  // then it's killed and an exception is thrown, with
@@ -118,7 +118,7 @@ namespace tut {
118
118
  options.startCommand = "ruby\t" "start.rb";
119
119
  options.startupFile = "start.rb";
120
120
  options.startTimeout = 300;
121
-
121
+
122
122
  vector<string> preloaderCommand;
123
123
  preloaderCommand.push_back("bash");
124
124
  preloaderCommand.push_back("-c");
@@ -129,7 +129,7 @@ namespace tut {
129
129
  options,
130
130
  make_shared<SpawnerConfig>(*resourceLocator));
131
131
  setLogLevel(LVL_CRIT);
132
-
132
+
133
133
  try {
134
134
  process = spawner.spawn(options);
135
135
  process->requiresShutdown = false;
@@ -140,7 +140,7 @@ namespace tut {
140
140
  ensure(e.getErrorPage().find("hello world\n") != string::npos);
141
141
  }
142
142
  }
143
-
143
+
144
144
  TEST_METHOD(83) {
145
145
  // If the preloader crashed during startup without returning
146
146
  // a proper error response, then its stderr output is used
@@ -149,7 +149,7 @@ namespace tut {
149
149
  options.appRoot = "stub/rack";
150
150
  options.startCommand = "ruby\t" "start.rb";
151
151
  options.startupFile = "start.rb";
152
-
152
+
153
153
  vector<string> preloaderCommand;
154
154
  preloaderCommand.push_back("bash");
155
155
  preloaderCommand.push_back("-c");
@@ -180,7 +180,7 @@ namespace tut {
180
180
  options.startCommand = "ruby\t" "start.rb";
181
181
  options.startupFile = "start.rb";
182
182
  options.environmentVariables.push_back(make_pair("PASSENGER_FOO", "foo"));
183
-
183
+
184
184
  vector<string> preloaderCommand;
185
185
  preloaderCommand.push_back("bash");
186
186
  preloaderCommand.push_back("-c");
@@ -191,7 +191,7 @@ namespace tut {
191
191
  options,
192
192
  make_shared<SpawnerConfig>(*resourceLocator));
193
193
  setLogLevel(LVL_CRIT);
194
-
194
+
195
195
  try {
196
196
  process = spawner.spawn(options);
197
197
  process->requiresShutdown = false;
@@ -208,7 +208,7 @@ namespace tut {
208
208
  PipeWatcher::onData = gatherOutput;
209
209
  Options options = createOptions();
210
210
  options.appRoot = "stub/rack";
211
-
211
+
212
212
  {
213
213
  vector<string> preloaderCommand;
214
214
  preloaderCommand.push_back("ruby");
@@ -221,10 +221,10 @@ namespace tut {
221
221
  process = spawner.spawn(options);
222
222
  process->requiresShutdown = false;
223
223
  }
224
-
224
+
225
225
  SessionPtr session = process->newSession();
226
226
  session->initiate();
227
-
227
+
228
228
  const char header[] =
229
229
  "REQUEST_METHOD\0GET\0"
230
230
  "PATH_INFO\0/print_stderr\0";
@@ -31,7 +31,7 @@
31
31
  (void) uid; (void) gid; (void) groups
32
32
 
33
33
  typedef boost::shared_ptr<Spawner> SpawnerPtr;
34
-
34
+
35
35
  static void addUserSwitchingCode() {
36
36
  FILE *f = fopen("tmp.wsgi/passenger_wsgi.py", "a");
37
37
  fputs(
@@ -84,7 +84,7 @@
84
84
  process = spawner->spawn(options);
85
85
  process->requiresShutdown = false;
86
86
  ensure_equals(process->sockets->size(), 1u);
87
-
87
+
88
88
  Connection conn = process->sockets->front().checkoutConnection();
89
89
  ScopeGuard guard(boost::bind(checkin, process, &conn));
90
90
  writeExact(conn.fd, "ping\n");
@@ -181,13 +181,13 @@
181
181
  process = spawner->spawn(options);
182
182
  process->requiresShutdown = false;
183
183
  ensure_equals(process->sockets->size(), 1u);
184
-
184
+
185
185
  Connection conn = process->sockets->front().checkoutConnection();
186
186
  ScopeGuard guard(boost::bind(checkin, process, &conn));
187
187
  writeExact(conn.fd, "pid\n");
188
188
  ensure_equals(readAll(conn.fd), toString(process->pid) + "\n");
189
189
  }
190
-
190
+
191
191
  TEST_METHOD(7) {
192
192
  // Custom environment variables can be passed.
193
193
  Options options = createOptions();
@@ -200,7 +200,7 @@
200
200
  process = spawner->spawn(options);
201
201
  process->requiresShutdown = false;
202
202
  ensure_equals(process->sockets->size(), 1u);
203
-
203
+
204
204
  Connection conn = process->sockets->front().checkoutConnection();
205
205
  ScopeGuard guard(boost::bind(checkin, process, &conn));
206
206
  writeExact(conn.fd, "envvars\n");
@@ -296,10 +296,10 @@
296
296
  SpawnerPtr spawner = createSpawner(options);
297
297
  process = spawner->spawn(options);
298
298
  process->requiresShutdown = false;
299
-
299
+
300
300
  SessionPtr session = process->newSession();
301
301
  session->initiate();
302
-
302
+
303
303
  setLogLevel(LVL_ERROR); // TODO: should be LVL_WARN
304
304
  const char header[] =
305
305
  "REQUEST_METHOD\0GET\0"
@@ -336,7 +336,7 @@
336
336
  SpawnerPtr spawner = createSpawner(options);
337
337
  process = spawner->spawn(options);
338
338
  process->requiresShutdown = false;
339
-
339
+
340
340
  ensure_equals(process->codeRevision, "hello");
341
341
  }
342
342
 
@@ -354,10 +354,10 @@
354
354
  SpawnerPtr spawner = createSpawner(options);
355
355
  process = spawner->spawn(options);
356
356
  process->requiresShutdown = false;
357
-
357
+
358
358
  ensure_equals(process->codeRevision, "today");
359
359
  }
360
-
360
+
361
361
  // It raises an exception if getStartupCommand() is empty.
362
362
 
363
363
  /******* User switching tests *******/
@@ -820,6 +820,6 @@
820
820
  }
821
821
  defaultGroups.erase(0, pos);
822
822
  }
823
-
823
+
824
824
  ensure_equals(groups, defaultGroups);
825
825
  }
@@ -8,7 +8,7 @@ namespace tut {
8
8
  struct ScgiRequestParserTest {
9
9
  ScgiRequestParser parser;
10
10
  };
11
-
11
+
12
12
  DEFINE_TEST_GROUP(ScgiRequestParserTest);
13
13
 
14
14
  TEST_METHOD(1) {
@@ -17,9 +17,9 @@ namespace tut {
17
17
  ensure_equals(parser.getState(), ScgiRequestParser::READING_LENGTH_STRING);
18
18
  ensure(parser.getHeaderData().empty());
19
19
  }
20
-
20
+
21
21
  /***** Test parsing a complete SCGI request in a single pass. *****/
22
-
22
+
23
23
  TEST_METHOD(2) {
24
24
  // Parsing a request with a single header and no body.
25
25
  static const char data[] = "12:hello\0world\0,";
@@ -33,7 +33,7 @@ namespace tut {
33
33
  string("hello\0world\0", 12));
34
34
  ensure(parser.getHeader("hello") == "world");
35
35
  }
36
-
36
+
37
37
  TEST_METHOD(3) {
38
38
  // Parsing a request with a single header and a body.
39
39
  static const char data[] = "12:hello\0world\0,data";
@@ -47,7 +47,7 @@ namespace tut {
47
47
  string("hello\0world\0", 12));
48
48
  ensure(parser.getHeader("hello") == "world");
49
49
  }
50
-
50
+
51
51
  TEST_METHOD(4) {
52
52
  // Parsing a request with multiple headers and no body.
53
53
  static const char data[] = "19:hello\0world\0SCGI\0001\0,";
@@ -62,7 +62,7 @@ namespace tut {
62
62
  ensure(parser.getHeader("hello") == "world");
63
63
  ensure(parser.getHeader("SCGI") == "1");
64
64
  }
65
-
65
+
66
66
  TEST_METHOD(5) {
67
67
  // Parsing a request with multiple headers and a body.
68
68
  static const char data[] = "19:hello\0world\0SCGI\0001\0,body";
@@ -77,7 +77,7 @@ namespace tut {
77
77
  ensure(parser.getHeader("hello") == "world");
78
78
  ensure(parser.getHeader("SCGI") == "1");
79
79
  }
80
-
80
+
81
81
  TEST_METHOD(6) {
82
82
  // Parsing a request that's larger than the limit.
83
83
  parser = ScgiRequestParser(9);
@@ -87,9 +87,9 @@ namespace tut {
87
87
  ensure_equals(parser.getErrorReason(),
88
88
  ScgiRequestParser::LIMIT_REACHED);
89
89
  }
90
-
90
+
91
91
  /***** Test parsing a complete SCGI request in multiple passes. *****/
92
-
92
+
93
93
  TEST_METHOD(8) {
94
94
  // Parsing a request with multiple headers and a body.
95
95
  // 1 byte per pass.
@@ -105,7 +105,7 @@ namespace tut {
105
105
  ensure(parser.getHeader("hello") == "world");
106
106
  ensure(parser.getHeader("foo") == "bar");
107
107
  }
108
-
108
+
109
109
  TEST_METHOD(9) {
110
110
  // Parsing a request with multiple headers and a body.
111
111
  // Half element per pass.
@@ -125,7 +125,7 @@ namespace tut {
125
125
  ensure(parser.getHeader("hello") == "world");
126
126
  ensure(parser.getHeader("foo") == "bar");
127
127
  }
128
-
128
+
129
129
  TEST_METHOD(10) {
130
130
  // Parsing a request with multiple headers and a body.
131
131
  // 1 element per pass.
@@ -142,7 +142,7 @@ namespace tut {
142
142
  ensure(parser.getHeader("hello") == "world");
143
143
  ensure(parser.getHeader("foo") == "bar");
144
144
  }
145
-
145
+
146
146
  TEST_METHOD(11) {
147
147
  // Parsing a request with multiple headers and a body.
148
148
  // 2 elements per pass.
@@ -157,7 +157,7 @@ namespace tut {
157
157
  ensure(parser.getHeader("hello") == "world");
158
158
  ensure(parser.getHeader("foo") == "bar");
159
159
  }
160
-
160
+
161
161
  TEST_METHOD(12) {
162
162
  // Parsing a request with multiple headers and a body.
163
163
  // Variable number of elements per pass.
@@ -185,9 +185,9 @@ namespace tut {
185
185
  ensure(parser.getHeader("hello") == "world");
186
186
  ensure(parser.getHeader("foo") == "bar");
187
187
  }
188
-
188
+
189
189
  /***** Test parsing invalid SCGI requests in one pass. *****/
190
-
190
+
191
191
  TEST_METHOD(16) {
192
192
  // Invalid first character for length string.
193
193
  ensure_equals("Parser did not accept anything.",
@@ -195,56 +195,56 @@ namespace tut {
195
195
  ensure_equals("Parser is in the error state.",
196
196
  parser.getState(), ScgiRequestParser::ERROR);
197
197
  }
198
-
198
+
199
199
  TEST_METHOD(17) {
200
200
  // Invalid character inside length string.
201
201
  ensure_equals(parser.feed("12x:hello world!", 16), 2u);
202
202
  ensure_equals("Parser is in the error state.",
203
203
  parser.getState(), ScgiRequestParser::ERROR);
204
204
  }
205
-
205
+
206
206
  TEST_METHOD(18) {
207
207
  // Invalid character in place of colon.
208
208
  ensure_equals(parser.feed("12#hello world!", 15), 2u);
209
209
  ensure_equals("Parser is in the error state.",
210
210
  parser.getState(), ScgiRequestParser::ERROR);
211
211
  }
212
-
212
+
213
213
  TEST_METHOD(19) {
214
214
  // Invalid character in place of comma.
215
215
  ensure_equals(parser.feed("12:hello\0world\0!", 16), 15u);
216
216
  ensure_equals("Parser is in the error state.",
217
217
  parser.getState(), ScgiRequestParser::ERROR);
218
218
  }
219
-
219
+
220
220
  TEST_METHOD(20) {
221
221
  // Only a header name, without even a null terminator.
222
222
  ensure_equals(parser.feed("5:hello,", 8), (size_t) 8);
223
223
  ensure_equals("Parser is in the error state.",
224
224
  parser.getState(), ScgiRequestParser::ERROR);
225
225
  }
226
-
226
+
227
227
  TEST_METHOD(21) {
228
228
  // Only a header name, with a null terminator.
229
229
  ensure_equals(parser.feed("6:hello\0,", 9), (size_t) 9);
230
230
  ensure_equals("Parser is in the error state.",
231
231
  parser.getState(), ScgiRequestParser::ERROR);
232
232
  }
233
-
233
+
234
234
  TEST_METHOD(22) {
235
235
  // A header name with its value not having a null terminator.
236
236
  ensure_equals(parser.feed("7:foo\0bar,", 10), (size_t) 10);
237
237
  ensure_equals("Parser is in the error state.",
238
238
  parser.getState(), ScgiRequestParser::ERROR);
239
239
  }
240
-
240
+
241
241
  TEST_METHOD(23) {
242
242
  // A header name without corresponding value.
243
243
  ensure_equals(parser.feed("10:foo\0bar\0a\0,", 14), (size_t) 14);
244
244
  ensure_equals("Parser is in the error state.",
245
245
  parser.getState(), ScgiRequestParser::ERROR);
246
246
  }
247
-
247
+
248
248
  TEST_METHOD(24) {
249
249
  // Length string is too large.
250
250
  static const char data[] = "999999999999999999999";
@@ -252,88 +252,102 @@ namespace tut {
252
252
  ensure_equals("Parser is in the error state.",
253
253
  parser.getState(), ScgiRequestParser::ERROR);
254
254
  }
255
-
255
+
256
256
  TEST_METHOD(25) {
257
257
  // An empty header name.
258
258
  ensure_equals(parser.feed("5:\0bar\0,", 8), (size_t) 8);
259
259
  ensure_equals("Parser is in the error state.",
260
260
  parser.getState(), ScgiRequestParser::ERROR);
261
261
  }
262
-
262
+
263
263
  TEST_METHOD(26) {
264
264
  // An empty header.
265
265
  ensure_equals(parser.feed("0:,", 3), (size_t) 2);
266
266
  ensure_equals("Parser is in the error state.",
267
267
  parser.getState(), ScgiRequestParser::ERROR);
268
268
  }
269
-
270
- /***** Test parsing invalid SCGI requests in multiple passes. *****/
271
-
269
+
272
270
  TEST_METHOD(27) {
271
+ // An empty length string.
272
+ ensure_equals(parser.feed(":", 1), (size_t) 0);
273
+ ensure_equals("Parser is in the error state.",
274
+ parser.getState(), ScgiRequestParser::ERROR);
275
+ }
276
+
277
+ TEST_METHOD(28) {
278
+ // Empty header names.
279
+ ensure_equals(parser.feed("2:\0\0,", 5), (size_t) 5);
280
+ ensure_equals("Parser is in the error state.",
281
+ parser.getState(), ScgiRequestParser::ERROR);
282
+ }
283
+
284
+ /***** Test parsing invalid SCGI requests in multiple passes. *****/
285
+
286
+ TEST_METHOD(30) {
273
287
  // Once the parser has entered the error state, it stays there.
274
288
  ensure_equals(parser.feed("hello world!", 12), 0u);
275
289
  ensure_equals(parser.feed("1", 1), 0u);
276
290
  ensure_equals("Parser is in the error state.",
277
291
  parser.getState(), ScgiRequestParser::ERROR);
278
292
  }
279
-
280
- TEST_METHOD(28) {
293
+
294
+ TEST_METHOD(31) {
281
295
  // Invalid character inside length string.
282
296
  ensure_equals(parser.feed("12", 2), 2u);
283
297
  ensure_equals(parser.feed("x:", 2), 0u);
284
298
  ensure_equals("Parser is in the error state.",
285
299
  parser.getState(), ScgiRequestParser::ERROR);
286
300
  }
287
-
288
- TEST_METHOD(29) {
301
+
302
+ TEST_METHOD(32) {
289
303
  // Invalid character in place of colon.
290
304
  ensure_equals(parser.feed("12", 2), 2u);
291
305
  ensure_equals(parser.feed("#", 1), 0u);
292
306
  ensure_equals("Parser is in the error state.",
293
307
  parser.getState(), ScgiRequestParser::ERROR);
294
308
  }
295
-
296
- TEST_METHOD(30) {
309
+
310
+ TEST_METHOD(33) {
297
311
  // Invalid character in place of comma.
298
312
  ensure_equals(parser.feed("12:hello\0world\0", 15), 15u);
299
313
  ensure_equals(parser.feed("!", 1), 0u);
300
314
  ensure_equals("Parser is in the error state.",
301
315
  parser.getState(), ScgiRequestParser::ERROR);
302
316
  }
303
-
304
- TEST_METHOD(31) {
317
+
318
+ TEST_METHOD(34) {
305
319
  // Only a header name, without even a null terminator.
306
320
  ensure_equals(parser.feed("5:hell", 6), (size_t) 6);
307
321
  ensure_equals(parser.feed("o,", 2), (size_t) 2);
308
322
  ensure_equals("Parser is in the error state.",
309
323
  parser.getState(), ScgiRequestParser::ERROR);
310
324
  }
311
-
312
- TEST_METHOD(32) {
325
+
326
+ TEST_METHOD(35) {
313
327
  // Only a header name, with a null terminator.
314
328
  ensure_equals(parser.feed("6:hello", 7), (size_t) 7);
315
329
  ensure_equals(parser.feed("\0,", 2), (size_t) 2);
316
330
  ensure_equals("Parser is in the error state.",
317
331
  parser.getState(), ScgiRequestParser::ERROR);
318
332
  }
319
-
320
- TEST_METHOD(33) {
333
+
334
+ TEST_METHOD(36) {
321
335
  // A header name with its value not having a null terminator.
322
336
  ensure_equals(parser.feed("7:foo\0ba", 8), (size_t) 8);
323
337
  ensure_equals(parser.feed("r,", 2), (size_t) 2);
324
338
  ensure_equals("Parser is in the error state.",
325
339
  parser.getState(), ScgiRequestParser::ERROR);
326
340
  }
327
-
328
- TEST_METHOD(34) {
341
+
342
+ TEST_METHOD(37) {
329
343
  // A header name without corresponding value.
330
344
  ensure_equals(parser.feed("10:foo\0bar\0a", 12), (size_t) 12);
331
345
  ensure_equals(parser.feed("\0,", 2), (size_t) 2);
332
346
  ensure_equals("Parser is in the error state.",
333
347
  parser.getState(), ScgiRequestParser::ERROR);
334
348
  }
335
-
336
- TEST_METHOD(35) {
349
+
350
+ TEST_METHOD(38) {
337
351
  // Length string is too large.
338
352
  static const char data[] = "999999999999999999999";
339
353
  ensure_equals(parser.feed("99", 2), 2u);
@@ -341,8 +355,8 @@ namespace tut {
341
355
  ensure_equals("Parser is in the error state.",
342
356
  parser.getState(), ScgiRequestParser::ERROR);
343
357
  }
344
-
345
- TEST_METHOD(36) {
358
+
359
+ TEST_METHOD(39) {
346
360
  // Parsing a request that's larger than the limit.
347
361
  parser = ScgiRequestParser(9);
348
362
  parser.feed("1", 1);
@@ -353,54 +367,54 @@ namespace tut {
353
367
  ensure_equals(parser.getErrorReason(),
354
368
  ScgiRequestParser::LIMIT_REACHED);
355
369
  }
356
-
357
- TEST_METHOD(37) {
370
+
371
+ TEST_METHOD(40) {
358
372
  // An empty header name.
359
373
  ensure_equals(parser.feed("5:\0", 3), (size_t) 3);
360
374
  ensure_equals(parser.feed("bar\0,", 5), (size_t) 5);
361
375
  ensure_equals("Parser is in the error state.",
362
376
  parser.getState(), ScgiRequestParser::ERROR);
363
377
  }
364
-
378
+
365
379
  /***** Test parsing incomplete SCGI requests. *****/
366
-
367
- TEST_METHOD(40) {
380
+
381
+ TEST_METHOD(45) {
368
382
  // Incomplete length string.
369
383
  ensure_equals(parser.feed("2", 1), 1u);
370
384
  ensure_equals("Parser is still waiting for length string input.",
371
385
  parser.getState(), ScgiRequestParser::READING_LENGTH_STRING);
372
386
  }
373
-
374
- TEST_METHOD(41) {
387
+
388
+ TEST_METHOD(46) {
375
389
  // Incomplete header.
376
390
  ensure_equals(parser.feed("21:", 3), 3u);
377
391
  ensure_equals("Parser is waiting for header data input.",
378
392
  parser.getState(), ScgiRequestParser::READING_HEADER_DATA);
379
393
  }
380
-
381
- TEST_METHOD(42) {
394
+
395
+ TEST_METHOD(47) {
382
396
  // Incomplete header.
383
397
  ensure_equals(parser.feed("20:hel", 6), 6u);
384
398
  ensure_equals("Parser is waiting for header data input.",
385
399
  parser.getState(), ScgiRequestParser::READING_HEADER_DATA);
386
400
  }
387
-
388
- TEST_METHOD(43) {
401
+
402
+ TEST_METHOD(48) {
389
403
  // Complete header but no comma.
390
404
  ensure_equals(parser.feed("8:foo\0bar\0", 10), 10u);
391
405
  ensure_equals("Parser is waiting for comma.",
392
406
  parser.getState(), ScgiRequestParser::EXPECTING_COMMA);
393
407
  }
394
-
395
- TEST_METHOD(44) {
408
+
409
+ TEST_METHOD(49) {
396
410
  // Parsing a request that's smaller than the limit.
397
411
  static const char data[] = "10:";
398
-
412
+
399
413
  parser = ScgiRequestParser(11);
400
414
  parser.feed(data, sizeof(data) - 1);
401
415
  ensure_equals("It accepted the data (9)",
402
416
  parser.getState(), ScgiRequestParser::READING_HEADER_DATA);
403
-
417
+
404
418
  parser = ScgiRequestParser(10);
405
419
  parser.feed(data, sizeof(data) - 1);
406
420
  ensure_equals("It accepted the data (10)",