passenger 5.0.0.beta3 → 5.0.0.rc1

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 +11 -5
  5. data/CHANGELOG +38 -0
  6. data/CONTRIBUTING.md +1 -4
  7. data/Gemfile +0 -1
  8. data/Gemfile.lock +0 -2
  9. data/Rakefile +33 -33
  10. data/bin/passenger +1 -1
  11. data/bin/passenger-config +1 -1
  12. data/bin/passenger-install-apache2-module +800 -800
  13. data/bin/passenger-install-nginx-module +592 -592
  14. data/bin/passenger-memory-stats +127 -127
  15. data/bin/passenger-status +216 -216
  16. data/build/agents.rb +127 -127
  17. data/build/apache2.rb +87 -87
  18. data/build/basics.rb +60 -60
  19. data/build/common_library.rb +165 -165
  20. data/build/cplusplus_support.rb +51 -51
  21. data/build/cxx_tests.rb +268 -268
  22. data/build/debian.rb +143 -143
  23. data/build/documentation.rb +58 -58
  24. data/build/integration_tests.rb +81 -81
  25. data/build/misc.rb +132 -132
  26. data/build/nginx.rb +20 -20
  27. data/build/node_tests.rb +7 -7
  28. data/build/oxt_tests.rb +14 -14
  29. data/build/packaging.rb +570 -570
  30. data/build/preprocessor.rb +260 -260
  31. data/build/rake_extensions.rb +71 -71
  32. data/build/ruby_extension.rb +29 -29
  33. data/build/ruby_tests.rb +6 -6
  34. data/build/test_basics.rb +37 -37
  35. data/debian.template/control.template +3 -5
  36. data/dev/copy_boost_headers +134 -134
  37. data/dev/install_scripts_bootstrap_code.rb +25 -25
  38. data/dev/list_tests +20 -20
  39. data/dev/ruby_server.rb +223 -223
  40. data/dev/runner +18 -18
  41. data/doc/ServerOptimizationGuide.txt.md +55 -2
  42. data/doc/Users guide Nginx.txt +0 -26
  43. data/doc/Users guide Standalone.txt +5 -1
  44. data/doc/users_guide_snippets/tips.txt +9 -0
  45. data/ext/common/ApplicationPool2/Group.h +23 -11
  46. data/ext/common/ApplicationPool2/Implementation.cpp +32 -7
  47. data/ext/common/ApplicationPool2/Pool.h +22 -17
  48. data/ext/common/ApplicationPool2/SmartSpawner.h +4 -1
  49. data/ext/common/ApplicationPool2/Spawner.h +1 -1
  50. data/ext/common/Constants.h +1 -1
  51. data/ext/common/agents/Base.cpp +35 -20
  52. data/ext/common/agents/HelperAgent/Main.cpp +8 -1
  53. data/ext/common/agents/HelperAgent/OptionParser.h +18 -4
  54. data/ext/common/agents/HelperAgent/RequestHandler.h +2 -83
  55. data/ext/common/agents/HelperAgent/RequestHandler/ForwardResponse.cpp +54 -1
  56. data/ext/common/agents/HelperAgent/RequestHandler/InitRequest.cpp +7 -4
  57. data/ext/common/agents/Main.cpp +1 -1
  58. data/ext/common/agents/Watchdog/Main.cpp +54 -19
  59. data/ext/nginx/Configuration.c +7 -0
  60. data/ext/nginx/ContentHandler.c +9 -1
  61. data/helper-scripts/backtrace-sanitizer.rb +106 -87
  62. data/helper-scripts/crash-watch.rb +32 -0
  63. data/helper-scripts/download_binaries/extconf.rb +38 -38
  64. data/helper-scripts/meteor-loader.rb +107 -107
  65. data/helper-scripts/prespawn +101 -101
  66. data/helper-scripts/rack-loader.rb +96 -96
  67. data/helper-scripts/rack-preloader.rb +137 -137
  68. data/lib/phusion_passenger.rb +292 -292
  69. data/lib/phusion_passenger/abstract_installer.rb +438 -438
  70. data/lib/phusion_passenger/active_support3_extensions/init.rb +168 -170
  71. data/lib/phusion_passenger/admin_tools.rb +20 -20
  72. data/lib/phusion_passenger/admin_tools/instance.rb +178 -178
  73. data/lib/phusion_passenger/admin_tools/instance_registry.rb +61 -61
  74. data/lib/phusion_passenger/admin_tools/memory_stats.rb +267 -267
  75. data/lib/phusion_passenger/apache2/config_options.rb +182 -182
  76. data/lib/phusion_passenger/common_library.rb +479 -485
  77. data/lib/phusion_passenger/config/about_command.rb +161 -161
  78. data/lib/phusion_passenger/config/admin_command_command.rb +129 -129
  79. data/lib/phusion_passenger/config/agent_compiler.rb +121 -121
  80. data/lib/phusion_passenger/config/build_native_support_command.rb +43 -43
  81. data/lib/phusion_passenger/config/command.rb +25 -25
  82. data/lib/phusion_passenger/config/compile_agent_command.rb +62 -62
  83. data/lib/phusion_passenger/config/compile_nginx_engine_command.rb +88 -73
  84. data/lib/phusion_passenger/config/detach_process_command.rb +72 -72
  85. data/lib/phusion_passenger/config/download_agent_command.rb +246 -227
  86. data/lib/phusion_passenger/config/download_nginx_engine_command.rb +245 -224
  87. data/lib/phusion_passenger/config/install_agent_command.rb +144 -132
  88. data/lib/phusion_passenger/config/install_standalone_runtime_command.rb +205 -185
  89. data/lib/phusion_passenger/config/installation_utils.rb +204 -204
  90. data/lib/phusion_passenger/config/list_instances_command.rb +64 -64
  91. data/lib/phusion_passenger/config/main.rb +152 -152
  92. data/lib/phusion_passenger/config/nginx_engine_compiler.rb +319 -300
  93. data/lib/phusion_passenger/config/reopen_logs_command.rb +67 -67
  94. data/lib/phusion_passenger/config/restart_app_command.rb +155 -155
  95. data/lib/phusion_passenger/config/system_metrics_command.rb +13 -13
  96. data/lib/phusion_passenger/config/utils.rb +95 -95
  97. data/lib/phusion_passenger/config/validate_install_command.rb +198 -198
  98. data/lib/phusion_passenger/console_text_template.rb +25 -25
  99. data/lib/phusion_passenger/constants.rb +90 -90
  100. data/lib/phusion_passenger/debug_logging.rb +106 -106
  101. data/lib/phusion_passenger/loader_shared_helpers.rb +447 -432
  102. data/lib/phusion_passenger/message_channel.rb +312 -312
  103. data/lib/phusion_passenger/message_client.rb +176 -176
  104. data/lib/phusion_passenger/native_support.rb +369 -369
  105. data/lib/phusion_passenger/nginx/config_options.rb +297 -297
  106. data/lib/phusion_passenger/packaging.rb +131 -131
  107. data/lib/phusion_passenger/platform_info.rb +360 -360
  108. data/lib/phusion_passenger/platform_info/apache.rb +767 -767
  109. data/lib/phusion_passenger/platform_info/apache_detector.rb +199 -199
  110. data/lib/phusion_passenger/platform_info/binary_compatibility.rb +107 -107
  111. data/lib/phusion_passenger/platform_info/compiler.rb +570 -570
  112. data/lib/phusion_passenger/platform_info/curl.rb +32 -32
  113. data/lib/phusion_passenger/platform_info/cxx_portability.rb +188 -188
  114. data/lib/phusion_passenger/platform_info/depcheck.rb +372 -372
  115. data/lib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +109 -109
  116. data/lib/phusion_passenger/platform_info/depcheck_specs/compiler_toolchain.rb +4 -4
  117. data/lib/phusion_passenger/platform_info/depcheck_specs/gems.rb +10 -34
  118. data/lib/phusion_passenger/platform_info/depcheck_specs/libs.rb +101 -101
  119. data/lib/phusion_passenger/platform_info/depcheck_specs/ruby.rb +5 -5
  120. data/lib/phusion_passenger/platform_info/depcheck_specs/utilities.rb +13 -13
  121. data/lib/phusion_passenger/platform_info/linux.rb +55 -55
  122. data/lib/phusion_passenger/platform_info/operating_system.rb +149 -149
  123. data/lib/phusion_passenger/platform_info/ruby.rb +468 -448
  124. data/lib/phusion_passenger/platform_info/zlib.rb +9 -9
  125. data/lib/phusion_passenger/plugin.rb +66 -66
  126. data/lib/phusion_passenger/preloader_shared_helpers.rb +126 -126
  127. data/lib/phusion_passenger/public_api.rb +191 -191
  128. data/lib/phusion_passenger/rack/out_of_band_gc.rb +93 -94
  129. data/lib/phusion_passenger/rack/thread_handler_extension.rb +231 -227
  130. data/lib/phusion_passenger/request_handler.rb +567 -577
  131. data/lib/phusion_passenger/request_handler/thread_handler.rb +379 -381
  132. data/lib/phusion_passenger/ruby_core_enhancements.rb +86 -86
  133. data/lib/phusion_passenger/ruby_core_io_enhancements.rb +74 -74
  134. data/lib/phusion_passenger/simple_benchmarking.rb +25 -25
  135. data/lib/phusion_passenger/standalone/app_finder.rb +153 -150
  136. data/lib/phusion_passenger/standalone/command.rb +44 -40
  137. data/lib/phusion_passenger/standalone/config_utils.rb +53 -53
  138. data/lib/phusion_passenger/standalone/control_utils.rb +38 -59
  139. data/lib/phusion_passenger/standalone/main.rb +73 -73
  140. data/lib/phusion_passenger/standalone/start_command.rb +697 -685
  141. data/lib/phusion_passenger/standalone/start_command/builtin_engine.rb +193 -155
  142. data/lib/phusion_passenger/standalone/start_command/nginx_engine.rb +162 -133
  143. data/lib/phusion_passenger/standalone/status_command.rb +64 -64
  144. data/lib/phusion_passenger/standalone/stop_command.rb +72 -72
  145. data/lib/phusion_passenger/standalone/version_command.rb +9 -9
  146. data/lib/phusion_passenger/union_station/connection.rb +32 -32
  147. data/lib/phusion_passenger/union_station/core.rb +251 -251
  148. data/lib/phusion_passenger/union_station/transaction.rb +126 -126
  149. data/lib/phusion_passenger/utils.rb +199 -167
  150. data/lib/phusion_passenger/utils/ansi_colors.rb +128 -128
  151. data/lib/phusion_passenger/utils/download.rb +196 -196
  152. data/lib/phusion_passenger/utils/file_system_watcher.rb +158 -158
  153. data/lib/phusion_passenger/utils/hosts_file_parser.rb +101 -101
  154. data/lib/phusion_passenger/utils/lock.rb +31 -31
  155. data/lib/phusion_passenger/utils/native_support_utils.rb +31 -31
  156. data/lib/phusion_passenger/utils/progress_bar.rb +26 -26
  157. data/lib/phusion_passenger/utils/shellwords.rb +20 -20
  158. data/lib/phusion_passenger/utils/terminal_choice_menu.rb +206 -206
  159. data/lib/phusion_passenger/utils/unseekable_socket.rb +272 -272
  160. data/lib/phusion_passenger/vendor/crash_watch/app.rb +129 -0
  161. data/lib/phusion_passenger/vendor/crash_watch/gdb_controller.rb +341 -0
  162. data/lib/phusion_passenger/vendor/crash_watch/version.rb +24 -0
  163. data/lib/phusion_passenger/vendor/daemon_controller.rb +877 -0
  164. data/lib/phusion_passenger/vendor/daemon_controller/lock_file.rb +127 -0
  165. data/lib/phusion_passenger/vendor/daemon_controller/spawn.rb +26 -0
  166. data/lib/phusion_passenger/vendor/daemon_controller/version.rb +29 -0
  167. data/packaging/rpm/passenger_spec/passenger.spec.template +0 -1
  168. data/passenger.gemspec +0 -1
  169. data/resources/templates/config/nginx_engine_compiler/possible_solutions_for_download_and_extraction_problems.txt.erb +27 -0
  170. data/resources/templates/standalone/config.erb +19 -15
  171. data/test/integration_tests/apache2_tests.rb +566 -566
  172. data/test/integration_tests/downloaded_binaries_tests.rb +126 -125
  173. data/test/integration_tests/native_packaging_spec.rb +296 -296
  174. data/test/integration_tests/nginx_tests.rb +393 -393
  175. data/test/integration_tests/shared/example_webapp_tests.rb +282 -280
  176. data/test/integration_tests/source_packaging_test.rb +138 -138
  177. data/test/integration_tests/spec_helper.rb +5 -5
  178. data/test/integration_tests/standalone_tests.rb +367 -367
  179. data/test/ruby/debug_logging_spec.rb +133 -133
  180. data/test/ruby/message_channel_spec.rb +186 -186
  181. data/test/ruby/rack/loader_spec.rb +28 -28
  182. data/test/ruby/rack/preloader_spec.rb +34 -34
  183. data/test/ruby/rails3.0/loader_spec.rb +12 -12
  184. data/test/ruby/rails3.0/preloader_spec.rb +18 -18
  185. data/test/ruby/rails3.1/loader_spec.rb +12 -12
  186. data/test/ruby/rails3.1/preloader_spec.rb +18 -18
  187. data/test/ruby/rails3.2/loader_spec.rb +12 -12
  188. data/test/ruby/rails3.2/preloader_spec.rb +18 -18
  189. data/test/ruby/rails4.0/loader_spec.rb +12 -12
  190. data/test/ruby/rails4.0/preloader_spec.rb +18 -18
  191. data/test/ruby/rails4.1/loader_spec.rb +12 -12
  192. data/test/ruby/rails4.1/preloader_spec.rb +18 -18
  193. data/test/ruby/request_handler_spec.rb +730 -730
  194. data/test/ruby/shared/loader_sharedspec.rb +224 -224
  195. data/test/ruby/shared/rails/union_station_extensions_sharedspec.rb +327 -327
  196. data/test/ruby/shared/ruby_loader_sharedspec.rb +47 -47
  197. data/test/ruby/spec_helper.rb +65 -65
  198. data/test/ruby/standalone/runtime_installer_spec.rb +384 -384
  199. data/test/ruby/union_station_spec.rb +276 -276
  200. data/test/ruby/utils/file_system_watcher_spec.rb +220 -220
  201. data/test/ruby/utils/hosts_file_parser.rb +248 -248
  202. data/test/ruby/utils/tee_input_spec.rb +215 -215
  203. data/test/ruby/utils/unseekable_socket_spec.rb +57 -57
  204. data/test/ruby/utils_spec.rb +21 -21
  205. data/test/stub/rack/config.ru +87 -87
  206. data/test/stub/rack/library.rb +8 -8
  207. data/test/stub/rack/start.rb +30 -30
  208. data/test/support/apache2_controller.rb +191 -191
  209. data/test/support/nginx_controller.rb +90 -99
  210. data/test/support/placebo-preloader.rb +57 -57
  211. data/test/support/test_helper.rb +435 -435
  212. metadata +11 -21
  213. metadata.gz.asc +7 -7
  214. data/lib/phusion_passenger/standalone/command2.rb +0 -292
  215. data/lib/phusion_passenger/standalone/start2_command.rb +0 -799
  216. data/resources/templates/standalone/download_tool_missing.txt.erb +0 -18
  217. data/resources/templates/standalone/possible_solutions_for_download_and_extraction_problems.txt.erb +0 -17
  218. data/resources/templates/standalone/run_installer_as_root.txt.erb +0 -8
@@ -0,0 +1,127 @@
1
+ # daemon_controller, library for robust daemon management
2
+ # Copyright (c) 2010-2015 Phusion
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+
22
+ require 'fcntl'
23
+
24
+ module PhusionPassenger
25
+ class DaemonController
26
+ # A lock file is a synchronization mechanism, like a Mutex, but it also allows
27
+ # inter-process synchronization (as opposed to only inter-thread synchronization
28
+ # within a single process).
29
+ #
30
+ # Processes can obtain either a shared lock or an exclusive lock. It's possible
31
+ # for multiple processes to obtain a shared lock on a file as long as no
32
+ # exclusive lock has been obtained by a process. If a process has obtained an
33
+ # exclusive lock, then no other processes can lock the file, whether they're
34
+ # trying to obtain a shared lock or an exclusive lock.
35
+ #
36
+ # Note that on JRuby, LockFile can only guarantee synchronization between
37
+ # threads if the different threads use the same LockFile object. Specifying the
38
+ # same filename is not enough.
39
+ class LockFile
40
+ class AlreadyLocked < StandardError
41
+ end
42
+
43
+ # Create a LockFile object. The lock file is initially not locked.
44
+ #
45
+ # +filename+ may point to a nonexistant file. In that case, the lock
46
+ # file will not be created until one's trying to obtain a lock.
47
+ #
48
+ # Note that LockFile will use this exact filename. So if +filename+
49
+ # is a relative filename, then the actual lock file that will be used
50
+ # depends on the current working directory.
51
+ def initialize(filename)
52
+ @filename = filename
53
+ end
54
+
55
+ # Obtain an exclusive lock on the lock file, yield the given block,
56
+ # then unlock the lockfile. If the lock file was already locked (whether
57
+ # shared or exclusively) by another process/thread then this method will
58
+ # block until the lock file has been unlocked.
59
+ #
60
+ # The lock file *must* be writable, otherwise an Errno::EACCESS
61
+ # exception will be raised.
62
+ def exclusive_lock
63
+ File.open(@filename, 'w') do |f|
64
+ if Fcntl.const_defined? :F_SETFD
65
+ f.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
66
+ end
67
+ f.flock(File::LOCK_EX)
68
+ yield
69
+ end
70
+ end
71
+
72
+ # Obtain an exclusive lock on the lock file, yield the given block,
73
+ # then unlock the lockfile. If the lock file was already exclusively
74
+ # locked by another process/thread then this method will
75
+ # block until the exclusive lock has been released. This method will not
76
+ # block if only shared locks have been obtained.
77
+ #
78
+ # The lock file *must* be writable, otherwise an Errno::EACCESS
79
+ # exception will be raised.
80
+ def shared_lock
81
+ File.open(@filename, 'w+') do |f|
82
+ if Fcntl.const_defined? :F_SETFD
83
+ f.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
84
+ end
85
+ f.flock(File::LOCK_SH)
86
+ yield
87
+ end
88
+ end
89
+
90
+ # Try to obtain a shared lock on the lock file, similar to #shared_lock.
91
+ # But unlike #shared_lock, this method will raise AlreadyLocked if
92
+ # no lock can be obtained, instead of blocking.
93
+ #
94
+ # If a lock can be obtained, then the given block will be yielded.
95
+ def try_shared_lock
96
+ File.open(@filename, 'w+') do |f|
97
+ if Fcntl.const_defined? :F_SETFD
98
+ f.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
99
+ end
100
+ if f.flock(File::LOCK_SH | File::LOCK_NB)
101
+ yield
102
+ else
103
+ raise AlreadyLocked
104
+ end
105
+ end
106
+ end
107
+
108
+ # Try to obtain an exclusive lock on the lock file, similar to #exclusive_lock.
109
+ # But unlike #exclusive_lock, this method will raise AlreadyLocked if
110
+ # no lock can be obtained, instead of blocking.
111
+ #
112
+ # If a lock can be obtained, then the given block will be yielded.
113
+ def try_exclusive_lock
114
+ File.open(@filename, 'w') do |f|
115
+ if Fcntl.const_defined? :F_SETFD
116
+ f.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
117
+ end
118
+ if f.flock(File::LOCK_EX | File::LOCK_NB)
119
+ yield
120
+ else
121
+ raise AlreadyLocked
122
+ end
123
+ end
124
+ end
125
+ end # class LockFile
126
+ end # class DaemonController
127
+ end # module PhusionPassenger
@@ -0,0 +1,26 @@
1
+ # daemon_controller, library for robust daemon management
2
+ # Copyright (c) 2010 Phusion
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+
22
+ # This helper script is used for daemonizing a command by executing it and
23
+ # then exiting ourselves. Used on Ruby 1.9 and JRuby because forking may not
24
+ # be safe/supported on all platforms.
25
+ Process.setsid
26
+ Process.spawn(ARGV[0])
@@ -0,0 +1,29 @@
1
+ # daemon_controller, library for robust daemon management
2
+ # Copyright (c) 2010-2015 Phusion
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+
22
+ module PhusionPassenger
23
+ class DaemonController
24
+ MAJOR = 1
25
+ MINOR = 2
26
+ TINY = 1
27
+ VERSION_STRING = "#{MAJOR}.#{MINOR}.#{TINY}"
28
+ end # class DaemonController
29
+ end # module PhusionPassenger
@@ -74,7 +74,6 @@ Patch107: rubygem-passenger-4.0.18-GLIBC_HAVE_LONG_LONG.patch
74
74
 
75
75
  Requires: rubygems
76
76
  # XXX: Needed to run passenger standalone
77
- Requires: rubygem(daemon_controller) >= 1.1.0
78
77
  Requires: rubygem(rack)
79
78
  Requires: rubygem(rake)
80
79
  %if 0%{?uses_rubyabi}
data/passenger.gemspec CHANGED
@@ -15,7 +15,6 @@ Gem::Specification.new do |s|
15
15
  s.email = "software-signing@phusion.nl"
16
16
  s.require_paths = ["lib"]
17
17
  s.add_dependency 'rake', '>= 0.8.1'
18
- s.add_dependency 'daemon_controller', '>= 1.2.0'
19
18
  s.add_dependency 'rack'
20
19
  s.files = Dir[*PhusionPassenger::Packaging::GLOB] -
21
20
  Dir[*PhusionPassenger::Packaging::EXCLUDE_GLOB]
@@ -0,0 +1,27 @@
1
+ <red><b>Unable to download or extract Nginx source tarball</b></red>
2
+
3
+ Possible reasons:
4
+
5
+ <b>* Your Internet connection is unstable.</b>
6
+ If this is the case, try re-running this installer with higher connection
7
+ timeouts:
8
+
9
+ passenger-config compile-nginx-engine --connect-timeout 60 --idle-timeout 60
10
+
11
+ <b>* You are not connected to the Internet.</b>
12
+ If this is the case, then please connect to the Internet and try again.
13
+
14
+ <b>* The URL that this installer tried to download from no longer exists.</b>
15
+ Please file a bug report if this is the case:
16
+ https://github.com/phusion/passenger/issues
17
+
18
+ <b>* The download was corrupted.</b>
19
+ Please try to re-run this installer:
20
+
21
+ passenger-config compile-nginx-engine
22
+
23
+ <b>* Phusion Passenger Standalone is not able to write to /tmp.</b>
24
+ Please fix the permissions for this directory, or run this installer with
25
+ root privileges:
26
+
27
+ <%= PlatformInfo.ruby_sudo_command %> passenger-config compile-nginx-engine
@@ -73,7 +73,7 @@ http {
73
73
  union_station_gateway_port <%= @options[:union_station_gateway_port] %>;
74
74
  union_station_gateway_cert -;
75
75
  <% end %>
76
-
76
+
77
77
  <% @options[:ctls].each do |ctl| %>
78
78
  passenger_ctl '<%= ctl.split("=", 2)[0] %>' '<%= ctl.split("=", 2)[1] %>';
79
79
  <% end %>
@@ -93,22 +93,22 @@ http {
93
93
  application/javascript application/x-javascript application/json \
94
94
  application/rss+xml application/vnd.ms-fontobject application/x-font-ttf \
95
95
  application/xml font/opentype image/svg+xml text/xml;
96
-
97
- <% if @apps.size > 1 %>
98
- # Default server entry.
99
- server {
100
- <% if @options[:ssl] %>
101
- <% if @options[:ssl_port] %>
102
- listen <%= nginx_listen_address %>;
103
- listen <%= nginx_listen_address_with_ssl_port %> ssl;
96
+
97
+ <% if @app_finder.multi_mode? %>
98
+ # Default server entry for mass deployment mode.
99
+ server {
100
+ <% if @options[:ssl] %>
101
+ <% if @options[:ssl_port] %>
102
+ listen <%= nginx_listen_address %>;
103
+ listen <%= nginx_listen_address_with_ssl_port %> ssl;
104
+ <% else %>
105
+ listen <%= nginx_listen_address %> ssl;
106
+ <% end %>
104
107
  <% else %>
105
- listen <%= nginx_listen_address %> ssl;
108
+ listen <%= nginx_listen_address %>;
106
109
  <% end %>
107
- <% else %>
108
- listen <%= nginx_listen_address %>;
109
- <% end %>
110
- root '<%= PhusionPassenger.resources_dir %>/standalone_default_root';
111
- }
110
+ root '<%= PhusionPassenger.resources_dir %>/standalone_default_root';
111
+ }
112
112
  <% end %>
113
113
 
114
114
  <% for app in @apps %>
@@ -151,6 +151,10 @@ http {
151
151
  ssl_certificate_key <%= app[:ssl_certificate_key] %>;
152
152
  <% end %>
153
153
 
154
+ <% @options[:envvars].each_pair do |name, value| %>
155
+ passenger_env_var '<%= name %>' '<%= value %>';
156
+ <% end %>
157
+
154
158
  # Rails asset pipeline support.
155
159
  location ~ "^/assets/.+-[0-9a-f]{32}\..+" {
156
160
  error_page 490 = @static_asset;
@@ -16,570 +16,570 @@ require 'integration_tests/shared/example_webapp_tests'
16
16
  # TODO: test custom page caching directory
17
17
 
18
18
  describe "Apache 2 module" do
19
- before :all do
20
- check_hosts_configuration
21
- @passenger_temp_dir = "/tmp/passenger-test.#{$$}"
22
- Dir.mkdir(@passenger_temp_dir)
23
- FileUtils.chmod_R(0777, @passenger_temp_dir)
24
- ENV['TMPDIR'] = @passenger_temp_dir
25
- end
26
-
27
- after :all do
28
- @apache2.stop if @apache2
29
- FileUtils.chmod_R(0777, @passenger_temp_dir)
30
- FileUtils.rm_rf(@passenger_temp_dir)
31
- end
32
-
33
- before :each do
34
- File.open("test.log", "a") do |f|
35
- # Make sure that all Apache log output is prepended by the test description
36
- # so that we know which messages are associated with which tests.
37
- f.puts "\n#### #{Time.now}: #{example.full_description}"
38
- @test_log_pos = f.pos
39
- end
40
- end
41
-
42
- after :each do
43
- log "End of test"
44
- if example.exception
45
- puts "\t---------------- Begin logs -------------------"
46
- File.open("test.log", "r") do |f|
47
- f.seek(@test_log_pos)
48
- puts f.read.split("\n").map{ |line| "\t#{line}" }.join("\n")
49
- end
50
- puts "\t---------------- End logs -------------------"
51
- puts "\tThe following test failed. The web server logs are printed above."
52
- end
53
- end
54
-
55
- def create_apache2_controller
56
- @apache2 = Apache2Controller.new
57
- @apache2.set(:passenger_temp_dir => @passenger_temp_dir)
58
- if Process.uid == 0
59
- @apache2.set(
60
- :www_user => CONFIG['normal_user_1'],
61
- :www_group => Etc.getgrgid(Etc.getpwnam(CONFIG['normal_user_1']).gid).name
62
- )
63
- end
64
- end
65
-
66
- def log(message)
67
- File.open("test.log", "a") do |f|
68
- f.puts "[#{Time.now}] Spec: #{message}"
69
- end
70
- end
71
-
72
- describe "a Ruby app running on the root URI" do
73
- before :all do
74
- create_apache2_controller
75
- @server = "http://1.passenger.test:#{@apache2.port}"
76
- @stub = RackStub.new('rack')
77
- @apache2 << "PassengerMaxPoolSize 1"
78
- @apache2.set_vhost("1.passenger.test", "#{@stub.full_app_root}/public")
79
- @apache2.start
80
- end
81
-
82
- after :all do
83
- @stub.destroy
84
- @apache2.stop if @apache2
85
- end
86
-
87
- before :each do
88
- @stub.reset
89
- end
90
-
91
- it_should_behave_like "an example web app"
92
- end
93
-
94
- describe "a Ruby app running in a sub-URI" do
95
- before :all do
96
- create_apache2_controller
97
- @server = "http://1.passenger.test:#{@apache2.port}/subapp"
98
- @stub = RackStub.new('rack')
99
- @apache2 << "PassengerMaxPoolSize 1"
100
- @apache2.set_vhost("1.passenger.test", File.expand_path("stub")) do |vhost|
101
- vhost << %Q{
102
- Alias /subapp #{@stub.full_app_root}/public
103
- <Location /subapp>
104
- PassengerBaseURI /subapp
105
- PassengerAppRoot #{@stub.full_app_root}
106
- </Location>
107
- }
108
- end
109
- @apache2.start
110
- end
111
-
112
- after :all do
113
- @stub.destroy
114
- @apache2.stop if @apache2
115
- end
116
-
117
- before :each do
118
- @stub.reset
119
- end
120
-
121
- it_should_behave_like "an example web app"
122
-
123
- it "does not interfere with the root website" do
124
- @server = "http://1.passenger.test:#{@apache2.port}"
125
- get('/').should == "This is the stub directory."
126
- end
127
- end
128
-
129
- describe "a Python app running on the root URI" do
130
- before :all do
131
- create_apache2_controller
132
- @server = "http://1.passenger.test:#{@apache2.port}"
133
- @stub = PythonStub.new('wsgi')
134
- @apache2 << "PassengerMaxPoolSize 1"
135
- @apache2.set_vhost("1.passenger.test", "#{@stub.full_app_root}/public")
136
- @apache2.start
137
- end
138
-
139
- after :all do
140
- @stub.destroy
141
- @apache2.stop if @apache2
142
- end
143
-
144
- before :each do
145
- @stub.reset
146
- end
147
-
148
- it_should_behave_like "an example web app"
149
- end
150
-
151
- describe "a Python app running in a sub-URI" do
152
- before :all do
153
- create_apache2_controller
154
- @server = "http://1.passenger.test:#{@apache2.port}/subapp"
155
- @stub = PythonStub.new('wsgi')
156
- @apache2 << "PassengerMaxPoolSize 1"
157
- @apache2.set_vhost("1.passenger.test", File.expand_path("stub")) do |vhost|
158
- vhost << %Q{
159
- Alias /subapp #{@stub.full_app_root}/public
160
- <Location /subapp>
161
- PassengerBaseURI /subapp
162
- PassengerAppRoot #{@stub.full_app_root}
163
- </Location>
164
- }
165
- end
166
- @apache2.start
167
- end
168
-
169
- after :all do
170
- @stub.destroy
171
- @apache2.stop if @apache2
172
- end
173
-
174
- before :each do
175
- @stub.reset
176
- end
177
-
178
- it_should_behave_like "an example web app"
179
-
180
- it "does not interfere with the root website" do
181
- @server = "http://1.passenger.test:#{@apache2.port}"
182
- get('/').should == "This is the stub directory."
183
- end
184
- end
185
-
186
- describe "a Node.js app running on the root URI" do
187
- before :all do
188
- create_apache2_controller
189
- @server = "http://1.passenger.test:#{@apache2.port}"
190
- @stub = NodejsStub.new('node')
191
- @apache2 << "PassengerMaxPoolSize 1"
192
- @apache2.set_vhost("1.passenger.test", "#{@stub.full_app_root}/public")
193
- @apache2.start
194
- end
195
-
196
- after :all do
197
- @stub.destroy
198
- @apache2.stop if @apache2
199
- end
200
-
201
- before :each do
202
- @stub.reset
203
- end
204
-
205
- it_should_behave_like "an example web app"
206
- end
207
-
208
- describe "a Node.js app running in a sub-URI" do
209
- before :all do
210
- create_apache2_controller
211
- @server = "http://1.passenger.test:#{@apache2.port}/subapp"
212
- @stub = NodejsStub.new('node')
213
- @apache2 << "PassengerMaxPoolSize 1"
214
- @apache2.set_vhost("1.passenger.test", File.expand_path("stub")) do |vhost|
215
- vhost << %Q{
216
- Alias /subapp #{@stub.full_app_root}/public
217
- <Location /subapp>
218
- PassengerBaseURI /subapp
219
- PassengerAppRoot #{@stub.full_app_root}
220
- </Location>
221
- }
222
- end
223
- @apache2.start
224
- end
225
-
226
- after :all do
227
- @stub.destroy
228
- @apache2.stop if @apache2
229
- end
230
-
231
- before :each do
232
- @stub.reset
233
- end
234
-
235
- it_should_behave_like "an example web app"
236
-
237
- it "does not interfere with the root website" do
238
- @server = "http://1.passenger.test:#{@apache2.port}"
239
- get('/').should == "This is the stub directory."
240
- end
241
- end
242
-
243
- describe "compatibility with other modules" do
244
- before :all do
245
- create_apache2_controller
246
- @apache2 << "PassengerMaxPoolSize 1"
247
- @apache2 << "PassengerStatThrottleRate 0"
248
-
249
- @stub = RackStub.new('rack')
250
- @server = "http://1.passenger.test:#{@apache2.port}"
251
- @apache2.set_vhost("1.passenger.test", "#{@stub.full_app_root}/public") do |vhost|
252
- vhost << "RewriteEngine on"
253
- vhost << "RewriteRule ^/rewritten_frontpage$ / [PT,QSA,L]"
254
- vhost << "RewriteRule ^/rewritten_env$ /env [PT,QSA,L]"
255
- end
256
- @apache2.start
257
- end
258
-
259
- after :all do
260
- @stub.destroy
261
- @apache2.stop if @apache2
262
- end
263
-
264
- before :each do
265
- @stub.reset
266
- end
267
-
268
- it "supports environment variable passing through mod_env" do
269
- File.write("#{@stub.app_root}/public/.htaccess", 'SetEnv FOO "Foo Bar!"')
270
- File.touch("#{@stub.app_root}/tmp/restart.txt", 2) # Activate ENV changes.
271
- get('/system_env').should =~ /^FOO = Foo Bar\!$/
272
- end
273
-
274
- it "supports mod_rewrite in the virtual host block" do
275
- get('/rewritten_frontpage').should == "front page"
276
- cgi_envs = get('/rewritten_env?foo=bar+baz')
277
- cgi_envs.should include("REQUEST_URI = /env?foo=bar+baz\n")
278
- cgi_envs.should include("PATH_INFO = /env\n")
279
- end
280
-
281
- it "supports mod_rewrite in .htaccess" do
282
- File.write("#{@stub.app_root}/public/.htaccess", %Q{
283
- RewriteEngine on
284
- RewriteRule ^htaccess_frontpage$ / [PT,QSA,L]
285
- RewriteRule ^htaccess_env$ env [PT,QSA,L]
286
- })
287
- get('/htaccess_frontpage').should == "front page"
288
- cgi_envs = get('/htaccess_env?foo=bar+baz')
289
- cgi_envs.should include("REQUEST_URI = /env?foo=bar+baz\n")
290
- cgi_envs.should include("PATH_INFO = /env\n")
291
- end
292
- end
293
-
294
- describe "configuration options" do
295
- before :all do
296
- create_apache2_controller
297
- @apache2 << "PassengerMaxPoolSize 3"
298
- @apache2 << "PassengerStatThrottleRate 0"
299
-
300
- @stub = RackStub.new('rack')
301
- @stub_url_root = "http://5.passenger.test:#{@apache2.port}"
302
- @apache2.set_vhost('5.passenger.test', "#{@stub.full_app_root}/public") do |vhost|
303
- vhost << "PassengerBufferUpload off"
304
- vhost << "PassengerFriendlyErrorPages on"
305
- vhost << "AllowEncodedSlashes on"
306
- end
307
-
308
- @stub2 = RackStub.new('rack')
309
- @stub2_url_root = "http://6.passenger.test:#{@apache2.port}"
310
- @apache2.set_vhost('6.passenger.test', "#{@stub2.full_app_root}/public") do |vhost|
311
- vhost << "PassengerAppEnv development"
312
- vhost << "PassengerSpawnMethod conservative"
313
- vhost << "PassengerRestartDir #{@stub2.full_app_root}/public"
314
- vhost << "AllowEncodedSlashes off"
315
- end
316
-
317
- @apache2.start
318
- end
319
-
320
- after :all do
321
- @stub.destroy
322
- @stub2.destroy
323
- @apache2.stop if @apache2
324
- end
325
-
326
- before :each do
327
- @stub.reset
328
- @stub2.reset
329
- end
330
-
331
- specify "PassengerAppEnv is per-virtual host" do
332
- @server = @stub_url_root
333
- get('/system_env').should =~ /PASSENGER_APP_ENV = production/
334
-
335
- @server = @stub2_url_root
336
- get('/system_env').should =~ /PASSENGER_APP_ENV = development/
337
- end
338
-
339
- it "looks for restart.txt in the directory specified by PassengerRestartDir" do
340
- @server = @stub2_url_root
341
- startup_file = "#{@stub2.app_root}/config.ru"
342
- restart_file = "#{@stub2.app_root}/public/restart.txt"
343
-
344
- File.write(startup_file, %Q{
345
- require File.expand_path(File.dirname(__FILE__) + "/library")
346
-
347
- app = lambda do |env|
348
- case env['PATH_INFO']
349
- when '/'
350
- text_response("hello world")
351
- else
352
- [404, { "Content-Type" => "text/plain" }, ["Unknown URI"]]
353
- end
354
- end
355
-
356
- run app
357
- })
358
-
359
- now = Time.now
360
- File.touch(restart_file, now - 5)
361
- get('/').should == "hello world"
362
-
363
- File.write(startup_file, %Q{
364
- require File.expand_path(File.dirname(__FILE__) + "/library")
365
-
366
- app = lambda do |env|
367
- case env['PATH_INFO']
368
- when '/'
369
- text_response("oh hai")
370
- else
371
- [404, { "Content-Type" => "text/plain" }, ["Unknown URI"]]
372
- end
373
- end
374
-
375
- run app
376
- })
377
-
378
- File.touch(restart_file, now - 10)
379
- get('/').should == "oh hai"
380
- end
381
-
382
- describe "PassengerAppRoot" do
383
- before :each do
384
- @server = @stub_url_root
385
- File.write("#{@stub.full_app_root}/public/cached.html", "Static cached.html")
386
- File.write("#{@stub.full_app_root}/public/dir.html", "Static dir.html")
387
- Dir.mkdir("#{@stub.full_app_root}/public/dir")
388
- end
389
-
390
- it "supports page caching on non-index URIs" do
391
- get('/cached').should == "Static cached.html"
392
- end
393
-
394
- it "supports page caching on directory index URIs" do
395
- get('/dir').should == "Static dir.html"
396
- end
397
-
398
- it "works" do
399
- result = get('/parameters?first=one&second=Green+Bananas')
400
- result.should =~ %r{First: one\n}
401
- result.should =~ %r{Second: Green Bananas\n}
402
- end
403
- end
404
-
405
- it "resolves symlinks in the document root if PassengerResolveSymlinksInDocumentRoot is set" do
406
- orig_app_root = @stub.app_root
407
- @stub.move(File.expand_path('tmp.mycook.symlinktest'))
408
- FileUtils.mkdir_p(orig_app_root)
409
- File.symlink("#{@stub.app_root}/public", "#{orig_app_root}/public")
410
- begin
411
- File.write("#{@stub.app_root}/public/.htaccess", "PassengerResolveSymlinksInDocumentRoot on")
412
- @server = @stub_url_root
413
- get('/').should == "front page"
414
- ensure
415
- FileUtils.rm_rf(orig_app_root)
416
- @stub.move(orig_app_root)
417
- end
418
- end
419
-
420
- it "supports encoded slashes in the URL if AllowEncodedSlashes is turned on" do
421
- @server = @stub_url_root
422
- get('/env/foo%2fbar').should =~ %r{PATH_INFO = /env/foo/bar\n}
423
-
424
- @server = @stub2_url_root
425
- get('/env/foo%2fbar').should =~ %r{404 Not Found}
426
- end
427
-
428
- describe "when handling POST requests with 'chunked' transfer encoding, if PassengerBufferUpload is off" do
429
- it "sets Transfer-Encoding to 'chunked' and removes Content-Length" do
430
- @uri = URI.parse(@stub_url_root)
431
- socket = TCPSocket.new(@uri.host, @uri.port)
432
- begin
433
- socket.write("POST #{@stub_url_root}/env HTTP/1.1\r\n")
434
- socket.write("Host: #{@uri.host}:#{@uri.port}\r\n")
435
- socket.write("Transfer-Encoding: chunked\r\n")
436
- socket.write("Content-Type: text/plain\r\n")
437
- socket.write("Connection: close\r\n")
438
- socket.write("\r\n")
439
-
440
- chunk = "foo=bar!"
441
- socket.write("%X\r\n%s\r\n" % [chunk.size, chunk])
442
- socket.write("0\r\n\r\n")
443
- socket.flush
444
-
445
- response = socket.read
446
- response.should_not include("CONTENT_LENGTH = ")
447
- response.should include("HTTP_TRANSFER_ENCODING = chunked\n")
448
- ensure
449
- socket.close
450
- end
451
- end
452
- end
453
-
454
- ####################################
455
- end
456
-
457
- describe "error handling" do
458
- before :all do
459
- create_apache2_controller
460
- FileUtils.rm_rf('tmp.webdir')
461
- FileUtils.mkdir_p('tmp.webdir')
462
- @webdir = File.expand_path('tmp.webdir')
463
- @apache2.set_vhost('1.passenger.test', @webdir) do |vhost|
464
- vhost << "PassengerBaseURI /app-that-crashes-during-startup/public"
465
- end
466
-
467
- @stub = RackStub.new('rack')
468
- @stub_url_root = "http://2.passenger.test:#{@apache2.port}"
469
- @apache2.set_vhost('2.passenger.test', "#{@stub.full_app_root}/public")
470
-
471
- @apache2 << "PassengerFriendlyErrorPages on"
472
- @apache2.start
473
- end
474
-
475
- after :all do
476
- FileUtils.rm_rf('tmp.webdir')
477
- @stub.destroy
478
- @apache2.stop if @apache2
479
- end
480
-
481
- before :each do
482
- @server = "http://1.passenger.test:#{@apache2.port}"
483
- @error_page_signature = /<meta name="generator" content="Phusion Passenger">/
484
- @stub.reset
485
- end
486
-
487
- it "displays an error page if the application crashes during startup" do
488
- RackStub.use('rack', "#{@webdir}/app-that-crashes-during-startup") do |stub|
489
- File.prepend(stub.startup_file, "raise 'app crash'")
490
- result = get("/app-that-crashes-during-startup/public")
491
- result.should =~ @error_page_signature
492
- result.should =~ /app crash/
493
- end
494
- end
495
-
496
- it "doesn't display a Ruby spawn error page if PassengerFriendlyErrorPages is off" do
497
- RackStub.use('rack', "#{@webdir}/app-that-crashes-during-startup") do |stub|
498
- File.write("#{stub.app_root}/public/.htaccess", "PassengerFriendlyErrorPages off")
499
- File.prepend(stub.startup_file, "raise 'app crash'")
500
- result = get("/app-that-crashes-during-startup/public")
501
- result.should_not =~ @error_page_signature
502
- result.should_not =~ /app crash/
503
- end
504
- end
505
- end
506
-
507
- describe "HelperAgent" do
508
- AdminTools = PhusionPassenger::AdminTools
509
-
510
- before :all do
511
- create_apache2_controller
512
- @stub = RackStub.new('rack')
513
- @stub_url_root = "http://1.passenger.test:#{@apache2.port}"
514
- @apache2 << "PassengerStatThrottleRate 0"
515
- @apache2.set_vhost('1.passenger.test', "#{@stub.full_app_root}/public")
516
- @apache2.start
517
- @server = "http://1.passenger.test:#{@apache2.port}"
518
- end
519
-
520
- after :all do
521
- @stub.destroy
522
- @apache2.stop if @apache2
523
- end
524
-
525
- before :each do
526
- @stub.reset
527
- end
528
-
529
- it "is restarted if it crashes" do
530
- # Make sure that all Apache worker processes have connected to
531
- # the helper agent.
532
- 10.times do
533
- get('/').should == "front page"
534
- sleep 0.1
535
- end
536
-
537
- # Now kill the helper agent.
538
- instance = AdminTools::InstanceRegistry.new.list.first
539
- Process.kill('SIGKILL', instance.server_pid)
540
- sleep 0.02 # Give the signal a small amount of time to take effect.
541
-
542
- # Each worker process should detect that the old
543
- # helper agent has died, and should reconnect.
544
- 10.times do
545
- get('/').should == "front page"
546
- sleep 0.1
547
- end
548
- end
549
-
550
- it "exposes the application pool for passenger-status" do
551
- File.touch("#{@stub.app_root}/tmp/restart.txt", 1) # Get rid of all previous app processes.
552
- get('/').should == "front page"
553
- instance = AdminTools::InstanceRegistry.new.list.first
554
-
555
- # Wait until the server has processed the session close event.
556
- sleep 0.1
557
-
558
- request = Net::HTTP::Get.new("/pool.xml")
559
- request.basic_auth("ro_admin", instance.read_only_admin_password)
560
- response = instance.http_request("agents.s/server_admin", request)
561
- if response.code.to_i / 100 == 2
562
- doc = REXML::Document.new(response.body)
563
- else
564
- raise response.body
565
- end
566
-
567
- groups = doc.get_elements("info/supergroups/supergroup/group")
568
- groups.should have(1).item
569
- groups.each do |group|
570
- group.elements["name"].text.should == "#{@stub.full_app_root} (production)#default"
571
- processes = group.get_elements("processes/process")
572
- processes.should have(1).item
573
- processes[0].elements["processed"].text.should == "1"
574
- end
575
- end
576
- end
577
-
578
- ##### Helper methods #####
579
-
580
- def start_web_server_if_necessary
581
- if !@apache2.running?
582
- @apache2.start
583
- end
584
- end
19
+ before :all do
20
+ check_hosts_configuration
21
+ @passenger_temp_dir = "/tmp/passenger-test.#{$$}"
22
+ Dir.mkdir(@passenger_temp_dir)
23
+ FileUtils.chmod_R(0777, @passenger_temp_dir)
24
+ ENV['TMPDIR'] = @passenger_temp_dir
25
+ end
26
+
27
+ after :all do
28
+ @apache2.stop if @apache2
29
+ FileUtils.chmod_R(0777, @passenger_temp_dir)
30
+ FileUtils.rm_rf(@passenger_temp_dir)
31
+ end
32
+
33
+ before :each do
34
+ File.open("test.log", "a") do |f|
35
+ # Make sure that all Apache log output is prepended by the test description
36
+ # so that we know which messages are associated with which tests.
37
+ f.puts "\n#### #{Time.now}: #{example.full_description}"
38
+ @test_log_pos = f.pos
39
+ end
40
+ end
41
+
42
+ after :each do
43
+ log "End of test"
44
+ if example.exception
45
+ puts "\t---------------- Begin logs -------------------"
46
+ File.open("test.log", "r") do |f|
47
+ f.seek(@test_log_pos)
48
+ puts f.read.split("\n").map{ |line| "\t#{line}" }.join("\n")
49
+ end
50
+ puts "\t---------------- End logs -------------------"
51
+ puts "\tThe following test failed. The web server logs are printed above."
52
+ end
53
+ end
54
+
55
+ def create_apache2_controller
56
+ @apache2 = Apache2Controller.new
57
+ @apache2.set(:passenger_temp_dir => @passenger_temp_dir)
58
+ if Process.uid == 0
59
+ @apache2.set(
60
+ :www_user => CONFIG['normal_user_1'],
61
+ :www_group => Etc.getgrgid(Etc.getpwnam(CONFIG['normal_user_1']).gid).name
62
+ )
63
+ end
64
+ end
65
+
66
+ def log(message)
67
+ File.open("test.log", "a") do |f|
68
+ f.puts "[#{Time.now}] Spec: #{message}"
69
+ end
70
+ end
71
+
72
+ describe "a Ruby app running on the root URI" do
73
+ before :all do
74
+ create_apache2_controller
75
+ @server = "http://1.passenger.test:#{@apache2.port}"
76
+ @stub = RackStub.new('rack')
77
+ @apache2 << "PassengerMaxPoolSize 1"
78
+ @apache2.set_vhost("1.passenger.test", "#{@stub.full_app_root}/public")
79
+ @apache2.start
80
+ end
81
+
82
+ after :all do
83
+ @stub.destroy
84
+ @apache2.stop if @apache2
85
+ end
86
+
87
+ before :each do
88
+ @stub.reset
89
+ end
90
+
91
+ it_should_behave_like "an example web app"
92
+ end
93
+
94
+ describe "a Ruby app running in a sub-URI" do
95
+ before :all do
96
+ create_apache2_controller
97
+ @server = "http://1.passenger.test:#{@apache2.port}/subapp"
98
+ @stub = RackStub.new('rack')
99
+ @apache2 << "PassengerMaxPoolSize 1"
100
+ @apache2.set_vhost("1.passenger.test", File.expand_path("stub")) do |vhost|
101
+ vhost << %Q{
102
+ Alias /subapp #{@stub.full_app_root}/public
103
+ <Location /subapp>
104
+ PassengerBaseURI /subapp
105
+ PassengerAppRoot #{@stub.full_app_root}
106
+ </Location>
107
+ }
108
+ end
109
+ @apache2.start
110
+ end
111
+
112
+ after :all do
113
+ @stub.destroy
114
+ @apache2.stop if @apache2
115
+ end
116
+
117
+ before :each do
118
+ @stub.reset
119
+ end
120
+
121
+ it_should_behave_like "an example web app"
122
+
123
+ it "does not interfere with the root website" do
124
+ @server = "http://1.passenger.test:#{@apache2.port}"
125
+ get('/').should == "This is the stub directory."
126
+ end
127
+ end
128
+
129
+ describe "a Python app running on the root URI" do
130
+ before :all do
131
+ create_apache2_controller
132
+ @server = "http://1.passenger.test:#{@apache2.port}"
133
+ @stub = PythonStub.new('wsgi')
134
+ @apache2 << "PassengerMaxPoolSize 1"
135
+ @apache2.set_vhost("1.passenger.test", "#{@stub.full_app_root}/public")
136
+ @apache2.start
137
+ end
138
+
139
+ after :all do
140
+ @stub.destroy
141
+ @apache2.stop if @apache2
142
+ end
143
+
144
+ before :each do
145
+ @stub.reset
146
+ end
147
+
148
+ it_should_behave_like "an example web app"
149
+ end
150
+
151
+ describe "a Python app running in a sub-URI" do
152
+ before :all do
153
+ create_apache2_controller
154
+ @server = "http://1.passenger.test:#{@apache2.port}/subapp"
155
+ @stub = PythonStub.new('wsgi')
156
+ @apache2 << "PassengerMaxPoolSize 1"
157
+ @apache2.set_vhost("1.passenger.test", File.expand_path("stub")) do |vhost|
158
+ vhost << %Q{
159
+ Alias /subapp #{@stub.full_app_root}/public
160
+ <Location /subapp>
161
+ PassengerBaseURI /subapp
162
+ PassengerAppRoot #{@stub.full_app_root}
163
+ </Location>
164
+ }
165
+ end
166
+ @apache2.start
167
+ end
168
+
169
+ after :all do
170
+ @stub.destroy
171
+ @apache2.stop if @apache2
172
+ end
173
+
174
+ before :each do
175
+ @stub.reset
176
+ end
177
+
178
+ it_should_behave_like "an example web app"
179
+
180
+ it "does not interfere with the root website" do
181
+ @server = "http://1.passenger.test:#{@apache2.port}"
182
+ get('/').should == "This is the stub directory."
183
+ end
184
+ end
185
+
186
+ describe "a Node.js app running on the root URI" do
187
+ before :all do
188
+ create_apache2_controller
189
+ @server = "http://1.passenger.test:#{@apache2.port}"
190
+ @stub = NodejsStub.new('node')
191
+ @apache2 << "PassengerMaxPoolSize 1"
192
+ @apache2.set_vhost("1.passenger.test", "#{@stub.full_app_root}/public")
193
+ @apache2.start
194
+ end
195
+
196
+ after :all do
197
+ @stub.destroy
198
+ @apache2.stop if @apache2
199
+ end
200
+
201
+ before :each do
202
+ @stub.reset
203
+ end
204
+
205
+ it_should_behave_like "an example web app"
206
+ end
207
+
208
+ describe "a Node.js app running in a sub-URI" do
209
+ before :all do
210
+ create_apache2_controller
211
+ @server = "http://1.passenger.test:#{@apache2.port}/subapp"
212
+ @stub = NodejsStub.new('node')
213
+ @apache2 << "PassengerMaxPoolSize 1"
214
+ @apache2.set_vhost("1.passenger.test", File.expand_path("stub")) do |vhost|
215
+ vhost << %Q{
216
+ Alias /subapp #{@stub.full_app_root}/public
217
+ <Location /subapp>
218
+ PassengerBaseURI /subapp
219
+ PassengerAppRoot #{@stub.full_app_root}
220
+ </Location>
221
+ }
222
+ end
223
+ @apache2.start
224
+ end
225
+
226
+ after :all do
227
+ @stub.destroy
228
+ @apache2.stop if @apache2
229
+ end
230
+
231
+ before :each do
232
+ @stub.reset
233
+ end
234
+
235
+ it_should_behave_like "an example web app"
236
+
237
+ it "does not interfere with the root website" do
238
+ @server = "http://1.passenger.test:#{@apache2.port}"
239
+ get('/').should == "This is the stub directory."
240
+ end
241
+ end
242
+
243
+ describe "compatibility with other modules" do
244
+ before :all do
245
+ create_apache2_controller
246
+ @apache2 << "PassengerMaxPoolSize 1"
247
+ @apache2 << "PassengerStatThrottleRate 0"
248
+
249
+ @stub = RackStub.new('rack')
250
+ @server = "http://1.passenger.test:#{@apache2.port}"
251
+ @apache2.set_vhost("1.passenger.test", "#{@stub.full_app_root}/public") do |vhost|
252
+ vhost << "RewriteEngine on"
253
+ vhost << "RewriteRule ^/rewritten_frontpage$ / [PT,QSA,L]"
254
+ vhost << "RewriteRule ^/rewritten_env$ /env [PT,QSA,L]"
255
+ end
256
+ @apache2.start
257
+ end
258
+
259
+ after :all do
260
+ @stub.destroy
261
+ @apache2.stop if @apache2
262
+ end
263
+
264
+ before :each do
265
+ @stub.reset
266
+ end
267
+
268
+ it "supports environment variable passing through mod_env" do
269
+ File.write("#{@stub.app_root}/public/.htaccess", 'SetEnv FOO "Foo Bar!"')
270
+ File.touch("#{@stub.app_root}/tmp/restart.txt", 2) # Activate ENV changes.
271
+ get('/system_env').should =~ /^FOO = Foo Bar\!$/
272
+ end
273
+
274
+ it "supports mod_rewrite in the virtual host block" do
275
+ get('/rewritten_frontpage').should == "front page"
276
+ cgi_envs = get('/rewritten_env?foo=bar+baz')
277
+ cgi_envs.should include("REQUEST_URI = /env?foo=bar+baz\n")
278
+ cgi_envs.should include("PATH_INFO = /env\n")
279
+ end
280
+
281
+ it "supports mod_rewrite in .htaccess" do
282
+ File.write("#{@stub.app_root}/public/.htaccess", %Q{
283
+ RewriteEngine on
284
+ RewriteRule ^htaccess_frontpage$ / [PT,QSA,L]
285
+ RewriteRule ^htaccess_env$ env [PT,QSA,L]
286
+ })
287
+ get('/htaccess_frontpage').should == "front page"
288
+ cgi_envs = get('/htaccess_env?foo=bar+baz')
289
+ cgi_envs.should include("REQUEST_URI = /env?foo=bar+baz\n")
290
+ cgi_envs.should include("PATH_INFO = /env\n")
291
+ end
292
+ end
293
+
294
+ describe "configuration options" do
295
+ before :all do
296
+ create_apache2_controller
297
+ @apache2 << "PassengerMaxPoolSize 3"
298
+ @apache2 << "PassengerStatThrottleRate 0"
299
+
300
+ @stub = RackStub.new('rack')
301
+ @stub_url_root = "http://5.passenger.test:#{@apache2.port}"
302
+ @apache2.set_vhost('5.passenger.test', "#{@stub.full_app_root}/public") do |vhost|
303
+ vhost << "PassengerBufferUpload off"
304
+ vhost << "PassengerFriendlyErrorPages on"
305
+ vhost << "AllowEncodedSlashes on"
306
+ end
307
+
308
+ @stub2 = RackStub.new('rack')
309
+ @stub2_url_root = "http://6.passenger.test:#{@apache2.port}"
310
+ @apache2.set_vhost('6.passenger.test', "#{@stub2.full_app_root}/public") do |vhost|
311
+ vhost << "PassengerAppEnv development"
312
+ vhost << "PassengerSpawnMethod conservative"
313
+ vhost << "PassengerRestartDir #{@stub2.full_app_root}/public"
314
+ vhost << "AllowEncodedSlashes off"
315
+ end
316
+
317
+ @apache2.start
318
+ end
319
+
320
+ after :all do
321
+ @stub.destroy
322
+ @stub2.destroy
323
+ @apache2.stop if @apache2
324
+ end
325
+
326
+ before :each do
327
+ @stub.reset
328
+ @stub2.reset
329
+ end
330
+
331
+ specify "PassengerAppEnv is per-virtual host" do
332
+ @server = @stub_url_root
333
+ get('/system_env').should =~ /PASSENGER_APP_ENV = production/
334
+
335
+ @server = @stub2_url_root
336
+ get('/system_env').should =~ /PASSENGER_APP_ENV = development/
337
+ end
338
+
339
+ it "looks for restart.txt in the directory specified by PassengerRestartDir" do
340
+ @server = @stub2_url_root
341
+ startup_file = "#{@stub2.app_root}/config.ru"
342
+ restart_file = "#{@stub2.app_root}/public/restart.txt"
343
+
344
+ File.write(startup_file, %Q{
345
+ require File.expand_path(File.dirname(__FILE__) + "/library")
346
+
347
+ app = lambda do |env|
348
+ case env['PATH_INFO']
349
+ when '/'
350
+ text_response("hello world")
351
+ else
352
+ [404, { "Content-Type" => "text/plain" }, ["Unknown URI"]]
353
+ end
354
+ end
355
+
356
+ run app
357
+ })
358
+
359
+ now = Time.now
360
+ File.touch(restart_file, now - 5)
361
+ get('/').should == "hello world"
362
+
363
+ File.write(startup_file, %Q{
364
+ require File.expand_path(File.dirname(__FILE__) + "/library")
365
+
366
+ app = lambda do |env|
367
+ case env['PATH_INFO']
368
+ when '/'
369
+ text_response("oh hai")
370
+ else
371
+ [404, { "Content-Type" => "text/plain" }, ["Unknown URI"]]
372
+ end
373
+ end
374
+
375
+ run app
376
+ })
377
+
378
+ File.touch(restart_file, now - 10)
379
+ get('/').should == "oh hai"
380
+ end
381
+
382
+ describe "PassengerAppRoot" do
383
+ before :each do
384
+ @server = @stub_url_root
385
+ File.write("#{@stub.full_app_root}/public/cached.html", "Static cached.html")
386
+ File.write("#{@stub.full_app_root}/public/dir.html", "Static dir.html")
387
+ Dir.mkdir("#{@stub.full_app_root}/public/dir")
388
+ end
389
+
390
+ it "supports page caching on non-index URIs" do
391
+ get('/cached').should == "Static cached.html"
392
+ end
393
+
394
+ it "supports page caching on directory index URIs" do
395
+ get('/dir').should == "Static dir.html"
396
+ end
397
+
398
+ it "works" do
399
+ result = get('/parameters?first=one&second=Green+Bananas')
400
+ result.should =~ %r{First: one\n}
401
+ result.should =~ %r{Second: Green Bananas\n}
402
+ end
403
+ end
404
+
405
+ it "resolves symlinks in the document root if PassengerResolveSymlinksInDocumentRoot is set" do
406
+ orig_app_root = @stub.app_root
407
+ @stub.move(File.expand_path('tmp.mycook.symlinktest'))
408
+ FileUtils.mkdir_p(orig_app_root)
409
+ File.symlink("#{@stub.app_root}/public", "#{orig_app_root}/public")
410
+ begin
411
+ File.write("#{@stub.app_root}/public/.htaccess", "PassengerResolveSymlinksInDocumentRoot on")
412
+ @server = @stub_url_root
413
+ get('/').should == "front page"
414
+ ensure
415
+ FileUtils.rm_rf(orig_app_root)
416
+ @stub.move(orig_app_root)
417
+ end
418
+ end
419
+
420
+ it "supports encoded slashes in the URL if AllowEncodedSlashes is turned on" do
421
+ @server = @stub_url_root
422
+ get('/env/foo%2fbar').should =~ %r{PATH_INFO = /env/foo/bar\n}
423
+
424
+ @server = @stub2_url_root
425
+ get('/env/foo%2fbar').should =~ %r{404 Not Found}
426
+ end
427
+
428
+ describe "when handling POST requests with 'chunked' transfer encoding, if PassengerBufferUpload is off" do
429
+ it "sets Transfer-Encoding to 'chunked' and removes Content-Length" do
430
+ @uri = URI.parse(@stub_url_root)
431
+ socket = TCPSocket.new(@uri.host, @uri.port)
432
+ begin
433
+ socket.write("POST #{@stub_url_root}/env HTTP/1.1\r\n")
434
+ socket.write("Host: #{@uri.host}:#{@uri.port}\r\n")
435
+ socket.write("Transfer-Encoding: chunked\r\n")
436
+ socket.write("Content-Type: text/plain\r\n")
437
+ socket.write("Connection: close\r\n")
438
+ socket.write("\r\n")
439
+
440
+ chunk = "foo=bar!"
441
+ socket.write("%X\r\n%s\r\n" % [chunk.size, chunk])
442
+ socket.write("0\r\n\r\n")
443
+ socket.flush
444
+
445
+ response = socket.read
446
+ response.should_not include("CONTENT_LENGTH = ")
447
+ response.should include("HTTP_TRANSFER_ENCODING = chunked\n")
448
+ ensure
449
+ socket.close
450
+ end
451
+ end
452
+ end
453
+
454
+ ####################################
455
+ end
456
+
457
+ describe "error handling" do
458
+ before :all do
459
+ create_apache2_controller
460
+ FileUtils.rm_rf('tmp.webdir')
461
+ FileUtils.mkdir_p('tmp.webdir')
462
+ @webdir = File.expand_path('tmp.webdir')
463
+ @apache2.set_vhost('1.passenger.test', @webdir) do |vhost|
464
+ vhost << "PassengerBaseURI /app-that-crashes-during-startup/public"
465
+ end
466
+
467
+ @stub = RackStub.new('rack')
468
+ @stub_url_root = "http://2.passenger.test:#{@apache2.port}"
469
+ @apache2.set_vhost('2.passenger.test', "#{@stub.full_app_root}/public")
470
+
471
+ @apache2 << "PassengerFriendlyErrorPages on"
472
+ @apache2.start
473
+ end
474
+
475
+ after :all do
476
+ FileUtils.rm_rf('tmp.webdir')
477
+ @stub.destroy
478
+ @apache2.stop if @apache2
479
+ end
480
+
481
+ before :each do
482
+ @server = "http://1.passenger.test:#{@apache2.port}"
483
+ @error_page_signature = /<meta name="generator" content="Phusion Passenger">/
484
+ @stub.reset
485
+ end
486
+
487
+ it "displays an error page if the application crashes during startup" do
488
+ RackStub.use('rack', "#{@webdir}/app-that-crashes-during-startup") do |stub|
489
+ File.prepend(stub.startup_file, "raise 'app crash'")
490
+ result = get("/app-that-crashes-during-startup/public")
491
+ result.should =~ @error_page_signature
492
+ result.should =~ /app crash/
493
+ end
494
+ end
495
+
496
+ it "doesn't display a Ruby spawn error page if PassengerFriendlyErrorPages is off" do
497
+ RackStub.use('rack', "#{@webdir}/app-that-crashes-during-startup") do |stub|
498
+ File.write("#{stub.app_root}/public/.htaccess", "PassengerFriendlyErrorPages off")
499
+ File.prepend(stub.startup_file, "raise 'app crash'")
500
+ result = get("/app-that-crashes-during-startup/public")
501
+ result.should_not =~ @error_page_signature
502
+ result.should_not =~ /app crash/
503
+ end
504
+ end
505
+ end
506
+
507
+ describe "HelperAgent" do
508
+ AdminTools = PhusionPassenger::AdminTools
509
+
510
+ before :all do
511
+ create_apache2_controller
512
+ @stub = RackStub.new('rack')
513
+ @stub_url_root = "http://1.passenger.test:#{@apache2.port}"
514
+ @apache2 << "PassengerStatThrottleRate 0"
515
+ @apache2.set_vhost('1.passenger.test', "#{@stub.full_app_root}/public")
516
+ @apache2.start
517
+ @server = "http://1.passenger.test:#{@apache2.port}"
518
+ end
519
+
520
+ after :all do
521
+ @stub.destroy
522
+ @apache2.stop if @apache2
523
+ end
524
+
525
+ before :each do
526
+ @stub.reset
527
+ end
528
+
529
+ it "is restarted if it crashes" do
530
+ # Make sure that all Apache worker processes have connected to
531
+ # the helper agent.
532
+ 10.times do
533
+ get('/').should == "front page"
534
+ sleep 0.1
535
+ end
536
+
537
+ # Now kill the helper agent.
538
+ instance = AdminTools::InstanceRegistry.new.list.first
539
+ Process.kill('SIGKILL', instance.server_pid)
540
+ sleep 0.02 # Give the signal a small amount of time to take effect.
541
+
542
+ # Each worker process should detect that the old
543
+ # helper agent has died, and should reconnect.
544
+ 10.times do
545
+ get('/').should == "front page"
546
+ sleep 0.1
547
+ end
548
+ end
549
+
550
+ it "exposes the application pool for passenger-status" do
551
+ File.touch("#{@stub.app_root}/tmp/restart.txt", 1) # Get rid of all previous app processes.
552
+ get('/').should == "front page"
553
+ instance = AdminTools::InstanceRegistry.new.list.first
554
+
555
+ # Wait until the server has processed the session close event.
556
+ sleep 0.1
557
+
558
+ request = Net::HTTP::Get.new("/pool.xml")
559
+ request.basic_auth("ro_admin", instance.read_only_admin_password)
560
+ response = instance.http_request("agents.s/server_admin", request)
561
+ if response.code.to_i / 100 == 2
562
+ doc = REXML::Document.new(response.body)
563
+ else
564
+ raise response.body
565
+ end
566
+
567
+ groups = doc.get_elements("info/supergroups/supergroup/group")
568
+ groups.should have(1).item
569
+ groups.each do |group|
570
+ group.elements["name"].text.should == "#{@stub.full_app_root} (production)#default"
571
+ processes = group.get_elements("processes/process")
572
+ processes.should have(1).item
573
+ processes[0].elements["processed"].text.should == "1"
574
+ end
575
+ end
576
+ end
577
+
578
+ ##### Helper methods #####
579
+
580
+ def start_web_server_if_necessary
581
+ if !@apache2.running?
582
+ @apache2.start
583
+ end
584
+ end
585
585
  end