passenger 5.0.6 → 5.0.7

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 (74) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/CHANGELOG +26 -0
  5. data/Rakefile +0 -1
  6. data/bin/passenger-install-apache2-module +46 -12
  7. data/bin/passenger-status +6 -3
  8. data/build/packaging.rb +9 -1
  9. data/dev/ci/run_travis.sh +0 -36
  10. data/doc/ServerOptimizationGuide.html +12 -11
  11. data/doc/ServerOptimizationGuide.txt.md +12 -11
  12. data/doc/Users guide Apache.html +81 -75
  13. data/doc/Users guide Apache.idmap.txt +15 -13
  14. data/doc/Users guide Apache.txt +9 -1
  15. data/doc/Users guide Nginx.html +81 -76
  16. data/doc/Users guide Nginx.idmap.txt +15 -13
  17. data/doc/Users guide Nginx.txt +8 -0
  18. data/doc/Users guide Standalone.html +183 -24
  19. data/doc/Users guide Standalone.idmap.txt +19 -11
  20. data/doc/Users guide Standalone.txt +4 -0
  21. data/doc/users_guide_snippets/environment_variables.txt +2 -1
  22. data/doc/users_guide_snippets/installation.txt +15 -2
  23. data/doc/users_guide_snippets/tips.txt +19 -31
  24. data/doc/users_guide_snippets/under_the_hood/relationship_with_ruby.txt +7 -0
  25. data/ext/apache2/ConfigurationCommands.cpp +7 -0
  26. data/ext/apache2/ConfigurationFields.hpp +2 -0
  27. data/ext/apache2/ConfigurationSetters.cpp +8 -0
  28. data/ext/apache2/CreateDirConfig.cpp +1 -0
  29. data/ext/apache2/MergeDirConfig.cpp +7 -0
  30. data/ext/apache2/SetHeaders.cpp +5 -0
  31. data/ext/common/ApplicationPool2/Options.h +9 -0
  32. data/ext/common/Constants.h +3 -1
  33. data/ext/common/Logging.cpp +2 -2
  34. data/ext/common/ServerKit/HttpHeaderParser.h +13 -1
  35. data/ext/common/ServerKit/Implementation.cpp +7 -1
  36. data/ext/common/agents/Base.cpp +1 -1
  37. data/ext/common/agents/HelperAgent/OptionParser.h +15 -0
  38. data/ext/common/agents/HelperAgent/RequestHandler.h +3 -1
  39. data/ext/common/agents/HelperAgent/RequestHandler/BufferBody.cpp +3 -3
  40. data/ext/common/agents/HelperAgent/RequestHandler/InitRequest.cpp +12 -1
  41. data/ext/common/agents/HelperAgent/RequestHandler/Utils.cpp +7 -3
  42. data/ext/common/agents/HelperAgent/ResponseCache.h +7 -1
  43. data/ext/common/agents/LoggingAgent/Main.cpp +4 -1
  44. data/ext/nginx/CacheLocationConfig.c +20 -0
  45. data/ext/nginx/Configuration.c +7 -0
  46. data/ext/nginx/ConfigurationCommands.c +10 -0
  47. data/ext/nginx/ConfigurationFields.h +2 -0
  48. data/ext/nginx/ContentHandler.c +10 -0
  49. data/ext/nginx/CreateLocationConfig.c +5 -0
  50. data/ext/nginx/MergeLocationConfig.c +6 -0
  51. data/helper-scripts/meteor-loader.rb +15 -2
  52. data/helper-scripts/rack-loader.rb +2 -6
  53. data/helper-scripts/rack-preloader.rb +1 -5
  54. data/lib/phusion_passenger.rb +3 -3
  55. data/lib/phusion_passenger/apache2/config_options.rb +5 -0
  56. data/lib/phusion_passenger/config/command.rb +9 -0
  57. data/lib/phusion_passenger/config/install_standalone_runtime_command.rb +4 -0
  58. data/lib/phusion_passenger/config/validate_install_command.rb +478 -46
  59. data/lib/phusion_passenger/constants.rb +1 -0
  60. data/lib/phusion_passenger/loader_shared_helpers.rb +26 -3
  61. data/lib/phusion_passenger/nginx/config_options.rb +4 -0
  62. data/lib/phusion_passenger/packaging.rb +0 -8
  63. data/lib/phusion_passenger/platform_info/apache.rb +40 -28
  64. data/lib/phusion_passenger/platform_info/apache_detector.rb +29 -3
  65. data/lib/phusion_passenger/rack/thread_handler_extension.rb +12 -7
  66. data/lib/phusion_passenger/request_handler/thread_handler.rb +5 -0
  67. data/lib/phusion_passenger/standalone/start_command.rb +46 -5
  68. data/lib/phusion_passenger/standalone/start_command/builtin_engine.rb +5 -3
  69. data/resources/templates/apache2/config_snippets.txt.erb +1 -1
  70. data/resources/templates/apache2/run_installer_as_root_for_apache_analysis.txt.erb +9 -0
  71. data/resources/templates/standalone/config.erb +16 -1
  72. metadata +3 -3
  73. metadata.gz.asc +7 -7
  74. data/build/debian.rb +0 -213
@@ -192,6 +192,10 @@ initializePrivilegedWorkingObjects() {
192
192
  foreach (description, authorizations) {
193
193
  parseAndAddAdminAuthorization(description);
194
194
  }
195
+
196
+ // Initialize ResourceLocator here in case passenger_root's parent
197
+ // directory is not executable by the unprivileged user.
198
+ wo->resourceLocator = new ResourceLocator(options.get("passenger_root"));
195
199
  }
196
200
 
197
201
  static void
@@ -280,7 +284,6 @@ initializeUnprivilegedWorkingObjects() {
280
284
  WorkingObjects *wo = workingObjects;
281
285
  int fd;
282
286
 
283
- wo->resourceLocator = new ResourceLocator(options.get("passenger_root"));
284
287
  options.set("union_station_gateway_cert", findUnionStationGatewayCert(
285
288
  *wo->resourceLocator, options.get("union_station_gateway_cert", false)));
286
289
 
@@ -68,6 +68,14 @@ u_char int_buf[32], *end, *buf, *pos;
68
68
 
69
69
 
70
70
 
71
+ if (conf->meteor_app_settings.data != NULL) {
72
+ len += sizeof("!~PASSENGER_METEOR_APP_SETTINGS: ") - 1;
73
+ len += conf->meteor_app_settings.len;
74
+ len += sizeof("\r\n") - 1;
75
+ }
76
+
77
+
78
+
71
79
  if (conf->environment.data != NULL) {
72
80
  len += sizeof("!~PASSENGER_APP_ENV: ") - 1;
73
81
  len += conf->environment.len;
@@ -337,6 +345,18 @@ if (buf == NULL) {
337
345
 
338
346
 
339
347
 
348
+ if (conf->meteor_app_settings.data != NULL) {
349
+ pos = ngx_copy(pos,
350
+ "!~PASSENGER_METEOR_APP_SETTINGS: ",
351
+ sizeof("!~PASSENGER_METEOR_APP_SETTINGS: ") - 1);
352
+ pos = ngx_copy(pos,
353
+ conf->meteor_app_settings.data,
354
+ conf->meteor_app_settings.len);
355
+ pos = ngx_copy(pos, (const u_char *) "\r\n", sizeof("\r\n") - 1);
356
+ }
357
+
358
+
359
+
340
360
  if (conf->environment.data != NULL) {
341
361
  pos = ngx_copy(pos,
342
362
  "!~PASSENGER_APP_ENV: ",
@@ -1397,6 +1397,13 @@ const ngx_command_t passenger_commands[] = {
1397
1397
  offsetof(passenger_main_conf_t, analytics_log_group),
1398
1398
  NULL },
1399
1399
 
1400
+ { ngx_string("passenger_read_timeout"),
1401
+ NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1,
1402
+ ngx_conf_set_msec_slot,
1403
+ NGX_HTTP_LOC_CONF_OFFSET,
1404
+ offsetof(passenger_loc_conf_t, upstream_config.read_timeout),
1405
+ NULL },
1406
+
1400
1407
  { ngx_string("union_station_gateway_address"),
1401
1408
  NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
1402
1409
  ngx_conf_set_str_slot,
@@ -79,6 +79,16 @@
79
79
  NULL
80
80
  },
81
81
 
82
+ {
83
+
84
+ ngx_string("passenger_meteor_app_settings"),
85
+ NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LIF_CONF | NGX_CONF_TAKE1,
86
+ ngx_conf_set_str_slot,
87
+ NGX_HTTP_LOC_CONF_OFFSET,
88
+ offsetof(passenger_loc_conf_t, meteor_app_settings),
89
+ NULL
90
+ },
91
+
82
92
  {
83
93
 
84
94
  ngx_string("passenger_app_env"),
@@ -91,6 +91,8 @@
91
91
 
92
92
  ngx_str_t group;
93
93
 
94
+ ngx_str_t meteor_app_settings;
95
+
94
96
  ngx_str_t nodejs;
95
97
 
96
98
  ngx_str_t python;
@@ -138,6 +138,16 @@ map_uri_to_page_cache_file(ngx_http_request_t *r, ngx_str_t *public_dir,
138
138
  }
139
139
  end = ngx_copy(end, "index.html", sizeof("index.html"));
140
140
 
141
+ } else if (filename[filename_len - 1] == '/') {
142
+ /* if the filename ends with '/' check for filename + "index.html". */
143
+
144
+ if (filename_len + sizeof("index.html") > page_cache_file->len) {
145
+ /* Page cache filename doesn't fit in the buffer. */
146
+ return 0;
147
+ }
148
+
149
+ end = ngx_copy(page_cache_file->data, filename, filename_len);
150
+ end = ngx_copy(end, "index.html", sizeof("index.html"));
141
151
  } else {
142
152
  /* Otherwise, the page cache file is just filename + ".html". */
143
153
 
@@ -59,6 +59,11 @@
59
59
 
60
60
 
61
61
 
62
+ conf->meteor_app_settings.data = NULL;
63
+ conf->meteor_app_settings.len = 0;
64
+
65
+
66
+
62
67
  conf->environment.data = NULL;
63
68
  conf->environment.len = 0;
64
69
 
@@ -64,6 +64,12 @@
64
64
 
65
65
 
66
66
 
67
+ ngx_conf_merge_str_value(conf->meteor_app_settings,
68
+ prev->meteor_app_settings,
69
+ NULL);
70
+
71
+
72
+
67
73
  ngx_conf_merge_str_value(conf->environment,
68
74
  prev->environment,
69
75
  NULL);
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  # encoding: binary
3
3
  # Phusion Passenger - https://www.phusionpassenger.com/
4
- # Copyright (c) 2010-2014 Phusion
4
+ # Copyright (c) 2010-2015 Phusion
5
5
  #
6
6
  # "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
7
7
  #
@@ -110,7 +110,20 @@ module PhusionPassenger
110
110
  # Meteor its own process group, and sending signals to the
111
111
  # entire process group.
112
112
  Process.setpgrp
113
- exec("meteor run -p #{port} #{production}")
113
+
114
+ if options["environment"] == "production"
115
+ puts("Warning: meteor running in simulated production mode (--production). For real production use, bundle your app.")
116
+ end
117
+
118
+ if options["meteor_app_settings"]
119
+ PhusionPassenger.require_passenger_lib 'utils/shellwords'
120
+ app_settings_file = Shellwords.escape(options["meteor_app_settings"])
121
+ puts("Using application settings from file #{app_settings_file}")
122
+ exec("meteor run -p #{port} --settings #{app_settings_file} #{production}")
123
+ else
124
+ exec("meteor run -p #{port} #{production}")
125
+ end
126
+ exec("meteor run -p #{port} #{production} --settings settings.json")
114
127
  end
115
128
  $0 = options["process_title"] if options["process_title"]
116
129
  $0 = "#{$0} (#{pid})"
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  # encoding: binary
3
3
  # Phusion Passenger - https://www.phusionpassenger.com/
4
- # Copyright (c) 2013-2014 Phusion
4
+ # Copyright (c) 2013-2015 Phusion
5
5
  #
6
6
  # "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
7
7
  #
@@ -94,12 +94,8 @@ module PhusionPassenger
94
94
  LoaderSharedHelpers.before_loading_app_code_step1('config.ru', options)
95
95
  LoaderSharedHelpers.run_load_path_setup_code(options)
96
96
  LoaderSharedHelpers.before_loading_app_code_step2(options)
97
+ LoaderSharedHelpers.activate_gem 'rack'
97
98
 
98
- begin
99
- require 'rubygems'
100
- rescue LoadError
101
- end
102
- require 'rack'
103
99
  rackup_file = options["startup_file"] || "config.ru"
104
100
  rackup_code = ::File.open(rackup_file, 'rb') do |f|
105
101
  f.read
@@ -98,12 +98,8 @@ module PhusionPassenger
98
98
  LoaderSharedHelpers.before_loading_app_code_step1('config.ru', options)
99
99
  LoaderSharedHelpers.run_load_path_setup_code(options)
100
100
  LoaderSharedHelpers.before_loading_app_code_step2(options)
101
+ LoaderSharedHelpers.activate_gem 'rack'
101
102
 
102
- begin
103
- require 'rubygems'
104
- rescue LoadError
105
- end
106
- require 'rack'
107
103
  rackup_file = options["startup_file"] || "config.ru"
108
104
  rackup_code = ::File.open(rackup_file, 'rb') do |f|
109
105
  f.read
@@ -30,10 +30,10 @@ module PhusionPassenger
30
30
 
31
31
  PACKAGE_NAME = 'passenger'
32
32
  # Run 'rake ext/common/Constants.h' after changing this number.
33
- VERSION_STRING = '5.0.6'
33
+ VERSION_STRING = '5.0.7'
34
34
 
35
- PREFERRED_NGINX_VERSION = '1.6.2'
36
- NGINX_SHA256_CHECKSUM = 'b5608c2959d3e7ad09b20fc8f9e5bd4bc87b3bc8ba5936a513c04ed8f1391a18'
35
+ PREFERRED_NGINX_VERSION = '1.6.3'
36
+ NGINX_SHA256_CHECKSUM = '0a98e95b366e4d6042f331e1fa4d70e18fd1e49d8993e589008e70e742b7e757'
37
37
 
38
38
  PREFERRED_PCRE_VERSION = '8.34'
39
39
  PCRE_SHA256_CHECKSUM = '1dd78994c81e44ac41cf30b2a21d4b4cc6d76ccde7fc6e77713ed51d7bddca47'
@@ -69,6 +69,11 @@ APACHE2_DIRECTORY_CONFIGURATION_OPTIONS = [
69
69
  :type => :string,
70
70
  :desc => "The Node.js command to use."
71
71
  },
72
+ {
73
+ :name => "PassengerMeteorAppSettings",
74
+ :type => :string,
75
+ :desc => "Settings file for (non-bundled) Meteor apps."
76
+ },
72
77
  {
73
78
  :name => "PassengerAppEnv",
74
79
  :type => :string,
@@ -30,6 +30,15 @@ module PhusionPassenger
30
30
  @options = self.class.create_default_options
31
31
  end
32
32
 
33
+ def run_and_get_exit_code
34
+ begin
35
+ run
36
+ exit(0)
37
+ rescue SystemExit => e
38
+ e.status
39
+ end
40
+ end
41
+
33
42
  private
34
43
  def self.create_default_options
35
44
  return {}
@@ -214,6 +214,10 @@ module PhusionPassenger
214
214
  end
215
215
 
216
216
  def download_nginx_engine
217
+ if @options[:nginx_version] != PREFERRED_NGINX_VERSION
218
+ return false
219
+ end
220
+
217
221
  if @options[:brief]
218
222
  puts " --> Installing Nginx #{@options[:nginx_version]} engine"
219
223
  else
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
  # Phusion Passenger - https://www.phusionpassenger.com/
3
- # Copyright (c) 2014 Phusion
3
+ # Copyright (c) 2014-2015 Phusion
4
4
  #
5
5
  # "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  #
@@ -22,6 +22,7 @@
22
22
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
23
  # THE SOFTWARE.
24
24
 
25
+ require 'optparse'
25
26
  PhusionPassenger.require_passenger_lib 'constants'
26
27
  PhusionPassenger.require_passenger_lib 'config/command'
27
28
 
@@ -33,61 +34,174 @@ module PhusionPassenger
33
34
  FAIL_EXIT_CODE = 1
34
35
  # Signifies that there are no error, but at least 1 warning.
35
36
  WARN_EXIT_CODE = 2
37
+ # Internal error occurred.
38
+ INTERNAL_ERROR_CODE = 9
36
39
 
37
- def self.help
38
- puts "Usage: passenger-config validate-install"
39
- puts "Validate this #{PROGRAM_NAME} installation."
40
- puts
41
- puts "Exit codes:"
42
- puts " 0 - All checks passed. No errors, no warnings."
43
- puts " #{FAIL_EXIT_CODE} - There are some errors."
44
- puts " #{WARN_EXIT_CODE} - There are no errors, but there are some warnings."
40
+ def run
41
+ @orig_argv = @argv.dup
42
+ parse_options
43
+ prepare
44
+ begin
45
+ if !@options[:auto]
46
+ ask_what_to_validate
47
+ if @options[:validate_apache2]
48
+ initialize_apache_envvars
49
+ check_whether_there_are_multiple_apache_installs
50
+ end
51
+ elsif @options[:validate_apache2]
52
+ initialize_apache_envvars
53
+ end
54
+
55
+ if @options[:validate_passenger]
56
+ check_tools_in_path
57
+ check_no_other_installs_in_path
58
+ end
59
+ if @options[:validate_apache2]
60
+ check_apache2_load_module_config
61
+ end
62
+
63
+ if @options[:summary]
64
+ summarize
65
+ end
66
+ exit(FAIL_EXIT_CODE) if @error_count > 0
67
+ exit(WARN_EXIT_CODE) if @warning_count > 0
68
+ ensure
69
+ reset_terminal
70
+ end
45
71
  end
46
72
 
47
- def run
48
- if @argv[0] == '--help'
49
- self.class.help
50
- exit
51
- elsif @argv.size > 0
52
- self.class.help
53
- exit 1
73
+ private
74
+ def self.create_default_options
75
+ return {
76
+ :auto => !STDIN.tty?,
77
+ :validate_passenger => true,
78
+ :colors => STDOUT.tty?,
79
+ :summary => true
80
+ }
81
+ end
82
+
83
+ def self.create_option_parser(options)
84
+ OptionParser.new do |opts|
85
+ nl = "\n" + ' ' * 37
86
+ opts.banner = "Usage: passenger-config validate-install [OPTIONS]\n"
87
+ opts.separator ""
88
+ opts.separator " Validate this #{SHORT_PROGRAM_NAME} installation and/or its integration with web servers."
89
+ opts.separator " If you run this command in a terminal, it will run interactively and ask you questions."
90
+ opts.separator " You can run this command non-interactively either by running it without a terminal, "
91
+ opts.separator " or by passing --auto."
92
+ opts.separator ""
93
+ opts.separator " When running non-interactively, the default is to validate the #{SHORT_PROGRAM_NAME}"
94
+ opts.separator " installation only (so e.g. Apache is not validated). You can customize this"
95
+ opts.separator " using the appropriate command line options."
96
+ opts.separator ""
97
+ opts.separator " The exit codes are as follows:"
98
+ opts.separator " 0 - All checks passed. No errors, no warnings."
99
+ opts.separator " #{FAIL_EXIT_CODE} - Some checks failed with an error."
100
+ opts.separator " #{WARN_EXIT_CODE} - No checks failed with an error, but some failed produced warnings."
101
+ opts.separator " #{INTERNAL_ERROR_CODE} - Some internal error occurred."
102
+ opts.separator ""
103
+
104
+ opts.separator "Options:"
105
+ opts.on("--auto", "Run non-interactively") do
106
+ options[:auto] = true
107
+ end
108
+ opts.on("--no-validate-passenger", "Do not validate the #{SHORT_PROGRAM_NAME} installation#{nl}" +
109
+ "itself") do
110
+ options[:validate_passenger] = false
111
+ end
112
+ opts.on("--validate-apache2", "Validate Apache 2 integration") do
113
+ options[:validate_apache2] = true
114
+ end
115
+ opts.on("--apxs2-path=PATH", String, "Apache installation to validate") do |val|
116
+ ENV['APXS2'] = val
117
+ end
118
+ opts.separator ""
119
+ opts.on("--no-colors", "Never output colors") do
120
+ options[:colors] = false
121
+ end
122
+ opts.on("--no-summary", "Do not display a summary") do
123
+ options[:summary] = false
124
+ end
125
+ opts.separator ""
126
+ opts.on("-h", "--help", "Show this help") do
127
+ options[:help] = true
128
+ end
129
+
130
+ opts.separator ""
131
+ opts.separator "Internal options:"
132
+ opts.on("--invoked-from-installer", "Indicate that this program is invoked from#{nl}" +
133
+ "passenger-install-apache2-module") do
134
+ options[:invoked_from_installer] = true
135
+ end
54
136
  end
137
+ end
55
138
 
139
+ def prepare
56
140
  begin
57
141
  require 'rubygems'
58
142
  rescue LoadError
59
143
  end
60
144
  PhusionPassenger.require_passenger_lib 'utils/ansi_colors'
145
+ PhusionPassenger.require_passenger_lib 'utils/terminal_choice_menu'
61
146
  PhusionPassenger.require_passenger_lib 'platform_info'
147
+ PhusionPassenger.require_passenger_lib 'platform_info/ruby'
148
+ PhusionPassenger.require_passenger_lib 'platform_info/apache'
149
+ PhusionPassenger.require_passenger_lib 'platform_info/apache_detector'
150
+ require 'stringio'
151
+ require 'pathname'
62
152
 
63
153
  @error_count = 0
64
154
  @warning_count = 0
65
155
 
66
- prepare_terminal
67
- begin
68
- check_tools_in_path
69
- check_no_other_installs_in_path
156
+ @colors = Utils::AnsiColors.new(@options[:colors])
70
157
 
71
- exit(FAIL_EXIT_CODE) if @error_count > 0
72
- exit(WARN_EXIT_CODE) if @warning_count > 0
73
- ensure
74
- reset_terminal
75
- end
158
+ prepare_terminal
76
159
  end
77
160
 
78
- private
79
161
  def prepare_terminal
80
- STDOUT.write(Utils::AnsiColors::DEFAULT_TERMINAL_COLOR)
162
+ STDOUT.write(@colors.default_terminal_color)
81
163
  STDOUT.flush
82
164
  end
83
165
 
84
166
  def reset_terminal
85
- STDOUT.write(Utils::AnsiColors::RESET)
167
+ STDOUT.write(@colors.reset)
86
168
  STDOUT.flush
87
169
  end
88
170
 
171
+ def ask_what_to_validate
172
+ log "<banner>What would you like to validate?</banner>"
173
+ log "Use <space> to select."
174
+ log "<dgray>If the menu doesn't display correctly, press '!'</dgray>"
175
+ puts
176
+
177
+ menu = Utils::TerminalChoiceMenu.new([
178
+ "#{SHORT_PROGRAM_NAME} itself",
179
+ "Apache"
180
+ ])
181
+ menu["#{SHORT_PROGRAM_NAME} itself"].checked = @options[:validate_passenger]
182
+ menu["Apache"].checked = @options[:validate_apache2]
183
+
184
+ begin
185
+ menu.query
186
+ rescue Interrupt
187
+ exit(INTERNAL_ERROR_CODE)
188
+ end
189
+ display_separator
190
+
191
+ @options[:validate_passenger] = menu.selected_choices.include?("#{SHORT_PROGRAM_NAME} itself")
192
+ @options[:validate_apache2] = menu.selected_choices.include?("Apache")
193
+ end
194
+
195
+ def initialize_apache_envvars
196
+ # The Apache executable may be located in an 'sbin' folder. We add
197
+ # the 'sbin' folders to $PATH just in case. On some systems
198
+ # 'sbin' isn't in $PATH unless the user is logged in as root from
199
+ # the start (i.e. not via 'su' or 'sudo').
200
+ ENV["PATH"] += ":/usr/sbin:/sbin:/usr/local/sbin"
201
+ end
202
+
89
203
  def check_tools_in_path
90
- checking "whether this #{PROGRAM_NAME} install is in PATH"
204
+ checking "whether this #{SHORT_PROGRAM_NAME} install is in PATH"
91
205
  paths = ENV['PATH'].to_s.split(':')
92
206
  if paths.include?(gem_bindir) ||
93
207
  paths.include?(homebrew_bindir) ||
@@ -98,7 +212,7 @@ module PhusionPassenger
98
212
  suggest %Q{
99
213
  Please add #{PhusionPassenger.bin_dir} to PATH.
100
214
  Otherwise you will get "command not found" errors upon running
101
- passenger-status and other tools.
215
+ any Passenger commands.
102
216
 
103
217
  Learn more at about PATH at:
104
218
 
@@ -108,7 +222,7 @@ module PhusionPassenger
108
222
  end
109
223
 
110
224
  def check_no_other_installs_in_path
111
- logn " * Checking whether there are no other #{PROGRAM_NAME} installations... "
225
+ checking "whether there are no other #{SHORT_PROGRAM_NAME} installations"
112
226
 
113
227
  paths = ENV['PATH'].to_s.split(':')
114
228
  if Process.uid == 0 &&
@@ -132,7 +246,7 @@ module PhusionPassenger
132
246
 
133
247
  other_installs = []
134
248
  paths.each do |path|
135
- filename = "#{path}/passenger-config"
249
+ filename = "#{path}/passenger"
136
250
  if File.exist?(filename)
137
251
  other_installs << filename
138
252
  end
@@ -142,16 +256,282 @@ module PhusionPassenger
142
256
  else
143
257
  check_warning
144
258
  suggest %Q{
145
- Besides this #{PROGRAM_NAME} installation, the following other
146
- #{PROGRAM_NAME} installations have been detected:
259
+ You are currently validating against #{PROGRAM_NAME} #{VERSION_STRING}, located in:
147
260
 
148
- #{other_installs.join("\n\t\t\t\t ")}
261
+ #{PhusionPassenger.bin_dir}/passenger
149
262
 
150
- Please uninstall them to avoid confusion or conflicts.
263
+ Besides this #{SHORT_PROGRAM_NAME} installation, the following other
264
+ #{SHORT_PROGRAM_NAME} installations have also been detected:
265
+
266
+ #{other_installs.join("\n ")}
267
+
268
+ Please uninstall these other #{SHORT_PROGRAM_NAME} installations to avoid
269
+ confusion or conflicts.
151
270
  }
152
271
  end
153
272
  end
154
273
 
274
+ def check_whether_there_are_multiple_apache_installs
275
+ log '<banner>Checking whether there are multiple Apache installations...</banner>'
276
+
277
+ output = StringIO.new
278
+ detector = PlatformInfo::ApacheDetector.new(output)
279
+ begin
280
+ detector.detect_all
281
+ detector.report
282
+ apache2 = detector.result_for(PlatformInfo.apxs2)
283
+
284
+ if apache2.nil?
285
+ # Print an extra newline because the autodetection routines
286
+ # may have run some commands which printed stuff to stderr.
287
+ puts
288
+
289
+ if Process.uid == 0
290
+ # More information will be displayed in #check_no_duplicate_apache2_load_module_config,
291
+ # which should also fail.
292
+ log "<red>Your Apache installation appears to be broken. More information will be displayed later.</red>"
293
+ else
294
+ whoami = `whoami`.strip
295
+ sudo = PhusionPassenger::PlatformInfo.ruby_sudo_command
296
+ selfcommand = "#{PhusionPassenger.bin_dir}/passenger-config validate-install #{@orig_argv.join(' ')}"
297
+
298
+ log "<red>Permission problems</red>"
299
+ log "This program must be able to analyze your Apache installation. But it can't"
300
+ log "do that, because you're running the installer as <b>#{whoami}</b>."
301
+ log "Please give this program root privileges, by re-running it with <yellow>#{sudo}</yellow>:"
302
+ log ""
303
+ log " <b>export ORIG_PATH=\"$PATH\"</b>"
304
+ log " <b>#{sudo_s_e}</b>"
305
+ log " <b>export PATH=\"$ORIG_PATH\"</b>"
306
+ log " <b>#{ruby_command} #{selfcommand}</b>"
307
+ exit(INTERNAL_ERROR_CODE)
308
+ end
309
+ elsif detector.results.size > 1
310
+ other_installs = detector.results - [apache2]
311
+
312
+ log "<yellow>Multiple Apache installations detected!</yellow>"
313
+ log ""
314
+ log "You are about to validate #{SHORT_PROGRAM_NAME} against the following"
315
+ log "Apache installation:"
316
+ log ""
317
+ log " <b>Apache #{apache2.version}</b>"
318
+ log " <b>apxs2 : #{apache2.apxs2}</b>"
319
+ log " <b>Executable: #{apache2.httpd}</b>"
320
+ log ""
321
+ log "However, #{other_installs.size} other Apache installation(s) have been found on your system:"
322
+ log ""
323
+ other_installs.each do |result|
324
+ log " <b>Apache #{result.version}</b>"
325
+ log " <b>apxs2 : #{result.apxs2}</b>"
326
+ log " <b>Executable: #{result.httpd}</b>"
327
+ log ""
328
+ end
329
+
330
+ result = prompt_confirmation "Are you sure you want to validate " +
331
+ "against Apache #{apache2.version} (#{apache2.apxs2})?"
332
+ if !result
333
+ puts
334
+ display_separator
335
+ other_installs.each do |result|
336
+ log " * To validate against <yellow>Apache #{result.version} (#{result.apxs2})</yellow>:"
337
+ log " Re-run this program with: <b>--apxs2-path '#{result.apxs2}'</b>"
338
+ end
339
+ log ""
340
+ log "You may also want to read the \"Installation\" section of the manual for"
341
+ log "installation troubleshooting:"
342
+ log ""
343
+ log " #{APACHE2_DOC_URL}"
344
+ log ""
345
+ log "If you keep having problems installing, please visit the following website for"
346
+ log "support:"
347
+ log ""
348
+ log " #{SUPPORT_URL}"
349
+ exit(INTERNAL_ERROR_CODE)
350
+ end
351
+ else
352
+ log '<green>Only a single installation detected. This is good.</green>'
353
+ end
354
+
355
+ display_separator
356
+ ensure
357
+ detector.finish
358
+ end
359
+ end
360
+
361
+ def check_apache2_load_module_config
362
+ checking "whether the Passenger module is correctly configured in Apache"
363
+
364
+ if PlatformInfo.httpd_default_config_file.nil?
365
+ check_error
366
+ passenger_config = "#{PhusionPassenger.bin_dir}/passenger-config"
367
+ suggest %Q{
368
+ Your Apache installation might be broken
369
+
370
+ You are about to validate #{PROGRAM_NAME} against the following
371
+ Apache installation:
372
+
373
+ apxs2: #{PlatformInfo.apxs2}
374
+
375
+ However, this Apache installation appears to be broken, so this program
376
+ cannot continue. To find out why this program thinks the above Apache
377
+ installation is broken, run:
378
+
379
+ export ORIG_PATH="$PATH"
380
+ #{sudo_s_e}
381
+ export PATH="$ORIG_PATH"
382
+ #{ruby_command} #{passenger_config} --detect-apache2
383
+ }
384
+ return
385
+ end
386
+
387
+ result = PlatformInfo.httpd_included_config_files(
388
+ PlatformInfo.httpd_default_config_file)
389
+ if !result[:unreadable_files].empty?
390
+ check_error
391
+
392
+ if Process.uid == 0
393
+ suggest %Q{
394
+ Permission problems
395
+
396
+ This program must be able to analyze your Apache installation. But it can't
397
+ do that despite running with root privileges. In particular, it failed to
398
+ read the following files:
399
+
400
+ #{result[:unreadable_files].join("\n ")}
401
+
402
+ This program doesn't know why this error occurred. Your system is probably
403
+ secured using some mechanism that this program is not familiar with. Please
404
+ consult your operating system's manual to learn which security mechanisms
405
+ may be preventing this program from accessing the above files. On Linux
406
+ systems, SELinux and AppArmor might be responsible.
407
+
408
+ When you've solved the problem, please re-run this program.
409
+ }
410
+ else
411
+ whoami = `whoami`.strip
412
+ sudo = PhusionPassenger::PlatformInfo.ruby_sudo_command
413
+ selfcommand = "#{PhusionPassenger.bin_dir}/passenger-config validate-install #{@orig_argv.join(' ')}"
414
+
415
+ suggest %Q{
416
+ Permission problems
417
+
418
+ This program must be able to analyze your Apache installation. But it can't
419
+ do that, because you're running the installer as '#{whoami}'. In particular,
420
+ it failed to read the following files:
421
+
422
+ #{result[:unreadable_files].join("\n ")}
423
+
424
+ Please give this program root privileges, by re-running it with '#{sudo}':
425
+
426
+ export ORIG_PATH=\"$PATH\"
427
+ #{sudo_s_e}
428
+ export PATH=\"$ORIG_PATH\"
429
+ #{ruby_command} #{selfcommand}
430
+ }
431
+ end
432
+ return
433
+ end
434
+
435
+ occurrences = 0
436
+ occurrence_files = []
437
+ module_path = nil
438
+
439
+ result[:files].each do |path|
440
+ lines = File.open(path, "rb") do |f|
441
+ f.read.split("\n")
442
+ end
443
+ lines.each do |line|
444
+ if line !~ /^[\s\t]*#/ && line =~ /LoadModule[\s\t]+passenger_module[\s\t]+(.*)/
445
+ module_path = $1
446
+ occurrences += 1
447
+ occurrence_files << path
448
+ end
449
+ end
450
+ end
451
+
452
+ if occurrences == 1
453
+ if module_path !~ /^\//
454
+ # Non-absolute path. Absolutize using ServerRoot.
455
+ module_path = "#{PlatformInfo.httpd_default_root}/#{module_path}"
456
+ end
457
+ # Resolve symlinks.
458
+ module_path = Pathname.new(module_path).realpath
459
+ expected_module_path = Pathname.new(PhusionPassenger.apache2_module_path).realpath
460
+
461
+ if module_path == expected_module_path
462
+ check_ok
463
+ else
464
+ check_error
465
+ suggest %Q{
466
+ Incorrect #{SHORT_PROGRAM_NAME} module path detected
467
+
468
+ #{PROGRAM_NAME} for Apache requires a 'LoadModule passenger_module'
469
+ directive inside an Apache configuration file. This directive has been
470
+ detected in the following config file:
471
+
472
+ #{occurrence_files[0]}
473
+
474
+ However, the directive refers to the following Apache module, which is wrong:
475
+
476
+ #{module_path}
477
+
478
+ Please edit the config file and change the directive to this instead:
479
+
480
+ LoadModule passenger_module #{PhusionPassenger.apache2_module_path}
481
+ }
482
+ end
483
+ elsif occurrences == 0
484
+ if @options[:invoked_from_installer]
485
+ check_warning
486
+ suggest %Q{
487
+ You did not specify 'LoadModule passenger_module' in any of your Apache
488
+ configuration files. Please paste the configuration snippet that this
489
+ installer printed earlier, into one of your Apache configuration files, such
490
+ as #{PlatformInfo.httpd_default_config_file}.
491
+ }
492
+ else
493
+ check_error
494
+ installer_command = "#{PhusionPassenger.bin_dir}/passenger-install-apache2-module"
495
+ suggest %Q{
496
+ You did not specify 'LoadModule passenger_module' in any of your
497
+ Apache configuration files. This means that #{PROGRAM_NAME}
498
+ for Apache is not installed or not active. Please run the
499
+ #{PROGRAM_NAME} Apache module installer:
500
+
501
+ #{ruby_command} #{installer_command} --apxs2=#{PlatformInfo.apxs2}
502
+ }
503
+ end
504
+ else
505
+ check_error
506
+
507
+ suggest %Q{
508
+ You have #{occurrences} 'LoadModule passenger_module' directives in your Apache
509
+ configuration files. However, you are only supposed to have one such
510
+ directive.
511
+
512
+ Please fix this by removing all 'LoadModule passenger_module' directives
513
+ besides the one for #{SHORT_PROGRAM_NAME} version #{VERSION_STRING}. The directives were
514
+ found in these files:
515
+
516
+ #{occurrence_files.uniq.join("\n ")}
517
+
518
+ Note: 'LoadModule passenger_module' may be placed inside the global context
519
+ only (so not within a VirtualHost).
520
+ }
521
+ end
522
+ end
523
+
524
+ def summarize
525
+ puts
526
+ if @error_count == 0 && @warning_count == 0
527
+ log "<green>Everything looks good. :-)</green>"
528
+ elsif @error_count == 0
529
+ log "<yellow>Detected 0 error(s), #{@warning_count} warning(s).</yellow>"
530
+ else
531
+ log "<red>Detected #{@error_count} error(s), #{@warning_count} warning(s).</red>"
532
+ end
533
+ end
534
+
155
535
  # Returns the RubyGems bin dir, if Phusion Passenger is installed through RubyGems.
156
536
  def gem_bindir
157
537
  if defined?(Gem) &&
@@ -174,20 +554,18 @@ module PhusionPassenger
174
554
  end
175
555
 
176
556
  def logn(message)
177
- if STDOUT.tty?
178
- STDOUT.write(Utils::AnsiColors.ansi_colorize(message))
179
- else
180
- STDOUT.write(Utils::AnsiColors.strip_color_tags(message))
181
- end
557
+ STDOUT.write(@colors.ansi_colorize(message))
182
558
  STDOUT.flush
183
559
  end
184
560
 
185
561
  def log(message)
186
- if STDOUT.tty?
187
- STDOUT.puts(Utils::AnsiColors.ansi_colorize(message))
188
- else
189
- STDOUT.puts(Utils::AnsiColors.strip_color_tags(message))
190
- end
562
+ STDOUT.puts(@colors.ansi_colorize(message))
563
+ end
564
+
565
+ def display_separator
566
+ puts
567
+ puts "-------------------------------------------------------------------------"
568
+ puts
191
569
  end
192
570
 
193
571
  def checking(message)
@@ -214,6 +592,52 @@ module PhusionPassenger
214
592
  puts
215
593
  end
216
594
 
595
+ def prompt_confirmation(message)
596
+ result = prompt("#{message} [y/n]") do |value|
597
+ if value.downcase == 'y' || value.downcase == 'n'
598
+ true
599
+ else
600
+ log "<red>Invalid input '#{value}'; please enter either 'y' or 'n'.</red>"
601
+ false
602
+ end
603
+ end
604
+ result.downcase == 'y'
605
+ rescue Interrupt
606
+ exit(INTERNAL_ERROR_CODE)
607
+ end
608
+
609
+ def prompt(message, default_value = nil)
610
+ done = false
611
+ while !done
612
+ logn "#{message}: "
613
+
614
+ if default_value
615
+ puts default_value
616
+ return default_value
617
+ end
618
+
619
+ begin
620
+ result = STDIN.readline
621
+ rescue EOFError
622
+ exit(INTERNAL_ERROR_CODE)
623
+ end
624
+ result.strip!
625
+ if result.empty?
626
+ if default_value
627
+ result = default_value
628
+ done = true
629
+ else
630
+ done = !block_given? || yield(result)
631
+ end
632
+ else
633
+ done = !block_given? || yield(result)
634
+ end
635
+ end
636
+ result
637
+ rescue Interrupt
638
+ exit(INTERNAL_ERROR_CODE)
639
+ end
640
+
217
641
  def unindent(text)
218
642
  return PlatformInfo.send(:unindent, text)
219
643
  end
@@ -221,6 +645,14 @@ module PhusionPassenger
221
645
  def reindent(text, level)
222
646
  return PlatformInfo.send(:reindent, text, level)
223
647
  end
648
+
649
+ def sudo_s_e
650
+ PlatformInfo.ruby_sudo_shell_command("-E")
651
+ end
652
+
653
+ def ruby_command
654
+ PlatformInfo.ruby_command
655
+ end
224
656
  end
225
657
 
226
658
  end # module Config