passenger 4.0.37 → 4.0.38

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.

data/ext/common/Utils.h CHANGED
@@ -65,8 +65,6 @@ typedef enum {
65
65
  FT_REGULAR,
66
66
  /** A directory. */
67
67
  FT_DIRECTORY,
68
- /** A symlink. Only returned by getFileTypeNoFollowSymlinks(), not by getFileType(). */
69
- FT_SYMLINK,
70
68
  /** Something else, e.g. a pipe or a socket. */
71
69
  FT_OTHER
72
70
  } FileType;
@@ -123,10 +121,6 @@ bool fileExists(const StaticString &filename, CachedFileStat *cstat = 0,
123
121
  */
124
122
  FileType getFileType(const StaticString &filename, CachedFileStat *cstat = 0,
125
123
  unsigned int throttleRate = 0);
126
- /**
127
- * Like getFileType(), but does not follow symlinks.
128
- */
129
- FileType getFileTypeNoFollowSymlinks(const StaticString &filename);
130
124
 
131
125
  /**
132
126
  * Create the given file with the given contents, permissions and ownership.
@@ -450,14 +450,19 @@ public:
450
450
  if (pidsArg[pidsArg.size() - 1] == ',') {
451
451
  pidsArg.resize(pidsArg.size() - 1);
452
452
  }
453
+
454
+ // The list of format arguments must also follow -o
455
+ // without a space.
456
+ // https://github.com/phusion/passenger/pull/94
457
+ string fmtArg = "-o";
458
+ #if defined(sun) || defined(__sun)
459
+ fmtArg.append("pid,ppid,pcpu,rss,vsz,pgid,uid,args");
460
+ #else
461
+ fmtArg.append("pid,ppid,%cpu,rss,vsize,pgid,uid,command");
462
+ #endif
453
463
 
454
464
  const char *command[] = {
455
- "ps", "-o",
456
- #if defined(sun) || defined(__sun)
457
- "pid,ppid,pcpu,rss,vsz,pgid,uid,args",
458
- #else
459
- "pid,ppid,%cpu,rss,vsize,pgid,uid,command",
460
- #endif
465
+ "ps", fmtArg.c_str(),
461
466
  #ifdef PS_SUPPORTS_MULTIPLE_PIDS
462
467
  pidsArg.c_str(),
463
468
  #endif
@@ -469,6 +474,7 @@ public:
469
474
  psOutput = runCommandAndCaptureOutput(command);
470
475
  }
471
476
  pidsArg.resize(0);
477
+ fmtArg.resize(0);
472
478
  ProcessMetricMap result = parsePsOutput<Collection, ConstIterator>(psOutput, pids);
473
479
  psOutput.resize(0);
474
480
  if (canMeasureRealMemory) {
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * Copyright (C) Igor Sysoev
3
3
  * Copyright (C) 2007 Manlio Perillo (manlio.perillo@gmail.com)
4
- * Copyright (C) 2010-2013 Phusion
4
+ * Copyright (C) 2010-2014 Phusion
5
5
  *
6
6
  * Redistribution and use in source and binary forms, with or without
7
7
  * modification, are permitted provided that the following conditions
@@ -305,6 +305,21 @@ create_key(ngx_http_request_t *r)
305
305
 
306
306
  #endif
307
307
 
308
+ /**
309
+ * Checks whether the given header is "Transfer-Encoding".
310
+ * We do not pass Transfer-Encoding headers to the HelperAgent because
311
+ * Nginx always buffers the request body and always sets Content-Length
312
+ * in the request headers.
313
+ */
314
+ static int
315
+ header_is_transfer_encoding(ngx_str_t *key)
316
+ {
317
+ return key->len == sizeof("transfer-encoding") - 1 &&
318
+ ngx_tolower(key->data[0]) == (u_char) 't' &&
319
+ ngx_tolower(key->data[sizeof("transfer-encoding") - 2]) == (u_char) 'g' &&
320
+ ngx_strncasecmp(key->data + 1, (u_char *) "ransfer-encodin", sizeof("ransfer-encodin") - 1) == 0;
321
+ }
322
+
308
323
 
309
324
  static ngx_int_t
310
325
  create_request(ngx_http_request_t *r)
@@ -475,8 +490,10 @@ create_request(ngx_http_request_t *r)
475
490
  i = 0;
476
491
  }
477
492
 
478
- len += sizeof("HTTP_") - 1 + header[i].key.len + 1
479
- + header[i].value.len + 1;
493
+ if (!header_is_transfer_encoding(&header[i].key)) {
494
+ len += sizeof("HTTP_") - 1 + header[i].key.len + 1
495
+ + header[i].value.len + 1;
496
+ }
480
497
  }
481
498
  }
482
499
 
@@ -656,6 +673,10 @@ create_request(ngx_http_request_t *r)
656
673
  i = 0;
657
674
  }
658
675
 
676
+ if (header_is_transfer_encoding(&header[i].key)) {
677
+ continue;
678
+ }
679
+
659
680
  b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1);
660
681
 
661
682
  for (n = 0; n < header[i].key.len; n++) {
@@ -107,7 +107,7 @@ module App
107
107
  abort "Cannot find a suitable port to start Meteor on"
108
108
  end
109
109
 
110
- production = options["environment"] == "production" ? "production" : ""
110
+ production = options["environment"] == "production" ? "--production" : ""
111
111
  pid = fork do
112
112
  # Meteor is quite !@#$% here: if we kill its start script
113
113
  # with *any* signal, it'll leave a ton of garbage processes
@@ -109,6 +109,8 @@ class TCPPrespawnLocation < PrespawnLocation
109
109
 
110
110
  def connect
111
111
  TCPSocket.new('127.0.0.1', request_port)
112
+ rescue Errno::ECONNREFUSED
113
+ TCPSocket.new('::1', request_port)
112
114
  end
113
115
  end
114
116
 
@@ -191,7 +191,7 @@ class RequestHandler:
191
191
  env['wsgi.version'] = (1, 0)
192
192
  env['wsgi.multithread'] = False
193
193
  env['wsgi.multiprocess'] = True
194
- env['wsgi.run_once'] = True
194
+ env['wsgi.run_once'] = False
195
195
  if env.get('HTTPS','off') in ('on', '1', 'true', 'yes'):
196
196
  env['wsgi.url_scheme'] = 'https'
197
197
  else:
@@ -30,13 +30,13 @@ module PhusionPassenger
30
30
 
31
31
  PACKAGE_NAME = 'passenger'
32
32
  # Run 'rake ext/common/Constants.h' after changing this number.
33
- VERSION_STRING = '4.0.37'
33
+ VERSION_STRING = '4.0.38'
34
34
 
35
- PREFERRED_NGINX_VERSION = '1.4.4'
36
- NGINX_SHA256_CHECKSUM = '7c989a58e5408c9593da0bebcd0e4ffc3d892d1316ba5042ddb0be5b0b4102b9'
35
+ PREFERRED_NGINX_VERSION = '1.4.6'
36
+ NGINX_SHA256_CHECKSUM = '7a8b5b15d708b5b9c61e723bd93faa247b06c8b90babb76f612c128edb5812c6'
37
37
 
38
- PREFERRED_PCRE_VERSION = '8.32'
39
- PCRE_SHA256_CHECKSUM = 'd5d8634b36baf3d08be442a627001099583b397f456bc795304a013383b6423a'
38
+ PREFERRED_PCRE_VERSION = '8.34'
39
+ PCRE_SHA256_CHECKSUM = '1dd78994c81e44ac41cf30b2a21d4b4cc6d76ccde7fc6e77713ed51d7bddca47'
40
40
 
41
41
  STANDALONE_INTERFACE_VERSION = 1
42
42
 
@@ -59,6 +59,7 @@ class AbstractInstaller
59
59
  def initialize(options = {})
60
60
  @stdout = STDOUT
61
61
  @stderr = STDERR
62
+ @auto = !STDIN.tty?
62
63
  options.each_pair do |key, value|
63
64
  instance_variable_set(:"@#{key}", value)
64
65
  end
@@ -213,7 +213,6 @@ private
213
213
 
214
214
  STDERR.puts " --> Compiling #{library_name} for the current Ruby interpreter..."
215
215
  STDERR.puts " (set PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY=0 to disable)"
216
- STDERR.puts " -------------------------------"
217
216
 
218
217
  require 'fileutils'
219
218
  require 'shellwords'
@@ -268,9 +267,17 @@ private
268
267
  return PhusionPassenger::Utils::Download.download(url, filename, real_options)
269
268
  end
270
269
 
271
- def mkdir(dir)
270
+ def log(message, options = {})
271
+ if logger = options[:logger]
272
+ logger.puts(message)
273
+ else
274
+ STDERR.puts " #{message}"
275
+ end
276
+ end
277
+
278
+ def mkdir(dir, options = {})
272
279
  begin
273
- STDERR.puts " # mkdir -p #{dir}"
280
+ log("# mkdir -p #{dir}", options)
274
281
  FileUtils.mkdir_p(dir)
275
282
  rescue Errno::EEXIST
276
283
  end
@@ -282,39 +289,57 @@ private
282
289
  end
283
290
  end
284
291
 
285
- def sh_nonfatal(command_string)
286
- STDERR.puts " # #{command_string}"
287
- PhusionPassenger::Utils.mktmpdir("passenger-native-support-") do |tmpdir|
288
- s_tmpdir = Shellwords.escape(tmpdir)
289
- result = system("#{command_string} >#{s_tmpdir}/log 2>&1")
290
- system("cat #{s_tmpdir}/log | sed 's/^/ /' >&2")
291
- return result
292
+ def sh_nonfatal(command_string, options = {})
293
+ log("# #{command_string}", options)
294
+ if logger = options[:logger]
295
+ s_logpath = Shellwords.escape(logger.path)
296
+ return system("(#{command_string}) >>#{s_logpath} 2>&1")
297
+ else
298
+ Utils.mktmpdir("passenger-native-support-") do |tmpdir|
299
+ s_tmpdir = Shellwords.escape(tmpdir)
300
+ result = system("(#{command_string}) >#{s_tmpdir}/log 2>&1")
301
+ system("cat #{s_tmpdir}/log | sed 's/^/ /' >&2")
302
+ return result
303
+ end
292
304
  end
293
305
  end
294
306
 
295
307
  def compile(target_dirs)
296
- try_directories(target_dirs) do |target_dir|
297
- result =
298
- sh_nonfatal("#{PlatformInfo.ruby_command} #{Shellwords.escape extconf_rb}") &&
299
- sh_nonfatal("make clean && make")
300
- if result
301
- STDERR.puts " Compilation succesful."
302
- [target_dir, false]
303
- else
304
- STDERR.puts " Compilation failed."
305
- [nil, false]
308
+ logger = Utils::TmpIO.new('passenger_native_support',
309
+ :mode => File::WRONLY | File::APPEND,
310
+ :binary => false,
311
+ :suffix => ".log",
312
+ :unlink_immediately => false)
313
+ options = { :logger => logger }
314
+ begin
315
+ try_directories(target_dirs, options) do |target_dir|
316
+ result =
317
+ sh_nonfatal("#{PlatformInfo.ruby_command} #{Shellwords.escape extconf_rb}",
318
+ options) &&
319
+ sh_nonfatal("make clean && make", options)
320
+ if result
321
+ log "Compilation succesful. The logs are here:"
322
+ log logger.path
323
+ [target_dir, false]
324
+ else
325
+ log "Warning: compilation didn't succeed. To learn why, read this file:"
326
+ log logger.path
327
+ [nil, false]
328
+ end
306
329
  end
307
330
  end
331
+ ensure
332
+ logger.close if logger
308
333
  end
309
334
 
310
- def try_directories(dirs)
335
+ def try_directories(dirs, options = {})
311
336
  result = nil
312
337
  dirs.each_with_index do |dir, i|
313
338
  begin
314
- mkdir(dir)
339
+ mkdir(dir, options)
315
340
  File.open("#{dir}/.permission_test", "w").close
316
341
  File.unlink("#{dir}/.permission_test")
317
- STDERR.puts " # cd #{dir}"
342
+ log("# cd #{dir}", options)
318
343
  Dir.chdir(dir) do
319
344
  result, should_retry = yield(dir)
320
345
  return result if !should_retry
@@ -325,26 +350,30 @@ private
325
350
  # error on the last one too then propagate the
326
351
  # exception.
327
352
  if i == dirs.size - 1
328
- STDERR.puts " Encountered permission error, " +
329
- "but no more directories to try. Giving up."
330
- STDERR.puts " -------------------------------"
353
+ log("Encountered permission error, " +
354
+ "but no more directories to try. Giving up.",
355
+ options)
356
+ log("-------------------------------", options)
331
357
  return nil
332
358
  else
333
- STDERR.puts " Encountered permission error, " +
334
- "trying a different directory..."
335
- STDERR.puts " -------------------------------"
359
+ log("Encountered permission error, " +
360
+ "trying a different directory...",
361
+ options)
362
+ log("-------------------------------", options)
336
363
  end
337
364
  rescue Errno::ENOTDIR
338
365
  # This can occur when locations.ini set buildout_dir
339
366
  # to an invalid path. Just ignore this error.
340
367
  if i == dirs.size - 1
341
- STDERR.puts " Not a valid directory, " +
342
- "but no more directories to try. Giving up."
343
- STDERR.puts " -------------------------------"
368
+ log("Not a valid directory, " +
369
+ "but no more directories to try. Giving up.",
370
+ options)
371
+ log("-------------------------------", options)
344
372
  return nil
345
373
  else
346
- STDERR.puts " Not a valid directory. Trying a different one..."
347
- STDERR.puts " -------------------------------"
374
+ log("Not a valid directory. Trying a different one...",
375
+ options)
376
+ log("-------------------------------", options)
348
377
  end
349
378
  end
350
379
  end
@@ -74,6 +74,7 @@ module Packaging
74
74
  'CONTRIBUTORS',
75
75
  'CONTRIBUTING.md',
76
76
  'LICENSE',
77
+ 'CHANGELOG',
77
78
  'INSTALL.md',
78
79
  'NEWS',
79
80
  'passenger.gemspec',
@@ -1,6 +1,6 @@
1
1
  # encoding: binary
2
2
  # Phusion Passenger - https://www.phusionpassenger.com/
3
- # Copyright (c) 2012-2013 Phusion
3
+ # Copyright (c) 2012-2014 Phusion
4
4
  #
5
5
  # "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  #
@@ -28,34 +28,104 @@ module PhusionPassenger
28
28
  module Rack
29
29
 
30
30
  class OutOfBandGc
31
- def initialize(app, frequency, logger = nil)
31
+ # Usage:
32
+ #
33
+ # OutOfBandGc.new(app, frequency, logger = nil)
34
+ # OutOfBandGc.new(app, options = {})
35
+ def initialize(app, *args)
32
36
  @app = app
33
- @frequency = frequency
34
- @request_count = 0
35
- @mutex = Mutex.new
36
-
37
- ::PhusionPassenger.on_event(:oob_work) do
38
- t0 = Time.now
39
- disabled = GC.enable
40
- GC.start
41
- GC.disable if disabled
42
- logger.info "Out Of Band GC finished in #{Time.now - t0} sec" if logger
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
43
  end
44
44
  end
45
45
 
46
46
  def call(env)
47
47
  status, headers, body = @app.call(env)
48
48
 
49
- @mutex.synchronize do
50
- @request_count += 1
51
- if @request_count == @frequency
52
- @request_count = 0
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['X-Passenger-Request-OOB-Work'] = 'true'
56
+ end
57
+ end
58
+
59
+ when :gctools_oobgc
60
+ if GC::OOB.dry_run
53
61
  headers['X-Passenger-Request-OOB-Work'] = 'true'
54
62
  end
63
+
64
+ else
65
+ raise "Unrecognized Out-Of-Band GC strategy #{@strategy.inspect}"
55
66
  end
56
-
67
+
57
68
  [status, headers, body]
58
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
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
121
+ end
122
+
123
+ def initialize_legacy(frequency, logger = nil)
124
+ initialize_with_options(
125
+ :strategy => :counting,
126
+ :frequency => frequency,
127
+ :logger => logger)
128
+ end
59
129
  end
60
130
 
61
131
  end # module Rack