passenger 4.0.25 → 4.0.26

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 (38) hide show
  1. data.tar.gz.asc +7 -7
  2. data/NEWS +11 -0
  3. data/build/packaging.rb +3 -3
  4. data/debian.template/passenger.install.template +1 -1
  5. data/debian.template/rules.template +2 -1
  6. data/doc/Users guide Apache.idmap.txt +5 -3
  7. data/doc/Users guide Apache.txt +22 -0
  8. data/doc/Users guide Nginx.txt +12 -12
  9. data/doc/Users guide Standalone.txt +10 -1
  10. data/ext/apache2/ConfigurationCommands.cpp +18 -0
  11. data/ext/apache2/ConfigurationFields.hpp +6 -0
  12. data/ext/apache2/ConfigurationSetters.cpp +27 -0
  13. data/ext/apache2/CreateDirConfig.cpp +3 -0
  14. data/ext/apache2/DirectoryMapper.h +15 -6
  15. data/ext/apache2/Hooks.cpp +34 -10
  16. data/ext/apache2/MergeDirConfig.cpp +21 -0
  17. data/ext/apache2/SetHeaders.cpp +4 -0
  18. data/ext/common/Constants.h +1 -1
  19. data/ext/common/Utils.cpp +0 -1
  20. data/ext/common/Utils/VariantMap.h +1 -1
  21. data/ext/common/agents/HelperAgent/AgentOptions.h +4 -0
  22. data/ext/common/agents/HelperAgent/Main.cpp +10 -3
  23. data/ext/nginx/ContentHandler.c +2 -7
  24. data/helper-scripts/download_binaries/extconf.rb +7 -5
  25. data/lib/phusion_passenger.rb +1 -1
  26. data/lib/phusion_passenger/abstract_installer.rb +7 -22
  27. data/lib/phusion_passenger/admin_tools/memory_stats.rb +1 -1
  28. data/lib/phusion_passenger/apache2/config_options.rb +20 -0
  29. data/lib/phusion_passenger/standalone/runtime_installer.rb +69 -49
  30. data/lib/phusion_passenger/standalone/runtime_locator.rb +3 -3
  31. data/lib/phusion_passenger/standalone/start_command.rb +13 -1
  32. data/lib/phusion_passenger/utils/download.rb +193 -0
  33. data/resources/templates/standalone/config.erb +20 -3
  34. data/test/ruby/standalone/runtime_installer_spec.rb +69 -69
  35. data/test/ruby/standalone/runtime_locator_spec.rb +3 -3
  36. metadata +3 -3
  37. metadata.gz.asc +7 -7
  38. data/resources/templates/standalone/welcome.txt.erb +0 -8
@@ -84,9 +84,9 @@ class RuntimeLocator
84
84
  if result = config["nginx_binary"]
85
85
  @nginx_binary = result
86
86
  elsif PhusionPassenger.natively_packaged? && @nginx_version == PhusionPassenger::PREFERRED_NGINX_VERSION
87
- @nginx_binary = "#{PhusionPassenger.lib_dir}/nginx"
87
+ @nginx_binary = "#{PhusionPassenger.lib_dir}/PassengerWebHelper"
88
88
  else
89
- filename = "#{@runtime_dir}/#{version}/nginx-#{@nginx_version}-#{cxx_compat_id}/nginx"
89
+ filename = "#{@runtime_dir}/#{version}/webhelper-#{@nginx_version}-#{cxx_compat_id}/PassengerWebHelper"
90
90
  if File.exist?(filename)
91
91
  @nginx_binary = filename
92
92
  else
@@ -133,7 +133,7 @@ class RuntimeLocator
133
133
  # Returns the directory to which the Nginx binary may be installed,
134
134
  # in case the RuntimeInstaller is to be invoked.
135
135
  def nginx_binary_install_destination
136
- return "#{@runtime_dir}/#{version}/nginx-#{@nginx_version}-#{cxx_compat_id}"
136
+ return "#{@runtime_dir}/#{version}/webhelper-#{@nginx_version}-#{cxx_compat_id}"
137
137
  end
138
138
 
139
139
  private
@@ -202,6 +202,10 @@ private
202
202
  wrap_desc("Specify the SSL key path")) do |val|
203
203
  @options[:ssl_certificate_key] = File.expand_path(val)
204
204
  end
205
+ opts.on("--ssl-port PORT", Integer,
206
+ wrap_desc("Listen for SSL on this port, while listening for HTTP on the normal port")) do |val|
207
+ @options[:ssl_port] = val
208
+ end
205
209
  opts.on("--static-files-dir PATH", String,
206
210
  wrap_desc("Specify the static files dir")) do |val|
207
211
  @options[:static_files_dir] = File.expand_path(val)
@@ -431,7 +435,7 @@ private
431
435
  if @options[:socket_file]
432
436
  return @options[:socket_file]
433
437
  else
434
- if @options[:ssl]
438
+ if @options[:ssl] && !@options[:ssl_port]
435
439
  scheme = "https"
436
440
  else
437
441
  scheme = "http"
@@ -700,6 +704,14 @@ private
700
704
  end
701
705
  end
702
706
 
707
+ def nginx_listen_address_with_ssl_port(options = @options)
708
+ if options[:socket_file]
709
+ return "unix:" + File.expand_path(options[:socket_file])
710
+ else
711
+ return "#{options[:address]}:#{options[:ssl_port]}"
712
+ end
713
+ end
714
+
703
715
  def default_group_for(username)
704
716
  user = Etc.getpwnam(username)
705
717
  group = Etc.getgrgid(user.gid)
@@ -0,0 +1,193 @@
1
+ # encoding: utf-8
2
+ # Phusion Passenger - https://www.phusionpassenger.com/
3
+ # Copyright (c) 2013 Phusion
4
+ #
5
+ # "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in
15
+ # all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ # THE SOFTWARE.
24
+
25
+ require 'phusion_passenger'
26
+ require 'phusion_passenger/platform_info'
27
+ require 'fileutils'
28
+ require 'shellwords'
29
+
30
+ module PhusionPassenger
31
+ module Utils
32
+
33
+ module Download
34
+ extend self # Make methods available as class methods.
35
+
36
+ def self.included(klass)
37
+ # When included into another class, make sure that Utils
38
+ # methods are made private.
39
+ public_instance_methods(false).each do |method_name|
40
+ klass.send(:private, method_name)
41
+ end
42
+ end
43
+
44
+ # Downloads a file from the given URL and saves it to the given filename.
45
+ # Returns whether the download succeeded.
46
+ #
47
+ # Options:
48
+ #
49
+ # show_progress: whether to show download progress. Default: false.
50
+ # logger: the logger to use. If not given, this function will log to STDERR.
51
+ # cacert: a CA certificate file to use for verifying SSL websites.
52
+ # The default is to use the download tool's down CA database.
53
+ # use_cache: Whether to copy the file from the download cache, if available.
54
+ # Default: false.
55
+ def download(url, output, options = {})
56
+ logger = options[:logger] || Logger.new(STDERR)
57
+
58
+ if options[:use_cache] && cache_dir = PhusionPassenger.download_cache_dir
59
+ basename = basename_from_url(url)
60
+ if File.exist?("#{cache_dir}/#{basename}")
61
+ logger.info "Copying #{basename} from #{cache_dir}..."
62
+ FileUtils.cp("#{cache_dir}/#{basename}", output)
63
+ return true
64
+ end
65
+ end
66
+
67
+ if PlatformInfo.find_command("curl")
68
+ return download_with_curl(logger, url, output, options)
69
+ elsif PlatformInfo.find_command("wget")
70
+ return download_with_wget(logger, url, output, options)
71
+ else
72
+ logger.error "Could not download #{url}: no download tool found (curl or wget required)"
73
+ return false
74
+ end
75
+ end
76
+
77
+ private
78
+ def basename_from_url(url)
79
+ return url.sub(/.*\//, '')
80
+ end
81
+
82
+ def download_with_curl(logger, url, output, options)
83
+ command = ["curl", "-f", "-L", "-o", output]
84
+ if options[:show_progress]
85
+ command << "-#"
86
+ else
87
+ command << "-s"
88
+ command << "-S"
89
+ end
90
+ if options[:cacert]
91
+ command << "--cacert"
92
+ command << options[:cacert]
93
+ end
94
+ command << url
95
+ command_str = Shellwords.join(command)
96
+ logger.info("Invoking: #{command_str}")
97
+
98
+ if options[:show_progress]
99
+ # If curl errors out we don't want it to display 'curl: ' prefixes,
100
+ # so we parse its output.
101
+ begin
102
+ io = IO.popen("#{command_str} 2>&1", "r")
103
+ rescue SystemCallError => e
104
+ logger.error("Could not invoke curl: #{e}")
105
+ return false
106
+ end
107
+ begin
108
+ non_empty_line_encountered = false
109
+ while !io.eof?
110
+ # We split on "\r" because progress bar lines do not contain "\n".
111
+ data = io.gets("\r")
112
+ data = remove_curl_output_prefix(data)
113
+
114
+ # If an error occurs then the first few lines may be empty.
115
+ # Skip those.
116
+ if !non_empty_line_encountered && data =~ /\A\n+/
117
+ data.gsub!(/\A\n+/, '')
118
+ end
119
+
120
+ non_empty_line_encountered = true
121
+ STDERR.write(data)
122
+ STDERR.flush
123
+ end
124
+ ensure
125
+ io.close
126
+ end
127
+ result = $?.exitstatus == 0
128
+ else
129
+ begin
130
+ output = `#{command_str} 2>&1`
131
+ rescue SystemCallError => e
132
+ logger.error("Could not invoke curl: #{e}")
133
+ return false
134
+ end
135
+ result = $?.exitstatus == 0
136
+ if !result
137
+ output = remove_curl_output_prefix(output)
138
+ output.chomp!
139
+ logger.error("Could not download #{url}: #{output}")
140
+ end
141
+ end
142
+
143
+ return result
144
+ end
145
+
146
+ def remove_curl_output_prefix(line)
147
+ return line.gsub(/^curl: (\([0-9]+\) )?/, '')
148
+ end
149
+
150
+ def download_with_wget(logger, url, output, options)
151
+ command = ["wget", "--tries=3", "-O", output]
152
+ if !options[:show_progress]
153
+ command << "-nv"
154
+ end
155
+ if options[:cacert]
156
+ command << "--ca-certificate=#{options[:cacert]}"
157
+ end
158
+ command << url
159
+ command_str = Shellwords.join(command)
160
+ logger.info("Invoking: #{command_str}")
161
+
162
+ if options[:show_progress]
163
+ begin
164
+ result = system(*command)
165
+ rescue SystemCallError => e
166
+ logger.error("Could not invoke wget: #{e}")
167
+ return false
168
+ end
169
+ if !result
170
+ logger.error("Could not download #{url}: #{output}")
171
+ end
172
+ else
173
+ begin
174
+ output = `#{command_str} 2>&1`
175
+ rescue SystemCallError => e
176
+ logger.error("Could not invoke wget: #{e}")
177
+ return false
178
+ end
179
+ result = $?.exitstatus == 0
180
+ if !result
181
+ # Error output may begin with "<URL>:\n" which is redundant.
182
+ output.gsub!(/\A#{Regexp.escape url}:\n/, '')
183
+ output.chomp!
184
+ logger.error("Could not download #{url}: #{output}")
185
+ end
186
+ end
187
+
188
+ return result
189
+ end
190
+ end
191
+
192
+ end # module Utils
193
+ end # module PhusionPassenger
@@ -73,7 +73,16 @@ http {
73
73
  <% if @apps.size > 1 %>
74
74
  # Default server entry.
75
75
  server {
76
- listen <%= nginx_listen_address %>;
76
+ <% if @options[:ssl] %>
77
+ <% if @options[:ssl_port] %>
78
+ listen <%= nginx_listen_address %>;
79
+ listen <%= nginx_listen_address_with_ssl_port %> ssl;
80
+ <% else %>
81
+ listen <%= nginx_listen_address %> ssl;
82
+ <% end %>
83
+ <% else %>
84
+ listen <%= nginx_listen_address %>;
85
+ <% end %>
77
86
  root '<%= PhusionPassenger.resources_dir %>/standalone_default_root';
78
87
  }
79
88
  <% end %>
@@ -87,7 +96,16 @@ http {
87
96
 
88
97
  <% for app in @apps %>
89
98
  server {
90
- listen <%= nginx_listen_address(app) %> <%= "ssl" if app[:ssl] %>;
99
+ <% if app[:ssl] %>
100
+ <% if app[:ssl_port] %>
101
+ listen <%= nginx_listen_address(app) %>;
102
+ listen <%= nginx_listen_address_with_ssl_port(app) %> ssl;
103
+ <% else %>
104
+ listen <%= nginx_listen_address(app) %> ssl;
105
+ <% end %>
106
+ <% else %>
107
+ listen <%= nginx_listen_address(app) %>;
108
+ <% end %>
91
109
  server_name <%= app[:server_names].join(' ') %>;
92
110
  <% if app[:static_files_dir] %>
93
111
  root '<%= app[:static_files_dir] %>';
@@ -109,7 +127,6 @@ http {
109
127
  union_station_key <%= app[:union_station_key] %>;
110
128
  <% end %>
111
129
  <% if app[:ssl] %>
112
- ssl on;
113
130
  ssl_certificate <%= app[:ssl_certificate] %>;
114
131
  ssl_certificate_key <%= app[:ssl_certificate_key] %>;
115
132
  <% end %>
@@ -25,7 +25,7 @@ describe RuntimeInstaller do
25
25
  let(:nginx_version) { PhusionPassenger::PREFERRED_NGINX_VERSION }
26
26
  let(:cxx_compat_id) { PlatformInfo.cxx_binary_compatibility_id }
27
27
  let(:support_binaries_url) { "#{binaries_url_root}/#{version}/support-#{cxx_compat_id}.tar.gz" }
28
- let(:nginx_binary_url) { "#{binaries_url_root}/#{version}/nginx-#{nginx_version}-#{cxx_compat_id}.tar.gz" }
28
+ let(:nginx_binary_url) { "#{binaries_url_root}/#{version}/webhelper-#{nginx_version}-#{cxx_compat_id}.tar.gz" }
29
29
  let(:nginx_source_url) { "http://nginx.org/download/nginx-#{nginx_version}.tar.gz" }
30
30
 
31
31
  def create_installer(options = {})
@@ -64,11 +64,11 @@ describe RuntimeInstaller do
64
64
  end
65
65
 
66
66
  def create_dummy_nginx_binary
67
- File.open("nginx", "w") do |f|
67
+ File.open("PassengerWebHelper", "w") do |f|
68
68
  f.puts "#!/bin/bash"
69
69
  f.puts "echo nginx version: 1.0.0"
70
70
  end
71
- File.chmod(0755, "nginx")
71
+ File.chmod(0755, "PassengerWebHelper")
72
72
  end
73
73
 
74
74
  def create_dummy_nginx_source
@@ -99,24 +99,24 @@ describe RuntimeInstaller do
99
99
  :nginx_dir => "#{@temp_dir}/nginx",
100
100
  :lib_dir => PhusionPassenger.lib_dir)
101
101
 
102
- @installer.should_receive(:download).
103
- and_return do |url, output, options|
104
- url.should == nginx_binary_url
105
- options[:use_cache].should be_true
106
- create_tarball(output) do
107
- create_dummy_nginx_binary
108
- end
109
- true
102
+ @installer.should_receive(:download).
103
+ and_return do |url, output, options|
104
+ url.should == nginx_binary_url
105
+ options[:use_cache].should be_true
106
+ create_tarball(output) do
107
+ create_dummy_nginx_binary
110
108
  end
109
+ true
110
+ end
111
111
 
112
- @installer.should_receive(:check_for_download_tool)
113
- @installer.should_not_receive(:check_depdendencies)
114
- @installer.should_not_receive(:compile_support_binaries)
115
- @installer.should_not_receive(:download_and_extract_nginx_sources)
116
- @installer.should_not_receive(:compile_nginx)
117
- @installer.run
112
+ @installer.should_receive(:check_for_download_tool)
113
+ @installer.should_not_receive(:check_depdendencies)
114
+ @installer.should_not_receive(:compile_support_binaries)
115
+ @installer.should_not_receive(:download_and_extract_nginx_sources)
116
+ @installer.should_not_receive(:compile_nginx)
117
+ @installer.run
118
118
 
119
- File.exist?("#{@temp_dir}/nginx/nginx").should be_true
119
+ File.exist?("#{@temp_dir}/nginx/PassengerWebHelper").should be_true
120
120
  end
121
121
 
122
122
  def test_building_nginx_binary
@@ -124,30 +124,30 @@ describe RuntimeInstaller do
124
124
  :nginx_dir => "#{@temp_dir}/nginx",
125
125
  :lib_dir => PhusionPassenger.lib_dir)
126
126
 
127
- @installer.should_receive(:download).twice.and_return do |url, output|
128
- if url == nginx_binary_url
129
- false
130
- elsif url == nginx_source_url
131
- create_tarball(output) do
132
- create_dummy_nginx_source
133
- end
134
- true
135
- else
136
- raise "Unexpected download URL: #{url}"
127
+ @installer.should_receive(:download).twice.and_return do |url, output|
128
+ if url == nginx_binary_url
129
+ false
130
+ elsif url == nginx_source_url
131
+ create_tarball(output) do
132
+ create_dummy_nginx_source
137
133
  end
134
+ true
135
+ else
136
+ raise "Unexpected download URL: #{url}"
138
137
  end
138
+ end
139
139
 
140
- @installer.should_receive(:check_for_download_tool)
141
- @installer.should_receive(:check_dependencies).and_return(true)
142
- @installer.should_not_receive(:compile_support_binaries)
143
- @installer.should_receive(:strip_binary).
144
- with(an_instance_of(String)).
145
- and_return(true)
146
- @installer.run
147
-
148
- File.read("#{@temp_dir}/nginx/nginx").should == "ok\n"
149
- File.read("#{@temp_dir}/configure.txt").should include(
150
- "--add-module=#{PhusionPassenger.nginx_module_source_dir}")
140
+ @installer.should_receive(:check_for_download_tool)
141
+ @installer.should_receive(:check_dependencies).and_return(true)
142
+ @installer.should_not_receive(:compile_support_binaries)
143
+ @installer.should_receive(:strip_binary).
144
+ with(an_instance_of(String)).
145
+ and_return(true)
146
+ @installer.run
147
+
148
+ File.read("#{@temp_dir}/nginx/PassengerWebHelper").should == "ok\n"
149
+ File.read("#{@temp_dir}/configure.txt").should include(
150
+ "--add-module=#{PhusionPassenger.nginx_module_source_dir}")
151
151
  end
152
152
 
153
153
  context "when originally packaged" do
@@ -216,7 +216,7 @@ describe RuntimeInstaller do
216
216
  @installer.run
217
217
 
218
218
  File.exist?("#{@temp_dir}/support/agents/PassengerWatchdog").should be_true
219
- File.exist?("#{@temp_dir}/nginx/nginx").should be_true
219
+ File.exist?("#{@temp_dir}/nginx/PassengerWebHelper").should be_true
220
220
  end
221
221
 
222
222
  it "builds the support binaries if it cannot be downloaded" do
@@ -304,39 +304,39 @@ describe RuntimeInstaller do
304
304
  :nginx_dir => "#{@temp_dir}/nginx",
305
305
  :lib_dir => PhusionPassenger.lib_dir)
306
306
 
307
- @installer.should_receive(:download).
308
- exactly(3).times.
309
- and_return do |url, output, options|
310
- if url == support_binaries_url
311
- options[:use_cache].should be_true
312
- create_tarball(output) do
313
- create_dummy_support_binaries
314
- end
315
- elsif url == nginx_binary_url
316
- options[:use_cache].should be_true
317
- create_tarball(output) do
318
- create_dummy_nginx_binary
319
- end
320
- elsif url == nginx_source_url
321
- create_tarball(output) do
322
- create_dummy_nginx_source
323
- end
324
- else
325
- raise "Unexpected download URL: #{url}"
307
+ @installer.should_receive(:download).
308
+ exactly(3).times.
309
+ and_return do |url, output, options|
310
+ if url == support_binaries_url
311
+ options[:use_cache].should be_true
312
+ create_tarball(output) do
313
+ create_dummy_support_binaries
326
314
  end
327
- true
315
+ elsif url == nginx_binary_url
316
+ options[:use_cache].should be_true
317
+ create_tarball(output) do
318
+ create_dummy_nginx_binary
319
+ end
320
+ elsif url == nginx_source_url
321
+ create_tarball(output) do
322
+ create_dummy_nginx_source
323
+ end
324
+ else
325
+ raise "Unexpected download URL: #{url}"
328
326
  end
327
+ true
328
+ end
329
329
 
330
- @installer.should_receive(:check_for_download_tool)
331
- @installer.should_receive(:check_support_binaries).and_return(false)
332
- @installer.should_receive(:check_nginx_binary).and_return(false)
333
- @installer.should_receive(:check_dependencies).and_return(true)
334
- @installer.should_receive(:compile_support_binaries)
335
- @installer.should_receive(:compile_nginx)
336
- @installer.run
330
+ @installer.should_receive(:check_for_download_tool)
331
+ @installer.should_receive(:check_support_binaries).and_return(false)
332
+ @installer.should_receive(:check_nginx_binary).and_return(false)
333
+ @installer.should_receive(:check_dependencies).and_return(true)
334
+ @installer.should_receive(:compile_support_binaries)
335
+ @installer.should_receive(:compile_nginx)
336
+ @installer.run
337
337
 
338
- Dir["#{@temp_dir}/nginx/*"].should be_empty
339
- Dir["#{@temp_dir}/support/*"].should be_empty
338
+ Dir["#{@temp_dir}/nginx/*"].should be_empty
339
+ Dir["#{@temp_dir}/support/*"].should be_empty
340
340
  end
341
341
 
342
342
  it "aborts if the Nginx source tarball cannot be extracted" do