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
@@ -25,109 +25,108 @@
25
25
  require 'thread'
26
26
 
27
27
  module PhusionPassenger
28
- module Rack
29
-
30
- class OutOfBandGc
31
- # Usage:
32
- #
33
- # OutOfBandGc.new(app, frequency, logger = nil)
34
- # OutOfBandGc.new(app, options = {})
35
- def initialize(app, *args)
36
- @app = app
37
- if args.size == 0 || (args.size == 1 && args[0].is_a?(Hash))
38
- # OutOfBandGc.new(app, options = {})
39
- initialize_with_options(args[0] || {})
40
- else
41
- # OutOfBandGc.new(app, frequency, logger = nil)
42
- initialize_legacy(*args)
43
- end
44
- end
45
-
46
- def call(env)
47
- status, headers, body = @app.call(env)
48
-
49
- case @strategy
50
- when :counting
51
- @mutex.synchronize do
52
- @request_count += 1
53
- if @request_count == @frequency
54
- @request_count = 0
55
- headers['!~Request-OOB-Work'] = 'true'
28
+ module Rack
29
+
30
+ class OutOfBandGc
31
+ # Usage:
32
+ #
33
+ # OutOfBandGc.new(app, frequency, logger = nil)
34
+ # OutOfBandGc.new(app, options = {})
35
+ def initialize(app, *args)
36
+ @app = app
37
+ if args.size == 0 || (args.size == 1 && args[0].is_a?(Hash))
38
+ # OutOfBandGc.new(app, options = {})
39
+ initialize_with_options(args[0] || {})
40
+ else
41
+ # OutOfBandGc.new(app, frequency, logger = nil)
42
+ initialize_legacy(*args)
56
43
  end
57
44
  end
58
45
 
59
- when :gctools_oobgc
60
- if GC::OOB.dry_run
61
- headers['!~Request-OOB-Work'] = 'true'
62
- end
63
-
64
- else
65
- raise "Unrecognized Out-Of-Band GC strategy #{@strategy.inspect}"
66
- end
46
+ def call(env)
47
+ status, headers, body = @app.call(env)
48
+
49
+ case @strategy
50
+ when :counting
51
+ @mutex.synchronize do
52
+ @request_count += 1
53
+ if @request_count == @frequency
54
+ @request_count = 0
55
+ headers['!~Request-OOB-Work'] = 'true'
56
+ end
57
+ end
58
+
59
+ when :gctools_oobgc
60
+ if GC::OOB.dry_run
61
+ headers['!~Request-OOB-Work'] = 'true'
62
+ end
63
+
64
+ else
65
+ raise "Unrecognized Out-Of-Band GC strategy #{@strategy.inspect}"
66
+ end
67
67
 
68
- [status, headers, body]
69
- end
70
-
71
- private
72
- def initialize_with_options(options)
73
- @strategy = options[:strategy]
74
- @logger = options[:logger]
75
-
76
- case @strategy
77
- when :counting
78
- @frequency = options[:frequency]
79
- @request_count = 0
80
- @mutex = Mutex.new
81
- if !@frequency || @frequency < 1
82
- raise ArgumentError, "The :frequency option must be a number that is at least 1."
83
- end
84
- ::PhusionPassenger.on_event(:oob_work) do
85
- t0 = Time.now
86
- disabled = GC.enable
87
- GC.start
88
- GC.disable if disabled
89
- @logger.info "Out Of Band GC finished in #{Time.now - t0} sec" if @logger
68
+ [status, headers, body]
90
69
  end
91
70
 
92
- when :gctools_oobgc
93
- if !defined?(::GC::OOB)
94
- raise "To use the :gctools_oobgc strategy, " +
95
- "first add 'gem \"gctools\"' to your Gemfile, " +
96
- "then call 'require \"gctools/oobgc\"' and 'GC::OOB.setup' " +
97
- "before using the #{self.class.name} middleware."
98
- elsif !::GC::OOB.respond_to?(:dry_run)
99
- raise "To use the :gctools_oobgc strategy, you must use a sufficiently " +
100
- "recent version of the gctools gem. Please see this pull request: " +
101
- "https://github.com/tmm1/gctools/pull/5"
102
- elsif PhusionPassenger::App.options["spawn_method"] =~ /smart/
103
- # Using GC::OOB with 'smart' currently results in a segfault.
104
- raise "The :gctools_oobgc strategy cannot be used with the '" +
105
- PhusionPassenger::App.options["spawn_method"] + "' spawning method. " +
106
- "Please use 'direct'."
107
- end
71
+ private
72
+ def initialize_with_options(options)
73
+ @strategy = options[:strategy]
74
+ @logger = options[:logger]
108
75
 
109
- ::PhusionPassenger.on_event(:oob_work) do
110
- t0 = Time.now
111
- GC::OOB.run
112
- @logger.info "Out Of Band GC finished in #{Time.now - t0} sec" if @logger
76
+ case @strategy
77
+ when :counting
78
+ @frequency = options[:frequency]
79
+ @request_count = 0
80
+ @mutex = Mutex.new
81
+ if !@frequency || @frequency < 1
82
+ raise ArgumentError, "The :frequency option must be a number that is at least 1."
83
+ end
84
+ ::PhusionPassenger.on_event(:oob_work) do
85
+ t0 = Time.now
86
+ disabled = GC.enable
87
+ GC.start
88
+ GC.disable if disabled
89
+ @logger.info "Out Of Band GC finished in #{Time.now - t0} sec" if @logger
90
+ end
91
+
92
+ when :gctools_oobgc
93
+ if !defined?(::GC::OOB)
94
+ raise "To use the :gctools_oobgc strategy, " +
95
+ "first add 'gem \"gctools\"' to your Gemfile, " +
96
+ "then call 'require \"gctools/oobgc\"' and 'GC::OOB.setup' " +
97
+ "before using the #{self.class.name} middleware."
98
+ elsif !::GC::OOB.respond_to?(:dry_run)
99
+ raise "To use the :gctools_oobgc strategy, you must use a sufficiently " +
100
+ "recent version of the gctools gem. Please see this pull request: " +
101
+ "https://github.com/tmm1/gctools/pull/5"
102
+ elsif PhusionPassenger::App.options["spawn_method"] =~ /smart/
103
+ # Using GC::OOB with 'smart' currently results in a segfault.
104
+ raise "The :gctools_oobgc strategy cannot be used with the '" +
105
+ PhusionPassenger::App.options["spawn_method"] + "' spawning method. " +
106
+ "Please use 'direct'."
107
+ end
108
+
109
+ ::PhusionPassenger.on_event(:oob_work) do
110
+ t0 = Time.now
111
+ GC::OOB.run
112
+ @logger.info "Out Of Band GC finished in #{Time.now - t0} sec" if @logger
113
+ end
114
+
115
+ when nil
116
+ raise ArgumentError, "You must specify an Out-Of-Band GC strategy with the :strategy option."
117
+
118
+ else
119
+ raise ArgumentError, "Invalid Out-Of-Band GC strategy #{@strategy.inspect}"
120
+ end
113
121
  end
114
122
 
115
- when nil
116
- raise ArgumentError, "You must specify an Out-Of-Band GC strategy with the :strategy option."
117
-
118
- else
119
- raise ArgumentError, "Invalid Out-Of-Band GC strategy #{@strategy.inspect}"
123
+ def initialize_legacy(frequency, logger = nil)
124
+ initialize_with_options(
125
+ :strategy => :counting,
126
+ :frequency => frequency,
127
+ :logger => logger)
128
+ end
120
129
  end
121
- end
122
130
 
123
- def initialize_legacy(frequency, logger = nil)
124
- initialize_with_options(
125
- :strategy => :counting,
126
- :frequency => frequency,
127
- :logger => logger)
128
- end
129
- end
130
-
131
- end # module Rack
131
+ end # module Rack
132
132
  end # module PhusionPassenger
133
-
@@ -25,246 +25,250 @@
25
25
  PhusionPassenger.require_passenger_lib 'utils/tee_input'
26
26
 
27
27
  module PhusionPassenger
28
- module Rack
28
+ module Rack
29
29
 
30
- module ThreadHandlerExtension
31
- # Constants which exist to relieve Ruby's garbage collector.
32
- RACK_VERSION = "rack.version" # :nodoc:
33
- RACK_VERSION_VALUE = [1, 2] # :nodoc:
34
- RACK_INPUT = "rack.input" # :nodoc:
35
- RACK_ERRORS = "rack.errors" # :nodoc:
36
- RACK_MULTITHREAD = "rack.multithread" # :nodoc:
37
- RACK_MULTIPROCESS = "rack.multiprocess" # :nodoc:
38
- RACK_RUN_ONCE = "rack.run_once" # :nodoc:
39
- RACK_URL_SCHEME = "rack.url_scheme" # :nodoc:
40
- RACK_HIJACK_P = "rack.hijack?" # :nodoc:
41
- RACK_HIJACK = "rack.hijack" # :nodoc:
42
- SCRIPT_NAME = "SCRIPT_NAME" # :nodoc:
43
- REQUEST_METHOD = "REQUEST_METHOD" # :nodoc:
44
- TRANSFER_ENCODING_HEADER = "Transfer-Encoding" # :nodoc:
45
- CONTENT_LENGTH_HEADER = "Content-Length" # :nodoc:
46
- CONTENT_LENGTH_HEADER_AND_SEPARATOR = "Content-Length: " # :nodoc
47
- TRANSFER_ENCODING_HEADER_AND_VALUE_CRLF2 = "Transfer-Encoding: chunked\r\n\r\n" # :nodoc:
48
- CONNECTION_CLOSE_CRLF = "Connection: close\r\n" # :nodoc:
49
- HEAD = "HEAD" # :nodoc:
50
- HTTPS = "HTTPS" # :nodoc:
51
- HTTPS_DOWNCASE = "https" # :nodoc:
52
- HTTP = "http" # :nodoc:
53
- YES = "yes" # :nodoc:
54
- ON = "on" # :nodoc:
55
- ONE = "1" # :nodoc:
56
- CRLF = "\r\n" # :nodoc:
57
- NEWLINE = "\n" # :nodoc:
58
- STATUS = "Status: " # :nodoc:
59
- NAME_VALUE_SEPARATOR = ": " # :nodoc:
60
- TERMINATION_CHUNK = "0\r\n\r\n" # :nodoc:
30
+ module ThreadHandlerExtension
31
+ # Constants which exist to relieve Ruby's garbage collector.
32
+ RACK_VERSION = "rack.version" # :nodoc:
33
+ RACK_VERSION_VALUE = [1, 2] # :nodoc:
34
+ RACK_INPUT = "rack.input" # :nodoc:
35
+ RACK_ERRORS = "rack.errors" # :nodoc:
36
+ RACK_MULTITHREAD = "rack.multithread" # :nodoc:
37
+ RACK_MULTIPROCESS = "rack.multiprocess" # :nodoc:
38
+ RACK_RUN_ONCE = "rack.run_once" # :nodoc:
39
+ RACK_URL_SCHEME = "rack.url_scheme" # :nodoc:
40
+ RACK_HIJACK_P = "rack.hijack?" # :nodoc:
41
+ RACK_HIJACK = "rack.hijack" # :nodoc:
42
+ SCRIPT_NAME = "SCRIPT_NAME" # :nodoc:
43
+ REQUEST_METHOD = "REQUEST_METHOD" # :nodoc:
44
+ TRANSFER_ENCODING_HEADER = "Transfer-Encoding" # :nodoc:
45
+ CONTENT_LENGTH_HEADER = "Content-Length" # :nodoc:
46
+ CONTENT_LENGTH_HEADER_AND_SEPARATOR = "Content-Length: " # :nodoc
47
+ TRANSFER_ENCODING_HEADER_AND_VALUE_CRLF2 = "Transfer-Encoding: chunked\r\n\r\n" # :nodoc:
48
+ CONNECTION_CLOSE_CRLF = "Connection: close\r\n" # :nodoc:
49
+ HEAD = "HEAD" # :nodoc:
50
+ HTTPS = "HTTPS" # :nodoc:
51
+ HTTPS_DOWNCASE = "https" # :nodoc:
52
+ HTTP = "http" # :nodoc:
53
+ YES = "yes" # :nodoc:
54
+ ON = "on" # :nodoc:
55
+ ONE = "1" # :nodoc:
56
+ CRLF = "\r\n" # :nodoc:
57
+ NEWLINE = "\n" # :nodoc:
58
+ STATUS = "Status: " # :nodoc:
59
+ NAME_VALUE_SEPARATOR = ": " # :nodoc:
60
+ TERMINATION_CHUNK = "0\r\n\r\n" # :nodoc:
61
61
 
62
- def process_request(env, connection, socket_wrapper, full_http_response)
63
- rewindable_input = PhusionPassenger::Utils::TeeInput.new(connection, env)
64
- begin
65
- env[RACK_VERSION] = RACK_VERSION_VALUE
66
- env[RACK_INPUT] = rewindable_input
67
- env[RACK_ERRORS] = STDERR
68
- env[RACK_MULTITHREAD] = @request_handler.concurrency > 1
69
- env[RACK_MULTIPROCESS] = true
70
- env[RACK_RUN_ONCE] = false
71
- if env[HTTPS] == YES || env[HTTPS] == ON || env[HTTPS] == ONE
72
- env[RACK_URL_SCHEME] = HTTPS_DOWNCASE
73
- else
74
- env[RACK_URL_SCHEME] = HTTP
75
- end
76
- env[RACK_HIJACK_P] = true
77
- env[RACK_HIJACK] = lambda do
78
- env[RACK_HIJACK_IO] ||= begin
79
- connection.stop_simulating_eof!
80
- connection
81
- end
82
- end
62
+ def process_request(env, connection, socket_wrapper, full_http_response)
63
+ rewindable_input = PhusionPassenger::Utils::TeeInput.new(connection, env)
64
+ begin
65
+ env[RACK_VERSION] = RACK_VERSION_VALUE
66
+ env[RACK_INPUT] = rewindable_input
67
+ env[RACK_ERRORS] = STDERR
68
+ env[RACK_MULTITHREAD] = @request_handler.concurrency > 1
69
+ env[RACK_MULTIPROCESS] = true
70
+ env[RACK_RUN_ONCE] = false
71
+ if env[HTTPS] == YES || env[HTTPS] == ON || env[HTTPS] == ONE
72
+ env[RACK_URL_SCHEME] = HTTPS_DOWNCASE
73
+ else
74
+ env[RACK_URL_SCHEME] = HTTP
75
+ end
76
+ env[RACK_HIJACK_P] = true
77
+ env[RACK_HIJACK] = lambda do
78
+ env[RACK_HIJACK_IO] ||= begin
79
+ connection.stop_simulating_eof!
80
+ connection
81
+ end
82
+ end
83
83
 
84
- begin
85
- status, headers, body = @app.call(env)
86
- rescue => e
87
- if should_reraise_app_error?(e, socket_wrapper)
88
- raise e
89
- elsif !should_swallow_app_error?(e, socket_wrapper)
90
- # It's a good idea to catch application exceptions here because
91
- # otherwise maliciously crafted responses can crash the app,
92
- # forcing it to be respawned, and thereby effectively DoSing it.
93
- print_exception("Rack application object", e)
94
- PhusionPassenger.log_request_exception(env, e)
95
- end
96
- return false
97
- end
84
+ begin
85
+ status, headers, body = @app.call(env)
86
+ rescue => e
87
+ if should_reraise_app_error?(e, socket_wrapper)
88
+ raise e
89
+ elsif !should_swallow_app_error?(e, socket_wrapper)
90
+ # It's a good idea to catch application exceptions here because
91
+ # otherwise maliciously crafted responses can crash the app,
92
+ # forcing it to be respawned, and thereby effectively DoSing it.
93
+ print_exception("Rack application object", e)
94
+ PhusionPassenger.log_request_exception(env, e)
95
+ end
96
+ return false
97
+ end
98
98
 
99
- # Application requested a full socket hijack.
100
- return true if env[RACK_HIJACK_IO]
99
+ # Application requested a full socket hijack.
100
+ return true if env[RACK_HIJACK_IO]
101
101
 
102
- begin
103
- process_body(env, connection, socket_wrapper, status.to_i, headers, body)
104
- ensure
105
- body.close if body && body.respond_to?(:close)
106
- end
107
- ensure
108
- rewindable_input.close
109
- end
110
- end
102
+ begin
103
+ process_body(env, connection, socket_wrapper, status.to_i, headers, body)
104
+ ensure
105
+ body.close if body && body.respond_to?(:close)
106
+ end
107
+ ensure
108
+ rewindable_input.close
109
+ end
110
+ end
111
111
 
112
- private
113
- # The code here is ugly, but it's necessary for performance.
114
- def process_body(env, connection, socket_wrapper, status, headers, body)
115
- if hijack_callback = headers[RACK_HIJACK]
116
- # Application requested a partial socket hijack.
117
- body = nil
118
- headers_output = generate_headers_array(status, headers)
119
- headers_output << "Connection: close\r\n"
120
- headers_output << CRLF
121
- connection.writev(headers_output)
122
- connection.flush
123
- hijacked_socket = env[RACK_HIJACK].call
124
- hijack_callback.call(hijacked_socket)
125
- return true
126
- elsif body.is_a?(Array)
127
- # The body may be an ActionController::StringCoercion::UglyBody
128
- # object instead of a real Array, even when #is_a? claims so.
129
- # Call #to_a just to be sure.
130
- body = body.to_a
131
- output_body = should_output_body?(status, env)
132
- headers_output = generate_headers_array(status, headers)
133
- perform_keep_alive(env, headers_output)
134
- if output_body && should_add_message_length_header?(status, headers)
135
- body_size = 0
136
- body.each { |part| body_size += bytesize(part.to_s) }
137
- headers_output << CONTENT_LENGTH_HEADER_AND_SEPARATOR
138
- headers_output << body_size.to_s
139
- headers_output << CRLF
140
- end
141
- headers_output << CRLF
142
- if output_body
143
- connection.writev2(headers_output, body)
144
- else
145
- connection.writev(headers_output)
146
- end
147
- return false
148
- elsif body.is_a?(String)
149
- output_body = should_output_body?(status, env)
150
- headers_output = generate_headers_array(status, headers)
151
- perform_keep_alive(env, headers_output)
152
- if output_body && should_add_message_length_header?(status, headers)
153
- headers_output << CONTENT_LENGTH_HEADER_AND_SEPARATOR
154
- headers_output << bytesize(body).to_s
155
- headers_output << CRLF
156
- end
157
- headers_output << CRLF
158
- if output_body
159
- headers_output << body
160
- end
161
- connection.writev(headers_output)
162
- return false
163
- else
164
- output_body = should_output_body?(status, env)
165
- headers_output = generate_headers_array(status, headers)
166
- perform_keep_alive(env, headers_output)
167
- chunk = output_body && should_add_message_length_header?(status, headers)
168
- if chunk
169
- headers_output << TRANSFER_ENCODING_HEADER_AND_VALUE_CRLF2
170
- else
171
- headers_output << CRLF
172
- end
173
- connection.writev(headers_output)
174
- if output_body && body
175
- begin
176
- if chunk
177
- body.each do |s|
178
- connection.writev(chunk_data(s))
179
- end
180
- connection.write(TERMINATION_CHUNK)
181
- else
182
- body.each do |s|
183
- connection.write(s)
184
- end
185
- end
186
- rescue => e
187
- if should_reraise_app_error?(e, socket_wrapper)
188
- raise e
189
- elsif !should_swallow_app_error?(e, socket_wrapper)
190
- # Body objects can raise exceptions in #each.
191
- print_exception("Rack body object #each method", e)
192
- end
193
- return false
194
- end
195
- end
196
- return false
197
- end
198
- end
112
+ private
113
+ # The code here is ugly, but it's necessary for performance.
114
+ def process_body(env, connection, socket_wrapper, status, headers, body)
115
+ if hijack_callback = headers[RACK_HIJACK]
116
+ # Application requested a partial socket hijack.
117
+ body = nil
118
+ headers_output = generate_headers_array(status, headers)
119
+ headers_output << "Connection: close\r\n"
120
+ headers_output << CRLF
121
+ connection.writev(headers_output)
122
+ connection.flush
123
+ hijacked_socket = env[RACK_HIJACK].call
124
+ hijack_callback.call(hijacked_socket)
125
+ true
126
+ elsif body.is_a?(Array)
127
+ # The body may be an ActionController::StringCoercion::UglyBody
128
+ # object instead of a real Array, even when #is_a? claims so.
129
+ # Call #to_a just to be sure.
130
+ body = body.to_a
131
+ output_body = should_output_body?(status, env)
132
+ headers_output = generate_headers_array(status, headers)
133
+ perform_keep_alive(env, headers_output)
134
+ if output_body && should_add_message_length_header?(status, headers)
135
+ body_size = 0
136
+ body.each { |part| body_size += bytesize(part.to_s) }
137
+ headers_output << CONTENT_LENGTH_HEADER_AND_SEPARATOR
138
+ headers_output << body_size.to_s
139
+ headers_output << CRLF
140
+ end
141
+ headers_output << CRLF
142
+ if output_body
143
+ connection.writev2(headers_output, body)
144
+ else
145
+ connection.writev(headers_output)
146
+ end
147
+ false
148
+ elsif body.is_a?(String)
149
+ output_body = should_output_body?(status, env)
150
+ headers_output = generate_headers_array(status, headers)
151
+ perform_keep_alive(env, headers_output)
152
+ if output_body && should_add_message_length_header?(status, headers)
153
+ headers_output << CONTENT_LENGTH_HEADER_AND_SEPARATOR
154
+ headers_output << bytesize(body).to_s
155
+ headers_output << CRLF
156
+ end
157
+ headers_output << CRLF
158
+ if output_body
159
+ headers_output << body
160
+ end
161
+ connection.writev(headers_output)
162
+ false
163
+ else
164
+ output_body = should_output_body?(status, env)
165
+ headers_output = generate_headers_array(status, headers)
166
+ perform_keep_alive(env, headers_output)
167
+ chunk = output_body && should_add_message_length_header?(status, headers)
168
+ if chunk
169
+ headers_output << TRANSFER_ENCODING_HEADER_AND_VALUE_CRLF2
170
+ else
171
+ headers_output << CRLF
172
+ end
173
+ connection.writev(headers_output)
174
+ if output_body && body
175
+ begin
176
+ if chunk
177
+ body.each do |part|
178
+ part = force_binary(part)
179
+ size = bytesize(part)
180
+ if size != 0
181
+ connection.writev(chunk_data(part, size))
182
+ end
183
+ end
184
+ connection.write(TERMINATION_CHUNK)
185
+ else
186
+ body.each do |s|
187
+ connection.write(s)
188
+ end
189
+ end
190
+ rescue => e
191
+ if should_reraise_app_error?(e, socket_wrapper)
192
+ raise e
193
+ elsif !should_swallow_app_error?(e, socket_wrapper)
194
+ # Body objects can raise exceptions in #each.
195
+ print_exception("Rack body object #each method", e)
196
+ end
197
+ false
198
+ end
199
+ end
200
+ false
201
+ end
202
+ end
199
203
 
200
- def generate_headers_array(status, headers)
201
- status_str = status.to_s
202
- result = ["HTTP/1.1 #{status_str} Whatever\r\n"]
203
- headers.each do |key, values|
204
- if values.is_a?(String)
205
- values = values.split(NEWLINE)
206
- elsif key == RACK_HIJACK
207
- # We do not check for this key name in every loop
208
- # iteration as an optimization.
209
- next
210
- else
211
- values = values.to_s.split(NEWLINE)
212
- end
213
- values.each do |value|
214
- result << key
215
- result << NAME_VALUE_SEPARATOR
216
- result << value
217
- result << CRLF
218
- end
219
- end
220
- return result
221
- end
204
+ def generate_headers_array(status, headers)
205
+ status_str = status.to_s
206
+ result = ["HTTP/1.1 #{status_str} Whatever\r\n"]
207
+ headers.each do |key, values|
208
+ if values.is_a?(String)
209
+ values = values.split(NEWLINE)
210
+ elsif key == RACK_HIJACK
211
+ # We do not check for this key name in every loop
212
+ # iteration as an optimization.
213
+ next
214
+ else
215
+ values = values.to_s.split(NEWLINE)
216
+ end
217
+ values.each do |value|
218
+ result << key
219
+ result << NAME_VALUE_SEPARATOR
220
+ result << value
221
+ result << CRLF
222
+ end
223
+ end
224
+ return result
225
+ end
222
226
 
223
- def perform_keep_alive(env, headers)
224
- if @can_keepalive
225
- @keepalive_performed = true
226
- else
227
- headers << CONNECTION_CLOSE_CRLF
228
- end
229
- end
227
+ def perform_keep_alive(env, headers)
228
+ if @can_keepalive
229
+ @keepalive_performed = true
230
+ else
231
+ headers << CONNECTION_CLOSE_CRLF
232
+ end
233
+ end
230
234
 
231
- def should_output_body?(status, env)
232
- return (status < 100 ||
233
- (status >= 200 && status != 204 && status != 205 && status != 304)) &&
234
- env[REQUEST_METHOD] != HEAD
235
- end
235
+ def should_output_body?(status, env)
236
+ return (status < 100 ||
237
+ (status >= 200 && status != 204 && status != 205 && status != 304)) &&
238
+ env[REQUEST_METHOD] != HEAD
239
+ end
236
240
 
237
- def should_add_message_length_header?(status, headers)
238
- return !headers.has_key?(TRANSFER_ENCODING_HEADER) &&
239
- !headers.has_key?(CONTENT_LENGTH_HEADER)
240
- end
241
+ def should_add_message_length_header?(status, headers)
242
+ return !headers.has_key?(TRANSFER_ENCODING_HEADER) &&
243
+ !headers.has_key?(CONTENT_LENGTH_HEADER)
244
+ end
241
245
 
242
- def chunk_data(data)
243
- [bytesize(data).to_s(16), CRLF, force_binary(data), CRLF]
244
- end
246
+ def chunk_data(data, size)
247
+ [size.to_s(16), CRLF, data, CRLF]
248
+ end
245
249
 
246
- if "".respond_to?(:bytesize)
247
- def bytesize(str)
248
- str.bytesize
249
- end
250
- else
251
- def bytesize(str)
252
- str.size
253
- end
254
- end
250
+ if "".respond_to?(:bytesize)
251
+ def bytesize(str)
252
+ str.bytesize
253
+ end
254
+ else
255
+ def bytesize(str)
256
+ str.size
257
+ end
258
+ end
255
259
 
256
- if "".respond_to?(:force_encoding)
257
- BINARY = "binary".freeze
260
+ if "".respond_to?(:force_encoding)
261
+ BINARY = "binary".freeze
258
262
 
259
- def force_binary(str)
260
- str.force_encoding(BINARY)
261
- end
262
- else
263
- def force_binary(str)
264
- str
265
- end
266
- end
267
- end
263
+ def force_binary(str)
264
+ str.force_encoding(BINARY)
265
+ end
266
+ else
267
+ def force_binary(str)
268
+ str
269
+ end
270
+ end
271
+ end
268
272
 
269
- end # module Rack
273
+ end # module Rack
270
274
  end # module PhusionPassenger