passenger 5.0.8 → 5.0.9
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.
- checksums.yaml +8 -8
- checksums.yaml.gz.asc +7 -7
- data.tar.gz.asc +7 -7
- data/.editorconfig +20 -0
- data/CHANGELOG +21 -0
- data/bin/passenger-install-apache2-module +3 -1
- data/build/agents.rb +7 -5
- data/build/basics.rb +3 -3
- data/build/common_library.rb +52 -30
- data/build/cxx_tests.rb +20 -13
- data/build/misc.rb +5 -5
- data/doc/Design and Architecture.html +1 -1
- data/doc/Design and Architecture.txt +1 -1
- data/doc/Packaging.html +4 -4
- data/doc/Packaging.txt.md +4 -4
- data/doc/Users guide Apache.html +22 -9
- data/doc/Users guide Apache.idmap.txt +4 -2
- data/doc/Users guide Apache.txt +2 -0
- data/doc/Users guide Nginx.html +22 -9
- data/doc/Users guide Nginx.idmap.txt +4 -2
- data/doc/Users guide Nginx.txt +2 -0
- data/doc/Users guide Standalone.html +14 -9
- data/doc/Users guide Standalone.idmap.txt +4 -2
- data/doc/users_guide_snippets/installation.txt +10 -6
- data/ext/apache2/Hooks.cpp +13 -2
- data/ext/common/ApplicationPool2/Pool/Inspection.h +8 -3
- data/ext/common/BackgroundEventLoop.cpp +249 -67
- data/ext/common/BackgroundEventLoop.h +5 -5
- data/ext/common/Constants.h +1 -1
- data/ext/common/InstanceDirectory.h +8 -6
- data/ext/common/ServerKit/Context.h +8 -2
- data/ext/common/ServerKit/FileBufferedChannel.h +262 -226
- data/ext/common/ServerKit/HeaderTable.h +28 -3
- data/ext/common/ServerKit/HttpHeaderParser.h +37 -13
- data/ext/common/ServerKit/HttpServer.h +17 -1
- data/ext/common/ServerKit/Implementation.cpp +2 -0
- data/ext/common/ServerKit/Server.h +25 -28
- data/ext/common/Utils/IOUtils.cpp +11 -0
- data/ext/common/Utils/ProcessMetricsCollector.h +4 -0
- data/ext/common/Utils/StrIntUtils.cpp +11 -7
- data/ext/common/Utils/StrIntUtils.h +1 -1
- data/ext/common/Utils/StrIntUtilsNoStrictAliasing.cpp +21 -16
- data/ext/common/agents/Base.cpp +6 -0
- data/ext/common/agents/Base.h +2 -0
- data/ext/common/agents/HelperAgent/AdminServer.h +25 -25
- data/ext/common/agents/HelperAgent/Main.cpp +37 -12
- data/ext/common/agents/HelperAgent/RequestHandler.h +18 -20
- data/ext/common/agents/HelperAgent/RequestHandler/AppResponse.h +4 -0
- data/ext/common/agents/HelperAgent/RequestHandler/ForwardResponse.cpp +10 -6
- data/ext/common/agents/HelperAgent/RequestHandler/Hooks.cpp +2 -0
- data/ext/common/agents/HelperAgent/RequestHandler/InitRequest.cpp +1 -1
- data/ext/common/agents/HelperAgent/RequestHandler/SendRequest.cpp +1 -1
- data/ext/common/agents/HelperAgent/RequestHandler/Utils.cpp +9 -2
- data/ext/common/agents/HelperAgent/ResponseCache.h +11 -11
- data/ext/common/agents/LoggingAgent/AdminServer.h +8 -8
- data/ext/common/agents/LoggingAgent/Main.cpp +6 -5
- data/ext/common/agents/Watchdog/AdminServer.h +13 -13
- data/ext/common/agents/Watchdog/Main.cpp +8 -3
- data/ext/libuv/.gitignore +72 -0
- data/ext/libuv/AUTHORS +199 -0
- data/ext/libuv/ChangeLog +2023 -0
- data/ext/libuv/LICENSE +46 -0
- data/ext/libuv/Makefile.am +336 -0
- data/ext/libuv/README.md +197 -0
- data/ext/libuv/checksparse.sh +233 -0
- data/ext/libuv/common.gypi +210 -0
- data/ext/libuv/configure.ac +67 -0
- data/ext/libuv/gyp_uv.py +96 -0
- data/ext/libuv/include/android-ifaddrs.h +54 -0
- data/ext/libuv/include/pthread-fixes.h +72 -0
- data/ext/libuv/include/tree.h +768 -0
- data/ext/libuv/include/uv-aix.h +32 -0
- data/ext/libuv/include/uv-bsd.h +34 -0
- data/ext/libuv/include/uv-darwin.h +61 -0
- data/ext/libuv/include/uv-errno.h +418 -0
- data/ext/libuv/include/uv-linux.h +34 -0
- data/ext/libuv/include/uv-sunos.h +44 -0
- data/ext/libuv/include/uv-threadpool.h +37 -0
- data/ext/libuv/include/uv-unix.h +383 -0
- data/ext/libuv/include/uv-version.h +39 -0
- data/ext/libuv/include/uv.h +1455 -0
- data/ext/libuv/libuv.pc.in +11 -0
- data/ext/libuv/m4/.gitignore +4 -0
- data/ext/libuv/m4/as_case.m4 +21 -0
- data/ext/libuv/m4/libuv-check-flags.m4 +319 -0
- data/ext/libuv/src/fs-poll.c +255 -0
- data/ext/libuv/src/heap-inl.h +245 -0
- data/ext/libuv/src/inet.c +313 -0
- data/ext/libuv/src/queue.h +92 -0
- data/ext/libuv/src/threadpool.c +303 -0
- data/ext/libuv/src/unix/aix.c +1240 -0
- data/ext/libuv/src/unix/android-ifaddrs.c +703 -0
- data/ext/libuv/src/unix/async.c +284 -0
- data/ext/libuv/src/unix/atomic-ops.h +60 -0
- data/ext/libuv/src/unix/core.c +985 -0
- data/ext/libuv/src/unix/darwin-proctitle.c +206 -0
- data/ext/libuv/src/unix/darwin.c +331 -0
- data/ext/libuv/src/unix/dl.c +83 -0
- data/ext/libuv/src/unix/freebsd.c +435 -0
- data/ext/libuv/src/unix/fs.c +1189 -0
- data/ext/libuv/src/unix/fsevents.c +899 -0
- data/ext/libuv/src/unix/getaddrinfo.c +202 -0
- data/ext/libuv/src/unix/getnameinfo.c +120 -0
- data/ext/libuv/src/unix/internal.h +314 -0
- data/ext/libuv/src/unix/kqueue.c +418 -0
- data/ext/libuv/src/unix/linux-core.c +876 -0
- data/ext/libuv/src/unix/linux-inotify.c +257 -0
- data/ext/libuv/src/unix/linux-syscalls.c +471 -0
- data/ext/libuv/src/unix/linux-syscalls.h +158 -0
- data/ext/libuv/src/unix/loop-watcher.c +63 -0
- data/ext/libuv/src/unix/loop.c +135 -0
- data/ext/libuv/src/unix/netbsd.c +368 -0
- data/ext/libuv/src/unix/openbsd.c +384 -0
- data/ext/libuv/src/unix/pipe.c +288 -0
- data/ext/libuv/src/unix/poll.c +113 -0
- data/ext/libuv/src/unix/process.c +551 -0
- data/ext/libuv/src/unix/proctitle.c +102 -0
- data/ext/libuv/src/unix/pthread-fixes.c +103 -0
- data/ext/libuv/src/unix/signal.c +465 -0
- data/ext/libuv/src/unix/spinlock.h +53 -0
- data/ext/libuv/src/unix/stream.c +1598 -0
- data/ext/libuv/src/unix/sunos.c +763 -0
- data/ext/libuv/src/unix/tcp.c +327 -0
- data/ext/libuv/src/unix/thread.c +519 -0
- data/ext/libuv/src/unix/timer.c +172 -0
- data/ext/libuv/src/unix/tty.c +265 -0
- data/ext/libuv/src/unix/udp.c +833 -0
- data/ext/libuv/src/uv-common.c +544 -0
- data/ext/libuv/src/uv-common.h +214 -0
- data/ext/libuv/src/version.c +49 -0
- data/ext/libuv/uv.gyp +487 -0
- data/ext/nginx/ContentHandler.c +21 -10
- data/ext/nginx/ngx_http_passenger_module.c +7 -0
- data/ext/oxt/implementation.cpp +9 -2
- data/ext/oxt/initialize.hpp +5 -1
- data/lib/phusion_passenger.rb +3 -3
- data/lib/phusion_passenger/admin_tools/instance.rb +10 -6
- data/lib/phusion_passenger/admin_tools/instance_registry.rb +6 -2
- data/lib/phusion_passenger/packaging.rb +3 -4
- data/lib/phusion_passenger/platform_info.rb +13 -1
- data/lib/phusion_passenger/platform_info/apache.rb +15 -4
- data/lib/phusion_passenger/platform_info/apache_detector.rb +5 -1
- data/lib/phusion_passenger/rack/thread_handler_extension.rb +184 -99
- data/lib/phusion_passenger/request_handler/thread_handler.rb +13 -6
- data/lib/phusion_passenger/standalone/start_command.rb +2 -2
- data/resources/templates/apache2/apache_install_broken.txt.erb +2 -1
- metadata +99 -22
- metadata.gz.asc +7 -7
- data/ext/libeio/Changes +0 -76
- data/ext/libeio/LICENSE +0 -36
- data/ext/libeio/Makefile.am +0 -15
- data/ext/libeio/Makefile.in +0 -694
- data/ext/libeio/aclocal.m4 +0 -9418
- data/ext/libeio/autogen.sh +0 -3
- data/ext/libeio/config.guess +0 -1540
- data/ext/libeio/config.h.in +0 -136
- data/ext/libeio/config.sub +0 -1779
- data/ext/libeio/configure +0 -14822
- data/ext/libeio/configure.ac +0 -22
- data/ext/libeio/demo.c +0 -194
- data/ext/libeio/ecb.h +0 -714
- data/ext/libeio/eio.c +0 -2818
- data/ext/libeio/eio.h +0 -414
- data/ext/libeio/install-sh +0 -520
- data/ext/libeio/libeio.m4 +0 -195
- data/ext/libeio/ltmain.sh +0 -9636
- data/ext/libeio/missing +0 -376
- data/ext/libeio/xthread.h +0 -166
data/ext/nginx/ContentHandler.c
CHANGED
@@ -140,12 +140,12 @@ map_uri_to_page_cache_file(ngx_http_request_t *r, ngx_str_t *public_dir,
|
|
140
140
|
|
141
141
|
} else if (filename[filename_len - 1] == '/') {
|
142
142
|
/* if the filename ends with '/' check for filename + "index.html". */
|
143
|
-
|
143
|
+
|
144
144
|
if (filename_len + sizeof("index.html") > page_cache_file->len) {
|
145
145
|
/* Page cache filename doesn't fit in the buffer. */
|
146
146
|
return 0;
|
147
147
|
}
|
148
|
-
|
148
|
+
|
149
149
|
end = ngx_copy(page_cache_file->data, filename, filename_len);
|
150
150
|
end = ngx_copy(end, "index.html", sizeof("index.html"));
|
151
151
|
} else {
|
@@ -416,16 +416,27 @@ prepare_request_buffer_construction(ngx_http_request_t *r, passenger_context_t *
|
|
416
416
|
* Nginx unescapes URI's before passing them to Phusion Passenger,
|
417
417
|
* but backend processes expect the escaped version.
|
418
418
|
* http://code.google.com/p/phusion-passenger/issues/detail?id=404
|
419
|
+
*
|
420
|
+
* Here we check whether Nginx has rewritten the URI or not. If not,
|
421
|
+
* we can use the raw, unparsed URI as sent by the client.
|
419
422
|
*/
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
423
|
+
if (r->valid_unparsed_uri && r->main) {
|
424
|
+
state->escaped_uri = r->unparsed_uri;
|
425
|
+
const char *pos = memchr((const char *) r->unparsed_uri.data, '?', r->unparsed_uri.len);
|
426
|
+
if (pos != NULL) {
|
427
|
+
state->escaped_uri.len = pos - (const char *) r->unparsed_uri.data;
|
428
|
+
}
|
429
|
+
} else {
|
430
|
+
state->escaped_uri.len =
|
431
|
+
2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, NGX_ESCAPE_URI)
|
432
|
+
+ r->uri.len;
|
433
|
+
state->escaped_uri.data = ngx_pnalloc(r->pool, state->escaped_uri.len);
|
434
|
+
if (state->escaped_uri.data == NULL) {
|
435
|
+
return NGX_ERROR;
|
436
|
+
}
|
437
|
+
ngx_escape_uri(state->escaped_uri.data, r->uri.data, r->uri.len,
|
438
|
+
NGX_ESCAPE_URI);
|
426
439
|
}
|
427
|
-
ngx_escape_uri(state->escaped_uri.data, r->uri.data, r->uri.len,
|
428
|
-
NGX_ESCAPE_URI);
|
429
440
|
|
430
441
|
if (r->headers_in.chunked) {
|
431
442
|
/* If the request body is chunked, then Nginx sets r->headers_in.content_length_n
|
@@ -302,6 +302,13 @@ start_watchdog(ngx_cycle_t *cycle) {
|
|
302
302
|
|
303
303
|
if (passenger_main_conf.log_file.len > 0) {
|
304
304
|
pp_variant_map_set_ngx_str(params, "log_file", &passenger_main_conf.log_file);
|
305
|
+
} else if (cycle->new_log.file == NULL) {
|
306
|
+
ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "Cannot initialize " PROGRAM_NAME
|
307
|
+
" because Nginx is not configured with an error log file."
|
308
|
+
" Please either configure Nginx with an error log file, or configure "
|
309
|
+
PROGRAM_NAME " with a `passenger_log_file`");
|
310
|
+
result = NGX_ERROR;
|
311
|
+
goto cleanup;
|
305
312
|
} else if (cycle->new_log.file->name.len > 0) {
|
306
313
|
pp_variant_map_set_ngx_str(params, "log_file", &cycle->new_log.file->name);
|
307
314
|
} else if (cycle->log->file->name.len > 0) {
|
data/ext/oxt/implementation.cpp
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
* OXT - OS eXtensions for boosT
|
3
3
|
* Provides important functionality necessary for writing robust server software.
|
4
4
|
*
|
5
|
-
* Copyright (c) 2008-
|
5
|
+
* Copyright (c) 2008-2015 Phusion
|
6
6
|
*
|
7
7
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
8
|
* of this software and associated documentation files (the "Software"), to deal
|
@@ -326,7 +326,8 @@ tracable_exception::what() const throw() {
|
|
326
326
|
#endif /* OXT_BACKTRACE_IS_ENABLED */
|
327
327
|
|
328
328
|
|
329
|
-
void
|
329
|
+
void
|
330
|
+
initialize() {
|
330
331
|
global_context = new global_context_t();
|
331
332
|
init_thread_local_context_support();
|
332
333
|
// For some reason make_shared() crashes here when compiled with clang 3.2 on OS X.
|
@@ -342,6 +343,12 @@ void initialize() {
|
|
342
343
|
ctx->iterator--;
|
343
344
|
}
|
344
345
|
|
346
|
+
void shutdown() {
|
347
|
+
free_thread_local_context();
|
348
|
+
delete global_context;
|
349
|
+
global_context = NULL;
|
350
|
+
}
|
351
|
+
|
345
352
|
|
346
353
|
global_context_t::global_context_t()
|
347
354
|
: next_thread_number(2)
|
data/ext/oxt/initialize.hpp
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
* OXT - OS eXtensions for boosT
|
3
3
|
* Provides important functionality necessary for writing robust server software.
|
4
4
|
*
|
5
|
-
* Copyright (c) 2012 Phusion
|
5
|
+
* Copyright (c) 2012-2015 Phusion
|
6
6
|
*
|
7
7
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
8
|
* of this software and associated documentation files (the "Software"), to deal
|
@@ -33,6 +33,10 @@ namespace oxt {
|
|
33
33
|
* for that.
|
34
34
|
*/
|
35
35
|
void initialize();
|
36
|
+
/**
|
37
|
+
* Frees resources allocated by initialize().
|
38
|
+
*/
|
39
|
+
void shutdown();
|
36
40
|
|
37
41
|
} // namespace oxt
|
38
42
|
|
data/lib/phusion_passenger.rb
CHANGED
@@ -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.
|
33
|
+
VERSION_STRING = '5.0.9'
|
34
34
|
|
35
|
-
PREFERRED_NGINX_VERSION = '1.
|
36
|
-
NGINX_SHA256_CHECKSUM = '
|
35
|
+
PREFERRED_NGINX_VERSION = '1.8.0'
|
36
|
+
NGINX_SHA256_CHECKSUM = '23cca1239990c818d8f6da118320c4979aadf5386deda691b1b7c2c96b9df3d5'
|
37
37
|
|
38
38
|
PREFERRED_PCRE_VERSION = '8.34'
|
39
39
|
PCRE_SHA256_CHECKSUM = '1dd78994c81e44ac41cf30b2a21d4b4cc6d76ccde7fc6e77713ed51d7bddca47'
|
@@ -59,28 +59,32 @@ module PhusionPassenger
|
|
59
59
|
|
60
60
|
def locked?
|
61
61
|
if defined?(File::LOCK_EX)
|
62
|
-
|
63
|
-
|
62
|
+
begin
|
63
|
+
!File.open("#{@path}/lock", "r") do |f|
|
64
|
+
f.flock(File::LOCK_EX | File::LOCK_NB)
|
65
|
+
end
|
66
|
+
rescue Errno::ENOENT
|
67
|
+
false
|
64
68
|
end
|
65
69
|
else
|
66
70
|
# Solaris :-(
|
67
71
|
# Since using fcntl locks in Ruby is a huge pain,
|
68
72
|
# we'll fallback to checking the watchdog PID.
|
69
|
-
|
73
|
+
watchdog_alive?
|
70
74
|
end
|
71
75
|
end
|
72
76
|
|
73
77
|
def stale?
|
74
78
|
stat = File.stat(@path)
|
75
79
|
if stat.mtime < Time.now - STALE_TIMEOUT
|
76
|
-
|
80
|
+
!locked?
|
77
81
|
else
|
78
|
-
|
82
|
+
false
|
79
83
|
end
|
80
84
|
end
|
81
85
|
|
82
86
|
def watchdog_alive?
|
83
|
-
|
87
|
+
process_is_alive?(@watchdog_pid)
|
84
88
|
end
|
85
89
|
|
86
90
|
def http_request(socket_path, request)
|
@@ -102,8 +102,12 @@ module PhusionPassenger
|
|
102
102
|
|
103
103
|
def cleanup(path)
|
104
104
|
puts "*** Cleaning stale instance directory #{path}"
|
105
|
-
|
106
|
-
|
105
|
+
begin
|
106
|
+
FileUtils.chmod_R(0700, path) rescue nil
|
107
|
+
FileUtils.remove_entry_secure(path)
|
108
|
+
rescue SystemCallError => e
|
109
|
+
puts " Warning: #{e}"
|
110
|
+
end
|
107
111
|
end
|
108
112
|
end
|
109
113
|
|
@@ -100,10 +100,9 @@ module PhusionPassenger
|
|
100
100
|
'ext/libev/{*.m4,autogen.sh,config.guess,config.h.in,config.sub}',
|
101
101
|
'ext/libev/{configure,configure.ac,depcomp,install-sh,ltmain.sh,missing,mkinstalldirs}',
|
102
102
|
'ext/libev/{*.h,*.c}',
|
103
|
-
'ext/
|
104
|
-
'ext/
|
105
|
-
'ext/
|
106
|
-
'ext/libeio/{*.h,*.c}',
|
103
|
+
'ext/libuv/**/*',
|
104
|
+
'ext/libuv/.gitignore',
|
105
|
+
'ext/libuv/m4/.gitignore',
|
107
106
|
'ext/oxt/*.hpp',
|
108
107
|
'ext/oxt/*.cpp',
|
109
108
|
'ext/oxt/*.txt',
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: binary
|
2
2
|
# Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
# Copyright (c) 2010-
|
3
|
+
# Copyright (c) 2010-2015 Phusion
|
4
4
|
#
|
5
5
|
# "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
|
6
6
|
#
|
@@ -366,6 +366,18 @@ module PhusionPassenger
|
|
366
366
|
["/opt/*/bin", "/opt/*/sbin", "/usr/local/*/bin", "/usr/local/*/sbin"].each do |glob|
|
367
367
|
search_dirs.concat(Dir[glob])
|
368
368
|
end
|
369
|
+
|
370
|
+
# Solaris systems may have Apache installations in
|
371
|
+
# /usr/apache2/2.2/bin/sparcv9/
|
372
|
+
Dir["/usr/apache2/*/bin"].each do |bindir|
|
373
|
+
search_dirs << bindir
|
374
|
+
Dir["#{bindir}/*"].each do |binsubdir|
|
375
|
+
if File.directory?(binsubdir)
|
376
|
+
search_dirs << binsubdir
|
377
|
+
end
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
369
381
|
search_dirs.delete("")
|
370
382
|
search_dirs.uniq!
|
371
383
|
|
@@ -649,14 +649,25 @@ module PhusionPassenger
|
|
649
649
|
# Linker flags that are necessary for linking an Apache module.
|
650
650
|
# Already includes APR and APU linker flags.
|
651
651
|
def self.apache2_module_cxx_ldflags
|
652
|
+
flags = ""
|
653
|
+
if !apxs2.nil?
|
654
|
+
flags << `#{apxs2} -q LDFLAGS`.strip
|
655
|
+
end
|
656
|
+
|
657
|
+
# We must include the cxxflags in the linker flags. On some multilib
|
658
|
+
# Solaris systems, `apxs -q CFLAGS` outputs a flag that tells the compiler
|
659
|
+
# which architecture to compile against, while `apxs -q LDFLAGS` doesn't.
|
660
|
+
flags << " #{apache2_module_cxxflags} #{apr_cxx_ldflags} #{apu_cxx_ldflags}"
|
661
|
+
|
652
662
|
if cxx_is_sun_studio?
|
653
|
-
flags
|
663
|
+
flags.gsub!("-fPIC", "-KPIC")
|
664
|
+
flags << " -KPIC" if !flags.include?("-KPIC")
|
654
665
|
else
|
655
|
-
flags
|
666
|
+
flags << " -fPIC" if !flags.include?("-fPIC")
|
656
667
|
end
|
657
|
-
|
668
|
+
|
658
669
|
flags.strip!
|
659
|
-
|
670
|
+
flags
|
660
671
|
end
|
661
672
|
memoize :apache2_module_cxx_ldflags
|
662
673
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# Phusion Passenger - https://www.phusionpassenger.com/
|
2
|
-
# Copyright (c) 2013 Phusion
|
2
|
+
# Copyright (c) 2013-2015 Phusion
|
3
3
|
#
|
4
4
|
# "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
|
5
5
|
#
|
@@ -107,6 +107,10 @@ module PhusionPassenger
|
|
107
107
|
log "<banner>Looking for possible Apache installations...</banner>"
|
108
108
|
apxses = PlatformInfo.find_all_commands("apxs2") +
|
109
109
|
PlatformInfo.find_all_commands("apxs")
|
110
|
+
if !apxses.include?(PlatformInfo.apxs2)
|
111
|
+
PlatformInfo.send(:log, "Looking for #{PlatformInfo.apxs2}: found")
|
112
|
+
apxses << PlatformInfo.apxs2
|
113
|
+
end
|
110
114
|
apxses = remove_symlink_duplications(apxses)
|
111
115
|
log ""
|
112
116
|
apxses.each do |apxs2|
|
@@ -39,13 +39,17 @@ module PhusionPassenger
|
|
39
39
|
RACK_URL_SCHEME = "rack.url_scheme" # :nodoc:
|
40
40
|
RACK_HIJACK_P = "rack.hijack?" # :nodoc:
|
41
41
|
RACK_HIJACK = "rack.hijack" # :nodoc:
|
42
|
+
HTTP_VERSION = "HTTP_VERSION" # :nodoc:
|
43
|
+
HTTP_1_1 = "HTTP/1.1" # :nodoc:
|
42
44
|
SCRIPT_NAME = "SCRIPT_NAME" # :nodoc:
|
43
45
|
REQUEST_METHOD = "REQUEST_METHOD" # :nodoc:
|
44
46
|
TRANSFER_ENCODING_HEADER = "Transfer-Encoding" # :nodoc:
|
45
47
|
CONTENT_LENGTH_HEADER = "Content-Length" # :nodoc:
|
48
|
+
X_SENDFILE_HEADER = "X-Sendfile" # :nodoc:
|
49
|
+
X_ACCEL_REDIRECT_HEADER = "X-Accel-Redirect" # :nodoc:
|
46
50
|
CONTENT_LENGTH_HEADER_AND_SEPARATOR = "Content-Length: " # :nodoc
|
47
|
-
|
48
|
-
|
51
|
+
TRANSFER_ENCODING_HEADER_AND_VALUE_CRLF = "Transfer-Encoding: chunked\r\n" # :nodoc:
|
52
|
+
CONNECTION_CLOSE_CRLF2 = "Connection: close\r\n\r\n" # :nodoc:
|
49
53
|
HEAD = "HEAD" # :nodoc:
|
50
54
|
HTTPS = "HTTPS" # :nodoc:
|
51
55
|
HTTPS_DOWNCASE = "https" # :nodoc:
|
@@ -80,6 +84,7 @@ module PhusionPassenger
|
|
80
84
|
connection
|
81
85
|
end
|
82
86
|
end
|
87
|
+
env[HTTP_VERSION] = HTTP_1_1
|
83
88
|
|
84
89
|
# Rails somehow modifies env['REQUEST_METHOD'], so we perform the comparison
|
85
90
|
# before the Rack application object is called.
|
@@ -88,10 +93,7 @@ module PhusionPassenger
|
|
88
93
|
begin
|
89
94
|
status, headers, body = @app.call(env)
|
90
95
|
rescue => e
|
91
|
-
|
92
|
-
if should_reraise_app_error?(e, socket_wrapper)
|
93
|
-
raise e
|
94
|
-
elsif !should_swallow_app_error?(e, socket_wrapper)
|
96
|
+
if !should_swallow_app_error?(e, socket_wrapper)
|
95
97
|
# It's a good idea to catch application exceptions here because
|
96
98
|
# otherwise maliciously crafted responses can crash the app,
|
97
99
|
# forcing it to be respawned, and thereby effectively DoSing it.
|
@@ -102,112 +104,206 @@ module PhusionPassenger
|
|
102
104
|
end
|
103
105
|
|
104
106
|
# Application requested a full socket hijack.
|
105
|
-
|
107
|
+
if env[RACK_HIJACK_IO]
|
108
|
+
# Since the app hijacked the socket, we don't know what state we're
|
109
|
+
# in and we don't know whether we can recover from it, so we don't
|
110
|
+
# catch any exception here.
|
111
|
+
#
|
112
|
+
# The Rack specification doesn't specify whether the body should
|
113
|
+
# be closed when the socket is hijacked. As of February 2 2015,
|
114
|
+
# Puma and Thin close the body, while Unicorn does not.
|
115
|
+
# However, Rack::Lock and possibly many other middlewares count
|
116
|
+
# on the body being closed, as described here:
|
117
|
+
# https://github.com/ngauthier/tubesock/issues/10#issuecomment-72539461
|
118
|
+
# So we have chosen to close the body.
|
119
|
+
body.close if body && body.respond_to?(:close)
|
120
|
+
return true
|
121
|
+
end
|
122
|
+
|
123
|
+
# Application requested a partial socket hijack.
|
124
|
+
if hijack_callback = headers[RACK_HIJACK]
|
125
|
+
# We don't catch exceptions here. EPIPE is already handled
|
126
|
+
# by ThreadHandler's #accept_and_process_next_request.
|
127
|
+
# On any other exception, we don't know what state we're
|
128
|
+
# in and we don't know whether we can recover from it.
|
129
|
+
begin
|
130
|
+
headers_output = generate_headers_array(status, headers)
|
131
|
+
headers_output << CONNECTION_CLOSE_CRLF2
|
132
|
+
connection.writev(headers_output)
|
133
|
+
connection.flush
|
134
|
+
hijacked_socket = env[RACK_HIJACK].call
|
135
|
+
hijack_callback.call(hijacked_socket)
|
136
|
+
return true
|
137
|
+
ensure
|
138
|
+
body.close if body && body.respond_to?(:close)
|
139
|
+
end
|
140
|
+
end
|
106
141
|
|
107
142
|
begin
|
108
143
|
process_body(env, connection, socket_wrapper, status.to_i, is_head_request,
|
109
144
|
headers, body)
|
110
|
-
rescue
|
111
|
-
|
112
|
-
|
145
|
+
rescue => e
|
146
|
+
if !should_swallow_app_error?(e, socket_wrapper)
|
147
|
+
print_exception("Rack response body object", e)
|
148
|
+
PhusionPassenger.log_request_exception(env, e)
|
149
|
+
end
|
113
150
|
ensure
|
114
|
-
|
151
|
+
begin
|
152
|
+
body.close if body && body.respond_to?(:close)
|
153
|
+
rescue => e
|
154
|
+
if !should_swallow_app_error?(e, socket_wrapper)
|
155
|
+
print_exception("Rack response body object's #close method", e)
|
156
|
+
PhusionPassenger.log_request_exception(env, e)
|
157
|
+
end
|
158
|
+
end
|
115
159
|
end
|
160
|
+
false
|
116
161
|
ensure
|
117
162
|
rewindable_input.close
|
118
163
|
end
|
119
164
|
end
|
120
165
|
|
121
166
|
private
|
122
|
-
# The code here is ugly, but it's necessary for performance.
|
123
167
|
def process_body(env, connection, socket_wrapper, status, is_head_request, headers, body)
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
hijacked_socket = env[RACK_HIJACK].call
|
133
|
-
hijack_callback.call(hijacked_socket)
|
134
|
-
true
|
135
|
-
elsif body.is_a?(Array)
|
168
|
+
# Fix up incompliant body objects. Ensure that the body object
|
169
|
+
# can respond to #each.
|
170
|
+
output_body = should_output_body?(status, is_head_request)
|
171
|
+
if body.is_a?(String)
|
172
|
+
body = [body]
|
173
|
+
elsif body.nil?
|
174
|
+
body = []
|
175
|
+
elsif output_body && body.is_a?(Array)
|
136
176
|
# The body may be an ActionController::StringCoercion::UglyBody
|
137
177
|
# object instead of a real Array, even when #is_a? claims so.
|
138
|
-
# Call #to_a just to be sure.
|
178
|
+
# Call #to_a just to be sure that connection.writev() can
|
179
|
+
# accept the body object.
|
139
180
|
body = body.to_a
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
181
|
+
end
|
182
|
+
|
183
|
+
# Generate preliminary headers and determine whether we need to output a body.
|
184
|
+
headers_output = generate_headers_array(status, headers)
|
185
|
+
|
186
|
+
|
187
|
+
# Determine how big the body is, determine whether we should try to keep-alive
|
188
|
+
# the connection, and fix up the headers according to the situation.
|
189
|
+
#
|
190
|
+
# It may not be possible to determine the body's size (e.g. because it's streamed
|
191
|
+
# through #each). In that case we'll want to output the body with a chunked transfer
|
192
|
+
# encoding. But it matters whether the app has already chunked the body or not.
|
193
|
+
#
|
194
|
+
# Note that if the Rack response header contains "Transfer-Encoding: chunked",
|
195
|
+
# then we assume that the Rack body is already in chunked form. This is the way
|
196
|
+
# Rails streaming and Rack::Chunked::Body behave.
|
197
|
+
# The only gem that doesn't behave this way is JRuby-Rack (see
|
198
|
+
# https://blog.engineyard.com/2011/taking-stock-jruby-web-servers), but I'm not
|
199
|
+
# aware of anybody using JRuby-Rack these days.
|
200
|
+
#
|
201
|
+
# We only try to keep-alive the connection if we are able to determine ahead of
|
202
|
+
# time that the body we write out is guaranteed to match what the headers say.
|
203
|
+
# Otherwise we disable keep-alive to prevent the app from being able to mess
|
204
|
+
# up the keep-alive connection.
|
205
|
+
if header = headers[CONTENT_LENGTH_HEADER]
|
206
|
+
# Easiest case: app has a Content-Length header. The headers
|
207
|
+
# need no fixing.
|
208
|
+
message_length_type = :content_length
|
209
|
+
content_length = header.to_i
|
210
|
+
if headers.has_key?(TRANSFER_ENCODING_HEADER)
|
211
|
+
# Disallowed by the HTTP spec
|
212
|
+
raise "Response object may not contain both Content-Length and Transfer-Encoding"
|
149
213
|
end
|
150
|
-
headers_output << CRLF
|
151
214
|
if output_body
|
152
|
-
|
153
|
-
|
154
|
-
|
215
|
+
if !body.is_a?(Array) || headers.has_key?(X_SENDFILE_HEADER) ||
|
216
|
+
headers.has_key?(X_ACCEL_REDIRECT_HEADER)
|
217
|
+
# If X-Sendfile or X-Accel-Redirect is set, don't check the
|
218
|
+
# body size. PassengerAgent's RequestHandler will ignore the
|
219
|
+
# body anyway. See
|
220
|
+
# ServerKit::HttpHeaderParser::processParseResult(const HttpParseResponse &)
|
221
|
+
@can_keepalive = false
|
222
|
+
else
|
223
|
+
body_size = 0
|
224
|
+
body.each { |part| body_size += bytesize(part) }
|
225
|
+
if body_size != content_length
|
226
|
+
raise "Response body size doesn't match Content-Length header: #{body_size} vs #{content_length}"
|
227
|
+
end
|
228
|
+
end
|
155
229
|
end
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
230
|
+
elsif headers.has_key?(TRANSFER_ENCODING_HEADER)
|
231
|
+
# App has a Transfer-Encoding header. We assume that the app
|
232
|
+
# has already chunked the body. The headers need no fixing.
|
233
|
+
message_length_type = :chunked_by_app
|
234
|
+
if output_body
|
235
|
+
# We have no way to determine whether the body was correct (save for
|
236
|
+
# parsing the chunking headers), so we don't keep-alive the connection
|
237
|
+
# just to be safe.
|
238
|
+
@can_keepalive = false
|
239
|
+
end
|
240
|
+
if headers.has_key?(CONTENT_LENGTH_HEADER)
|
241
|
+
# Disallowed by the HTTP spec
|
242
|
+
raise "Response object may not contain both Content-Length and Transfer-Encoding"
|
243
|
+
end
|
244
|
+
else
|
245
|
+
# The app has set neither the Content-Length nor the Transfer-Encoding
|
246
|
+
# header. This means we'll have to add one of those headers. We know exactly how
|
247
|
+
# big our body will be, so we can keep-alive the connection.
|
248
|
+
if body.is_a?(Array)
|
249
|
+
message_length_type = :content_length
|
250
|
+
content_length = 0
|
251
|
+
body.each { |part| content_length += bytesize(part.to_s) }
|
252
|
+
|
162
253
|
headers_output << CONTENT_LENGTH_HEADER_AND_SEPARATOR
|
163
|
-
headers_output <<
|
254
|
+
headers_output << content_length.to_s
|
164
255
|
headers_output << CRLF
|
256
|
+
else
|
257
|
+
message_length_type = :needs_chunking
|
258
|
+
headers_output << TRANSFER_ENCODING_HEADER_AND_VALUE_CRLF
|
165
259
|
end
|
260
|
+
end
|
261
|
+
|
262
|
+
# Finalize headers data.
|
263
|
+
if @can_keepalive
|
166
264
|
headers_output << CRLF
|
167
|
-
if output_body
|
168
|
-
headers_output << body
|
169
|
-
end
|
170
|
-
connection.writev(headers_output)
|
171
|
-
false
|
172
265
|
else
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
266
|
+
headers_output << CONNECTION_CLOSE_CRLF2
|
267
|
+
end
|
268
|
+
|
269
|
+
|
270
|
+
# If this is a request without body, write out headers without body.
|
271
|
+
if !output_body
|
272
|
+
connection.writev(headers_output)
|
273
|
+
signal_keep_alive_allowed!
|
274
|
+
return
|
275
|
+
end
|
276
|
+
|
277
|
+
# Otherwise, write out headers and body, then verify at the end whether what
|
278
|
+
# we wrote is matches the message length. Only keep-alive connection if it
|
279
|
+
# is the case.
|
280
|
+
case message_length_type
|
281
|
+
when :content_length
|
282
|
+
if body.is_a?(Array)
|
283
|
+
connection.writev2(headers_output, body)
|
179
284
|
else
|
180
|
-
headers_output
|
285
|
+
connection.writev(headers_output)
|
286
|
+
body.each do |part|
|
287
|
+
connection.write(part.to_s)
|
288
|
+
end
|
181
289
|
end
|
290
|
+
when :chunked_by_app
|
182
291
|
connection.writev(headers_output)
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
connection.write(TERMINATION_CHUNK)
|
193
|
-
else
|
194
|
-
body.each do |s|
|
195
|
-
connection.write(s)
|
196
|
-
end
|
197
|
-
end
|
198
|
-
rescue => e
|
199
|
-
disable_keep_alive
|
200
|
-
if should_reraise_app_error?(e, socket_wrapper)
|
201
|
-
raise e
|
202
|
-
elsif !should_swallow_app_error?(e, socket_wrapper)
|
203
|
-
# Body objects can raise exceptions in #each.
|
204
|
-
print_exception("Rack body object #each method", e)
|
205
|
-
end
|
206
|
-
false
|
292
|
+
body.each do |part|
|
293
|
+
connection.write(part.to_s)
|
294
|
+
end
|
295
|
+
when :needs_chunking
|
296
|
+
connection.writev(headers_output)
|
297
|
+
body.each do |part|
|
298
|
+
size = bytesize(part.to_s)
|
299
|
+
if size != 0
|
300
|
+
connection.writev(chunk_data(part.to_s, size))
|
207
301
|
end
|
208
302
|
end
|
209
|
-
|
303
|
+
connection.write(TERMINATION_CHUNK)
|
210
304
|
end
|
305
|
+
|
306
|
+
signal_keep_alive_allowed!
|
211
307
|
end
|
212
308
|
|
213
309
|
def generate_headers_array(status, headers)
|
@@ -233,33 +329,22 @@ module PhusionPassenger
|
|
233
329
|
return result
|
234
330
|
end
|
235
331
|
|
236
|
-
def perform_keep_alive(env, headers)
|
237
|
-
if @can_keepalive
|
238
|
-
@keepalive_performed = true
|
239
|
-
else
|
240
|
-
headers << CONNECTION_CLOSE_CRLF
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
def disable_keep_alive
|
245
|
-
@keepalive_performed = false
|
246
|
-
end
|
247
|
-
|
248
332
|
def should_output_body?(status, is_head_request)
|
249
333
|
return (status < 100 ||
|
250
334
|
(status >= 200 && status != 204 && status != 205 && status != 304)) &&
|
251
335
|
!is_head_request
|
252
336
|
end
|
253
337
|
|
254
|
-
def should_add_message_length_header?(status, headers)
|
255
|
-
return !headers.has_key?(TRANSFER_ENCODING_HEADER) &&
|
256
|
-
!headers.has_key?(CONTENT_LENGTH_HEADER)
|
257
|
-
end
|
258
|
-
|
259
338
|
def chunk_data(data, size)
|
260
339
|
[size.to_s(16), CRLF, data, CRLF]
|
261
340
|
end
|
262
341
|
|
342
|
+
# Called when body is written out successfully. Indicates that we should
|
343
|
+
# keep-alive the connection if we can.
|
344
|
+
def signal_keep_alive_allowed!
|
345
|
+
@keepalive_performed = @can_keepalive
|
346
|
+
end
|
347
|
+
|
263
348
|
if "".respond_to?(:bytesize)
|
264
349
|
def bytesize(str)
|
265
350
|
str.bytesize
|