passenger 5.0.2 → 5.0.3

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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- N2JiN2YxMTU2OTZmZTQzMzIwMTk1MWM4ZGZkYzZlZmJmMjdiZTM3NA==
4
+ YjRiYzNlNmYwZDQ5OGQ5MjJhMmE2MjM2MDE5M2M1YTBmMWVjNzAyOQ==
5
5
  data.tar.gz: !binary |-
6
- YWQ0YzJmMDg0MzMwYzBkOGQwZjExYWIzMjA1ZGM4MTAxMDE5NDNkZQ==
6
+ OTBjODU4Yjg5OTUzOGJlMzIxOGE5YjVmODY5ZTFhOGUzMGM3MmI0OQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ZGZhMjdiMTZhYTk1MDRiMTYxNTlhMjhiZjNmZDI3OTBmYWZkZmEzM2ZkMDY5
10
- ZTU4MDRmZWU1NjdiOTYxZjk2OGM0YmE3ZmZkNzU2YjRmZGIwMzI1M2UxYmU2
11
- YTBmYWEyNzdlZWYzMzQ0YzczYmRiNjcwYTVjMDQzMTVjNjBiMmM=
9
+ YTEyMmZkOWViYjU4YjNkNzA3M2VkNjA1MTgzMTdmMzUxYjc2MjlhYTA1MGM1
10
+ N2YzYWE3NjllZjcwNjQ5MjcxYTEyMWRkZDdhYzZmMWFiODJjMzU3ZGE0NTJk
11
+ OWY0OGU0MDU4ZTc5NWY5NTg5MmJlZDBiODJkYTQ4Y2M1MDVhMzU=
12
12
  data.tar.gz: !binary |-
13
- MzliMDhiMjI5MzM2NTZjNmUwYmQ4MWVhNmZiY2EwYTczNGY0NzI1YzAwMzQ4
14
- MmQwZTQwZTI0Y2U2NjBiY2ZmZGQzZTI1YmVjN2MzMjNkNTUwOTk0NDJiZTI3
15
- ZThhZTk0MzFjODY2NjQ1NWFlMzBiOTkwZWM0NTNmYmI4MjljYzY=
13
+ YTY0NWM0M2FmOWU1ZDVmZjJkNjhmZDE4MThkNjM1YjNhNTNiNzcxZDU2MzRm
14
+ OGFiOTZiODBmMjJjMjMwOGJkZjliOTA3Mzg5OGE3N2E3ODNmNmZmNGEzMjI5
15
+ MDMyZDYwYWJiYzI4MDI4YmMwMzRjYmQwYzA4NTlmODE2YzVjZmY=
@@ -2,11 +2,11 @@
2
2
  Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
3
3
  Comment: GPGTools - http://gpgtools.org
4
4
 
5
- iQEcBAABAgAGBQJU+skQAAoJECrHRaUKISqMCYEIALFilhp8+SVXIUbPuDbRWt+0
6
- V8JijFYyXw1Jiy5VFW5V20Zu70okzRXd9V+u3UvgdRkftqrIPsp4b+vW18pAeg4i
7
- Gse7Wjr53xMvNthIZKqC0BY6zi9FurzkgP4r0hkd2cLmcjB53NNui7nPuYt9mMwH
8
- +WplJeAazcISRhQRJnlBLMDrVWesgJMj+xP/8SaKGsIYfVju8m78TI+hl0X+XT0T
9
- qt9zZDLRd7EpJUS5BovYAFiU7ljLXeFt9bmvN23kZ1MB49GpaPe9hA9L8pRhZmOT
10
- 7oyLImaMKFprjwL+vPS8JYM0b+NVYkT1ALki08yEoKIpwtnujkNFr6KpHAyGSFc=
11
- =o0Sc
5
+ iQEcBAABAgAGBQJVAMF1AAoJECrHRaUKISqMDSsH/0xm2Y70Fr8iahHgf2MSe/bv
6
+ jKAkjl+MqArHlEcAskMRSwYoOJRRTbAYF8R7WxAJERnpCEa1a9l1bVO3DMCprDD7
7
+ by1xGn2FW2WWcsQcWjPNSeTgdII7qPtxk3AJ9KTP8PEoxMjzZKpBzCxHiwOTJ64t
8
+ 7AAGqEJ5Cr8zFq17NA9Lm9h8wvk7uop5ejmGJmgaOAcxtzowSXhGmN37C1yGGVWI
9
+ wUl5d2etK8vRry7T+bxL8eTn8e4fmcJXjk/Jq7Bq35YSR6lhUwPT/5GBe7ENrR4s
10
+ 0E7sOLTuROhGsKpJ0SFvkSiywS/rldjxut1wzjDWmmB6tnEb4gdtZ4JuWHuDPPQ=
11
+ =bM1v
12
12
  -----END PGP SIGNATURE-----
data.tar.gz.asc CHANGED
@@ -2,11 +2,11 @@
2
2
  Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
3
3
  Comment: GPGTools - http://gpgtools.org
4
4
 
5
- iQEcBAABAgAGBQJU+skQAAoJECrHRaUKISqM3w8IALm2kOp7hWd1Qy4mvAl7czSb
6
- b+V/QGy14Mlt+v24GIuVjl88CaX4qA3eHGzsBNb807+L3pc/PYPi7qd0pf0hEN6x
7
- kL730RkjnSFvpuLE37kuemtStVUKHnO8jxMbGWMUZEdEOLThw4LkeDKJPAjm2M2V
8
- dWuHzzdFsA3tb79dy6dL8SSkpqwpfHhpeCdHbgZXhMq+PhllCieeICuwBvZeSOvE
9
- mOwAqt5Toq1KNoKPE/gOPiywGsNQgLYn6HXYTuHrCz/p8YMjJOiTEMODTJD4io4V
10
- cF6byuXfikIouVBgkZQYbwuItMlpJr9e4oZidjBZ7trFmqOT1FnnFiMUehsaHzw=
11
- =h4HJ
5
+ iQEcBAABAgAGBQJVAMF1AAoJECrHRaUKISqMYNMIAK47UJTr5fLogoJ8+cF++oT4
6
+ jIyexyKyXXlySoUHBFBwSikqAWrpVnZPCDu4ULUHSTDPHy/jkcfcC6LYzmtq0AiN
7
+ NagWHqhtklUNgBoWUfv4rEg05hoZOUbFNysp2zbcQvqFEjhmNUONXnWzOgd1UMIC
8
+ wNxZVHxnVpmmnDqc0zfE4CTTcSSc98BLMX3xaWP3bzKHFuM0UvXczTdcgdnhOxrf
9
+ +wJ7Fp8i2YA7yADEYp8aMX1jUIB/UuhTQ5qjG+4whpMfGQvDqJpmh2Z9lolQPxv/
10
+ skt34/MboC5CuRq1jpJ40kU3P5XqY5XKe5sWdlC0z3lhiTXNcUA5hvOB1ZOIukc=
11
+ =oRka
12
12
  -----END PGP SIGNATURE-----
data/CHANGELOG CHANGED
@@ -1,8 +1,23 @@
1
+ Release 5.0.3
2
+ -------------
3
+
4
+ * [Standalone] When using the builtin engine, `passenger start` may crash during startup due to an initialization race condition. This has been fixed.
5
+ * [Enterprise] Fixes a bug in passenger-irb. Running passenger-irb without a PID parameter worked, but running it with a PID parameter didn't.
6
+ * Fixes an integer overflow that resulted in a file descriptor leak and stalled client connections. Closes GH-1412.
7
+ * Truncates Passenger source code paths in logs (to 3 chars) to reduce redundant info. Closes GH-1383.
8
+ * Fixes invalid JSON output for non-finite double values (e.g. from the HTTP JSON API). Closes GH-1408.
9
+ * All hooks now set the `PASSENGER_HOOK_NAME` environment variable. This variable is set to the name of the hook that is being called.
10
+ * The Ruby handler no longer tries to call #force_encoding on response body strings, which fixes an incompatibility with apps/libraries that return frozen body strings. Closes GH-1414.
11
+ * If the Ruby handler crashes while processing a Rack response body, it will now no longer stall the connection.
12
+ * Fixes env.SERVER_PORT containing 80 instead of 443 when using https on default port. Closes GH-1421.
13
+ * We now handle errors in the `poll()` system call better. This might fix some crashes during shutdown which manifest on FreeBSD.
14
+
15
+
1
16
  Release 5.0.2
2
17
  -------------
3
18
 
4
19
  * Fixes a connection freeze that could occur when processing large responses. This would manifest itself under the error message "This website is under heavy load" or "Request queue is full, returning an error". Closes GH-1404.
5
- * Debian and Ubuntu packages have been reintroduces.
20
+ * Debian and Ubuntu packages have been reintroduced.
6
21
  * When `passenger-config restart-app` is run interactively, if Passenger is not serving any applications, then the command now prints an error message instead of showing a menu with only a "Cancel" option.
7
22
  * Fixes a compilation problem on FreeBSD 10 (contributed by: clemensg). Closes GH-1401.
8
23
  * [Standalone] Fixes a crash that would occur if you use the `--ctl` parameter.
@@ -249,6 +249,9 @@ TEST_CXX_OBJECTS = {
249
249
  'test/cxx/UtilsTest.o' => %w(
250
250
  test/cxx/UtilsTest.cpp
251
251
  ext/common/Utils.h),
252
+ 'test/cxx/Utils/StrIntUtilsTest.o' => %w(
253
+ test/cxx/Utils/StrIntUtilsTest.cpp
254
+ ext/common/Utils/StrIntUtils.cpp),
252
255
  'test/cxx/IOUtilsTest.o' => %w(
253
256
  test/cxx/IOUtilsTest.cpp
254
257
  ext/common/Utils/IOUtils.h),
@@ -318,10 +318,10 @@ task 'package:sign' do
318
318
  end
319
319
 
320
320
  task 'package:update_homebrew' do
321
- require 'digest/sha1'
321
+ require 'digest/sha2'
322
322
  version = VERSION_STRING
323
- sha1 = File.open("#{PKG_DIR}/passenger-#{version}.tar.gz", "rb") do |f|
324
- Digest::SHA1.hexdigest(f.read)
323
+ sha256 = File.open("#{PKG_DIR}/passenger-#{version}.tar.gz", "rb") do |f|
324
+ Digest::SHA256.hexdigest(f.read)
325
325
  end
326
326
  sh "rm -rf #{homebrew_dir}"
327
327
  sh "git clone git@github.com:phusion/homebrew.git #{homebrew_dir}"
@@ -331,8 +331,8 @@ task 'package:update_homebrew' do
331
331
  formula = File.read("/tmp/homebrew/Library/Formula/passenger.rb")
332
332
  formula.gsub!(/passenger-.+?\.tar\.gz/, "passenger-#{version}.tar.gz") ||
333
333
  abort("Unable to substitute Homebrew formula tarball filename")
334
- formula.gsub!(/^ sha1 .*/, " sha1 '#{sha1}'") ||
335
- abort("Unable to substitute Homebrew formula SHA-1")
334
+ formula.gsub!(/^ sha256 .*/, " sha256 '#{sha256}'") ||
335
+ abort("Unable to substitute Homebrew formula SHA-256")
336
336
  necessary_dirs = ORIG_TARBALL_FILES.call.map{ |filename| filename.split("/").first }.uniq
337
337
  necessary_dirs -= Packaging::HOMEBREW_EXCLUDE
338
338
  necessary_dirs += ["buildout"]
@@ -1242,9 +1242,6 @@ This option may occur in the following places:
1242
1242
 
1243
1243
  In each place, it may be specified at most once. The default value is '300' (5 minutes).
1244
1244
 
1245
- :option: `--max-preloader-idle-time`
1246
- include::users_guide_snippets/alternative_for_flying_passenger.txt[]
1247
-
1248
1245
  ==== passenger_start_timeout <seconds> ====
1249
1246
  :version: 4.0.15
1250
1247
  include::users_guide_snippets/since_version.txt[]
@@ -453,10 +453,11 @@ A lot of information is passed to hook scripts in the form of environment variab
453
453
 
454
454
  Here are some of the environment variables which are passed to all hooks, unless documented otherwise:
455
455
 
456
+ * `PASSENGER_HOOK_NAME`
456
457
  * `PASSENGER_VERSION`
457
458
  * `PASSENGER_PASSENGER_ROOT`
458
- * `PASSENGER_SERVER_INSTANCE_DIR`
459
- * `PASSENGER_GENERATION_PATH`
459
+ * `PASSENGER_INSTANCE_DIR`
460
+ * `PASSENGER_INSTANCE_REGISTRY_DIR`
460
461
 
461
462
  ==== Blocking and concurrency
462
463
 
@@ -114,7 +114,7 @@
114
114
 
115
115
  #define NGINX_DOC_URL "https://www.phusionpassenger.com/documentation/Users%20guide%20Nginx.html"
116
116
 
117
- #define PASSENGER_VERSION "5.0.2"
117
+ #define PASSENGER_VERSION "5.0.3"
118
118
 
119
119
  #define POOL_HELPER_THREAD_STACK_SIZE 262144
120
120
 
@@ -106,6 +106,7 @@ namespace {
106
106
  for (it = options.environment.begin(); it != end; it++) {
107
107
  envvars.push_back(*it);
108
108
  }
109
+ envvars.push_back(make_pair("PASSENGER_HOOK_NAME", options.name));
109
110
  }
110
111
 
111
112
  inline void
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2010-2014 Phusion
3
+ * Copyright (c) 2010-2015 Phusion
4
4
  *
5
5
  * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  *
@@ -42,6 +42,8 @@ AssertionFailureInfo lastAssertionFailure;
42
42
  static bool printAppOutputAsDebuggingMessages = false;
43
43
  static char *logFile = NULL;
44
44
 
45
+ #define TRUNCATE_LOGPATHS_TO_MAXCHARS 3 // set to 0 to disable truncation
46
+
45
47
  void
46
48
  setLogLevel(int value) {
47
49
  _logLevel = value;
@@ -87,16 +89,6 @@ _prepareLogEntry(std::stringstream &sstream, const char *file, unsigned int line
87
89
  char datetime_buf[60];
88
90
  struct timeval tv;
89
91
 
90
- if (startsWith(file, "ext/")) {
91
- file += sizeof("ext/") - 1;
92
- if (startsWith(file, "common/")) {
93
- file += sizeof("common/") - 1;
94
- if (startsWith(file, "ApplicationPool2/")) {
95
- file += sizeof("Application") - 1;
96
- }
97
- }
98
- }
99
-
100
92
  the_time = time(NULL);
101
93
  localtime_r(&the_time, &the_tm);
102
94
  strftime(datetime_buf, sizeof(datetime_buf) - 1, "%F %H:%M:%S", &the_tm);
@@ -106,7 +98,22 @@ _prepareLogEntry(std::stringstream &sstream, const char *file, unsigned int line
106
98
  (unsigned long) (tv.tv_usec / 100) <<
107
99
  " " << std::dec << getpid() << "/" <<
108
100
  std::hex << pthread_self() << std::dec <<
109
- " " << file << ":" << line <<
101
+ " ";
102
+
103
+ if (startsWith(file, "ext/")) { // special reduncancy filter because most code resides in these paths
104
+ file += sizeof("ext/") - 1;
105
+ if (startsWith(file, "common/")) {
106
+ file += sizeof("common/") - 1;
107
+ }
108
+ }
109
+
110
+ if (TRUNCATE_LOGPATHS_TO_MAXCHARS > 0) {
111
+ truncateBeforeTokens(file, "/\\", TRUNCATE_LOGPATHS_TO_MAXCHARS, sstream);
112
+ } else {
113
+ sstream << file;
114
+ }
115
+
116
+ sstream << ":" << line <<
110
117
  " ]: ";
111
118
  }
112
119
 
@@ -1,6 +1,6 @@
1
1
  /*
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
  *
@@ -26,9 +26,12 @@
26
26
  #define _PASSENGER_SERVER_KIT_ACCEPT_LOAD_BALANCER_H_
27
27
 
28
28
  #include <boost/bind.hpp>
29
+ #include <boost/cstdint.hpp>
30
+ #include <boost/config.hpp>
29
31
  #include <oxt/thread.hpp>
30
32
  #include <oxt/macros.hpp>
31
33
  #include <vector>
34
+ #include <limits>
32
35
  #include <cassert>
33
36
  #include <cerrno>
34
37
 
@@ -41,6 +44,7 @@
41
44
 
42
45
  #include <Constants.h>
43
46
  #include <Logging.h>
47
+ #include <Utils.h>
44
48
  #include <Utils/IOUtils.h>
45
49
 
46
50
  namespace Passenger {
@@ -50,6 +54,32 @@ using namespace std;
50
54
  using namespace boost;
51
55
 
52
56
 
57
+ /**
58
+ * Listens for client connections and load balances them to multiple
59
+ * Server objects in a round-robin manner.
60
+ *
61
+ * Normally, the Server class listens for client connections directly.
62
+ * But this is inefficient in multithreaded situations where you are
63
+ * running one Server and event loop per CPU core, that all happen to
64
+ * listen on the same server socket. This is because every time a client
65
+ * connects, all threads wake up, but only one thread will succeed in
66
+ * accept()ing the client.
67
+ *
68
+ * Furthermore, it can also be very easy for threads to become
69
+ * unbalanced. If a burst of clients connect to the server socket,
70
+ * then it is very likely that a single Server accepts all of
71
+ * those clients. This can result in situations where, for example,
72
+ * thread 1 has 40 clients and thread 2 has only 3.
73
+ *
74
+ * The AcceptLoadBalancer solves this problem by being the sole entity
75
+ * that listens on the server socket. All client sockets that it
76
+ * accepts are distributed to all registered Server objects, in a
77
+ * round-robin manner.
78
+ *
79
+ * Inside the "PassengerAgent server", we activate AcceptLoadBalancer
80
+ * only if `server_threads > 1`, which is often the case because
81
+ * `server_threads` defaults to the number of CPU cores.
82
+ */
53
83
  template<typename Server>
54
84
  class AcceptLoadBalancer {
55
85
  private:
@@ -59,15 +89,24 @@ private:
59
89
  struct pollfd pollers[1 + SERVER_KIT_MAX_SERVER_ENDPOINTS];
60
90
  int newClients[ACCEPT_BURST_COUNT];
61
91
 
62
- unsigned int nEndpoints: 2;
63
- bool accept4Available: 1;
64
- bool quit: 1;
65
- unsigned int newClientCount: 4;
92
+ unsigned int nEndpoints;
93
+ boost::uint8_t newClientCount;
94
+ boost::uint8_t nextServer;
95
+ bool accept4Available;
96
+ bool quit;
66
97
 
67
- unsigned int nextServer;
68
98
  int exitPipe[2];
69
99
  oxt::thread *thread;
70
100
 
101
+ #if __cplusplus >= 199711L && !defined(BOOST_NO_STATIC_ASSERT)
102
+ static_assert(std::numeric_limits<typeof(nEndpoints)>::max()
103
+ >= SERVER_KIT_MAX_SERVER_ENDPOINTS,
104
+ "nEndpoints's type is too small to accomodate for SERVER_KIT_MAX_SERVER_ENDPOINTS");
105
+ static_assert(std::numeric_limits<typeof(newClientCount)>::max()
106
+ >= ACCEPT_BURST_COUNT,
107
+ "newClientCount's type is too small to accomodate for ACCEPT_BURST_COUNT");
108
+ #endif
109
+
71
110
  void pollAllEndpoints() {
72
111
  pollers[0].fd = exitPipe[0];
73
112
  pollers[0].events = POLLIN;
@@ -75,18 +114,28 @@ private:
75
114
  pollers[i + 1].fd = endpoints[i];
76
115
  pollers[i + 1].events = POLLIN;
77
116
  }
78
- if (poll(pollers, nEndpoints + 1, -1) == -1) {
117
+
118
+ int ret;
119
+ do {
120
+ ret = poll(pollers, nEndpoints + 1, -1) == -1;
121
+ } while (ret == -1 && pollErrnoShouldRetry(errno));
122
+ if (ret == -1) {
79
123
  int e = errno;
80
124
  throw SystemException("poll() failed", e);
81
125
  }
82
126
  }
83
127
 
128
+ bool pollErrnoShouldRetry(int e) const {
129
+ return e == EAGAIN
130
+ || e == EWOULDBLOCK
131
+ || e == EINTR;
132
+ }
133
+
84
134
  bool acceptNewClients(int endpoint) {
85
- unsigned int i;
86
135
  bool error = false;
87
136
  int fd, errcode = 0;
88
137
 
89
- for (i = 0; i < ACCEPT_BURST_COUNT; i++) {
138
+ while (newClientCount < ACCEPT_BURST_COUNT) {
90
139
  fd = acceptNonBlockingSocket(endpoint);
91
140
  if (fd == -1) {
92
141
  error = true;
@@ -94,11 +143,11 @@ private:
94
143
  break;
95
144
  }
96
145
 
97
- newClients[i] = fd;
146
+ P_TRACE(2, "Accepted client file descriptor: " << fd);
147
+ newClients[newClientCount] = fd;
148
+ newClientCount++;
98
149
  }
99
150
 
100
- newClientCount = i;
101
-
102
151
  if (error && errcode != EAGAIN && errcode != EWOULDBLOCK) {
103
152
  P_ERROR("Cannot accept client: " << getErrorDesc(errcode) <<
104
153
  " (errno=" << errcode << "). " <<
@@ -121,6 +170,8 @@ private:
121
170
 
122
171
  for (i = 0; i < newClientCount; i++) {
123
172
  ServerKit::Context *ctx = servers[nextServer]->getContext();
173
+ P_TRACE(2, "Feeding client to server thread " << nextServer <<
174
+ ": file descriptor " << newClients[i]);
124
175
  ctx->libev->runLater(boost::bind(feedNewClient, servers[nextServer],
125
176
  newClients[i]));
126
177
  nextServer = (nextServer + 1) % servers.size();
@@ -182,13 +233,19 @@ private:
182
233
  quit = true;
183
234
  break;
184
235
  }
185
- for (unsigned i = 0; i < nEndpoints; i++) {
236
+
237
+ unsigned int i = 0;
238
+ newClientCount = 0;
239
+
240
+ while (newClientCount < ACCEPT_BURST_COUNT && i < nEndpoints) {
186
241
  if (pollers[i + 1].revents & POLLIN) {
187
242
  if (!acceptNewClients(endpoints[i])) {
188
243
  break;
189
244
  }
190
245
  }
246
+ i++;
191
247
  }
248
+
192
249
  distributeNewClients();
193
250
  }
194
251
  }
@@ -198,10 +255,10 @@ public:
198
255
 
199
256
  AcceptLoadBalancer()
200
257
  : nEndpoints(0),
201
- accept4Available(true),
202
- quit(false),
203
258
  newClientCount(0),
204
259
  nextServer(0),
260
+ accept4Available(true),
261
+ quit(false),
205
262
  thread(NULL)
206
263
  {
207
264
  if (pipe(exitPipe) == -1) {
@@ -248,7 +305,8 @@ public:
248
305
  }
249
306
 
250
307
  void start() {
251
- thread = new oxt::thread(boost::bind(&AcceptLoadBalancer<Server>::mainLoop, this),
308
+ boost::function<void ()> func = boost::bind(&AcceptLoadBalancer<Server>::mainLoop, this);
309
+ thread = new oxt::thread(boost::bind(runAndPrintExceptions, func, true),
252
310
  "Load balancer");
253
311
  }
254
312
 
@@ -632,6 +632,7 @@ protected:
632
632
 
633
633
  virtual void reinitializeClient(Client *client, int fd) {
634
634
  client->setConnState(Client::ACTIVE);
635
+ SKC_TRACE(client, 2, "Client associated with file descriptor: " << fd);
635
636
  client->input.reinitialize(fd);
636
637
  client->output.reinitialize(fd);
637
638
  }
@@ -870,9 +871,10 @@ public:
870
871
  disconnectedClientCount++;
871
872
 
872
873
  deinitializeClient(c);
874
+ SKC_TRACE(c, 2, "Closing client file descriptor: " << fdnum);
873
875
  try {
874
876
  safelyClose(fdnum);
875
- } catch (SystemException &e) {
877
+ } catch (const SystemException &e) {
876
878
  SKC_WARN(c, "An error occurred while closing the client file descriptor: " <<
877
879
  e.what() << " (errno=" << e.code() << ")");
878
880
  }
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2010-2014 Phusion
3
+ * Copyright (c) 2010-2015 Phusion
4
4
  *
5
5
  * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  *
@@ -110,6 +110,38 @@ splitIncludeSep(const StaticString &str, char sep, vector<StaticString> &output)
110
110
  _splitIncludeSep(str, sep, output);
111
111
  }
112
112
 
113
+ void
114
+ truncateBeforeTokens(const char* str, const char *tokens, int maxBetweenTokens, std::stringstream& sstream) {
115
+ std::string source(str);
116
+
117
+ if (source.empty()) {
118
+ return;
119
+ }
120
+
121
+ string::size_type copyStart, findStart, pos;
122
+ copyStart = 0; // for copying including the last found token
123
+ findStart = 0;
124
+ while ((pos = source.find_first_of(tokens, findStart)) != string::npos) {
125
+ // Determine & limit how many chars between two tokens (or start and first token)
126
+ int copyLen = pos - findStart;
127
+ if (copyLen > maxBetweenTokens) {
128
+ copyLen = maxBetweenTokens;
129
+ }
130
+ // Include token from the previous find (first iteration has no previous)
131
+ if (findStart > 0) {
132
+ copyLen++;
133
+ }
134
+ sstream << source.substr(copyStart, copyLen);
135
+ copyStart = pos;
136
+ findStart = pos + 1;
137
+ }
138
+
139
+ // Copy anything remaining (e.g. when no tokens at all)
140
+ if (copyStart < source.size()) {
141
+ sstream << source.substr(copyStart);
142
+ }
143
+ }
144
+
113
145
  string
114
146
  replaceString(const string &str, const string &toFind, const string &replaceWith) {
115
147
  string::size_type pos = str.find(toFind);
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2010-2014 Phusion
3
+ * Copyright (c) 2010-2015 Phusion
4
4
  *
5
5
  * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  *
@@ -128,6 +128,14 @@ void splitIncludeSep(const StaticString & restrict_ref str,
128
128
  char sep,
129
129
  vector<StaticString> & restrict_ref output);
130
130
 
131
+ /**
132
+ * Each section in str ending with any of the tokens is truncated to a length of maxBetweenTokens.
133
+ * The result is streamed to sstream, including tokens.
134
+ *
135
+ * Example: ("hello/world\\path/Splitter.cpp", "\\/", 3, sstream) results in sstream << "hel/wor\\pat/Splitter.cpp"
136
+ */
137
+ void truncateBeforeTokens(const char* str, const char *tokens, int maxBetweenTokens, std::stringstream& sstream);
138
+
131
139
  /**
132
140
  * Look for 'toFind' inside 'str', replace it with 'replaceWith' and return the result.
133
141
  * Only the first occurence of 'toFind' is replaced.
@@ -204,6 +204,7 @@ uintToString( LargestUInt value,
204
204
  #include <iostream>
205
205
  #include <stdexcept>
206
206
  #include <string.h>
207
+ #include <boost/math/special_functions/fpclassify.hpp>
207
208
 
208
209
  #if _MSC_VER >= 1400 // VC++ 8.0
209
210
  #pragma warning( disable : 4996 ) // disable warning about strdup being deprecated.
@@ -3459,6 +3460,10 @@ std::string valueToString( UInt value )
3459
3460
 
3460
3461
  std::string valueToString( double value )
3461
3462
  {
3463
+ if (!boost::math::isfinite(value)) {
3464
+ return "null";
3465
+ }
3466
+
3462
3467
  char buffer[32];
3463
3468
  #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning.
3464
3469
  sprintf_s(buffer, sizeof(buffer), "%#.16g", value);
@@ -715,9 +715,17 @@ constructHeaderBuffersForResponse(Request *req, struct iovec *buffers,
715
715
  }
716
716
 
717
717
  if (showVersionInHeader) {
718
- PUSH_STATIC_BUFFER("X-Powered-By: " PROGRAM_NAME " " PASSENGER_VERSION "\r\n\r\n");
718
+ #ifdef PASSENGER_IS_ENTERPRISE
719
+ PUSH_STATIC_BUFFER("X-Powered-By: " PROGRAM_NAME " Enterprise " PASSENGER_VERSION "\r\n\r\n");
720
+ #else
721
+ PUSH_STATIC_BUFFER("X-Powered-By: " PROGRAM_NAME " " PASSENGER_VERSION "\r\n\r\n");
722
+ #endif
719
723
  } else {
720
- PUSH_STATIC_BUFFER("X-Powered-By: " PROGRAM_NAME "\r\n\r\n");
724
+ #ifdef PASSENGER_IS_ENTERPRISE
725
+ PUSH_STATIC_BUFFER("X-Powered-By: " PROGRAM_NAME " Enterprise\r\n\r\n");
726
+ #else
727
+ PUSH_STATIC_BUFFER("X-Powered-By: " PROGRAM_NAME "\r\n\r\n");
728
+ #endif
721
729
  }
722
730
 
723
731
  nbuffers = i;
@@ -212,7 +212,11 @@ determineHeaderSizeForSessionProtocol(Request *req,
212
212
  host->start->data + host->size - sep - 1);
213
213
  } else {
214
214
  state.serverName = StaticString(host->start->data, host->size);
215
- state.serverPort = P_STATIC_STRING("80");
215
+ if (req->https) {
216
+ state.serverPort = P_STATIC_STRING("443");
217
+ } else {
218
+ state.serverPort = P_STATIC_STRING("80");
219
+ }
216
220
  }
217
221
  } else {
218
222
  state.serverName = defaultServerName;
@@ -162,12 +162,12 @@ private:
162
162
 
163
163
  if (server->canKeepAlive(req)) {
164
164
  if (httpVersion < 1010) {
165
- // HTTP < 1.1 defaults to "Connection: close"
165
+ // HTTP < 1.1 defaults to "Connection: close", but we want keep-alive
166
166
  PUSH_STATIC_STRING("Connection: keep-alive\r\n");
167
167
  }
168
168
  } else {
169
169
  if (httpVersion >= 1010) {
170
- // HTTP 1.1 defaults to "Connection: keep-alive"
170
+ // HTTP 1.1 defaults to "Connection: keep-alive", but we don't want it
171
171
  PUSH_STATIC_STRING("Connection: close\r\n");
172
172
  }
173
173
  }
@@ -1215,6 +1215,8 @@ reportAgentsInformation(const WorkingObjectsPtr &wo, const vector<AgentWatcherPt
1215
1215
  str = doc.toStyledString();
1216
1216
 
1217
1217
  writeExact(wo->reportFile, str.data(), str.size());
1218
+ close(wo->reportFile);
1219
+ wo->reportFile = -1;
1218
1220
  }
1219
1221
  }
1220
1222
 
@@ -30,7 +30,7 @@ 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.2'
33
+ VERSION_STRING = '5.0.3'
34
34
 
35
35
  PREFERRED_NGINX_VERSION = '1.6.2'
36
36
  NGINX_SHA256_CHECKSUM = 'b5608c2959d3e7ad09b20fc8f9e5bd4bc87b3bc8ba5936a513c04ed8f1391a18'
@@ -1,5 +1,5 @@
1
1
  # Phusion Passenger - https://www.phusionpassenger.com/
2
- # Copyright (c) 2010-2014 Phusion
2
+ # Copyright (c) 2010-2015 Phusion
3
3
  #
4
4
  # "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
5
5
  #
@@ -175,7 +175,12 @@ module PhusionPassenger
175
175
  PhusionPassenger.require_passenger_lib 'platform_info/binary_compatibility'
176
176
  puts PhusionPassenger::PlatformInfo.cxx_binary_compatibility_id
177
177
  when "--version"
178
- puts PhusionPassenger::VERSION_STRING
178
+ if defined?(PhusionPassenger::PASSENGER_IS_ENTERPRISE)
179
+ name = "#{PhusionPassenger::PROGRAM_NAME} Enterprise"
180
+ else
181
+ name = PhusionPassenger::PROGRAM_NAME
182
+ end
183
+ puts "#{name} #{PhusionPassenger::VERSION_STRING}"
179
184
  when "--help"
180
185
  self.class.help
181
186
  else
@@ -84,6 +84,7 @@ module PhusionPassenger
84
84
  begin
85
85
  status, headers, body = @app.call(env)
86
86
  rescue => e
87
+ disable_keep_alive
87
88
  if should_reraise_app_error?(e, socket_wrapper)
88
89
  raise e
89
90
  elsif !should_swallow_app_error?(e, socket_wrapper)
@@ -101,6 +102,9 @@ module PhusionPassenger
101
102
 
102
103
  begin
103
104
  process_body(env, connection, socket_wrapper, status.to_i, headers, body)
105
+ rescue Exception => e
106
+ disable_keep_alive
107
+ raise
104
108
  ensure
105
109
  body.close if body && body.respond_to?(:close)
106
110
  end
@@ -175,7 +179,6 @@ module PhusionPassenger
175
179
  begin
176
180
  if chunk
177
181
  body.each do |part|
178
- part = force_binary(part)
179
182
  size = bytesize(part)
180
183
  if size != 0
181
184
  connection.writev(chunk_data(part, size))
@@ -188,6 +191,7 @@ module PhusionPassenger
188
191
  end
189
192
  end
190
193
  rescue => e
194
+ disable_keep_alive
191
195
  if should_reraise_app_error?(e, socket_wrapper)
192
196
  raise e
193
197
  elsif !should_swallow_app_error?(e, socket_wrapper)
@@ -232,6 +236,10 @@ module PhusionPassenger
232
236
  end
233
237
  end
234
238
 
239
+ def disable_keep_alive
240
+ @keepalive_performed = false
241
+ end
242
+
235
243
  def should_output_body?(status, env)
236
244
  return (status < 100 ||
237
245
  (status >= 200 && status != 204 && status != 205 && status != 304)) &&
@@ -256,18 +264,6 @@ module PhusionPassenger
256
264
  str.size
257
265
  end
258
266
  end
259
-
260
- if "".respond_to?(:force_encoding)
261
- BINARY = "binary".freeze
262
-
263
- def force_binary(str)
264
- str.force_encoding(BINARY)
265
- end
266
- else
267
- def force_binary(str)
268
- str
269
- end
270
- end
271
267
  end
272
268
 
273
269
  end # module Rack
@@ -68,10 +68,9 @@ module PhusionPassenger
68
68
  end
69
69
 
70
70
  def build_daemon_controller_options
71
- if @options[:socket_file]
72
- ping_spec = [:unix, @options[:socket_file]]
73
- else
74
- ping_spec = [:tcp, @options[:address], @options[:port]]
71
+ ping_spec = lambda do
72
+ File.exist?(report_file_path) &&
73
+ File.stat(report_file_path).size > 0
75
74
  end
76
75
 
77
76
  command = ""
@@ -0,0 +1,39 @@
1
+ #include "TestSupport.h"
2
+ #include <Utils/StrIntUtils.h>
3
+
4
+ using namespace Passenger;
5
+ using namespace std;
6
+
7
+ namespace tut {
8
+ struct StrIntUtilsTest {
9
+ };
10
+
11
+ void testTruncate(const char* str, const char *tokens, int maxBetweenTokens, const char* expected) {
12
+ std::stringstream sstream;
13
+ truncateBeforeTokens(str, tokens, maxBetweenTokens, sstream);
14
+ ensure("got [" + sstream.str() + "], expected [" + expected + "]", sstream.str() == expected);
15
+ }
16
+
17
+ DEFINE_TEST_GROUP(StrIntUtilsTest);
18
+
19
+ TEST_METHOD(1) {
20
+ set_test_name("no change should occur");
21
+ testTruncate("", "", 0, "");
22
+ testTruncate("testwithout/tokens", "", 2, "testwithout/tokens");
23
+ testTruncate("", "/", 2, "");
24
+ testTruncate("/", "", 2, "/");
25
+ testTruncate("/", "/", 2, "/");
26
+ testTruncate("hello", "/", 2, "hello");
27
+ testTruncate("/hello", "/", 3, "/hello");
28
+ } TEST_METHOD(2) {
29
+ set_test_name("truncation must not touch begin/end token");
30
+ testTruncate("hello/", "/", 3, "hel/");
31
+ testTruncate("/hello/", "/", 3, "/hel/");
32
+ } TEST_METHOD(3) {
33
+ set_test_name("exact truncation and multiple split tokens");
34
+ testTruncate("hello/world/Main.cpp", "/", 2, "he/wo/Main.cpp");
35
+ testTruncate("hello/world\\Main.cpp", "/\\", 1, "h/w\\Main.cpp");
36
+ testTruncate("hello/world\\Main.cpp", "/", 1, "h/world\\Main.cpp");
37
+ testTruncate("/he/llo/worl/", "/", 3, "/he/llo/wor/");
38
+ }
39
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: passenger
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.2
4
+ version: 5.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Phusion - http://www.phusion.nl/
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-07 00:00:00.000000000 Z
11
+ date: 2015-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -3009,6 +3009,7 @@ files:
3009
3009
  - test/cxx/TestSupport.cpp
3010
3010
  - test/cxx/TestSupport.h
3011
3011
  - test/cxx/UnionStationTest.cpp
3012
+ - test/cxx/Utils/StrIntUtilsTest.cpp
3012
3013
  - test/cxx/UtilsTest.cpp
3013
3014
  - test/cxx/VariantMapTest.cpp
3014
3015
  - test/gdbinit.example
metadata.gz.asc CHANGED
@@ -2,11 +2,11 @@
2
2
  Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
3
3
  Comment: GPGTools - http://gpgtools.org
4
4
 
5
- iQEcBAABAgAGBQJU+skQAAoJECrHRaUKISqM1iIH/A3Ew5qcBlnzwsgcAOA739Qf
6
- aI39zhOeeXUUnqbfyTEJgQzOxbrk6Qz496V7x5tcVRTfRdxFnF+9PNVZwrdYc6/6
7
- viWyR43O6z1r6IG0qbOPDjRByMAqJEz3r0rzHHxUYbNSnxErYzuAvuOz17FfVhri
8
- S78GmvltgdHBdP2nGCr+fFc9MNEgi/2UKYL31/1bJrRJ+j9enkAWwF0mudr9RYxX
9
- pxOV/kOslurXLDfMPCeMZDLNXwY1uLg5FTDmG6ao80wNvV1Z+pQ5vBfsl4t73sxN
10
- TVuscgETgrLuSrIFqant4zIaFPXCXwY+HRyCHDn+S4MqD8l1ydUL0hCfho5780M=
11
- =86O6
5
+ iQEcBAABAgAGBQJVAMF1AAoJECrHRaUKISqMImsIAJTQzyvYQ8pEqJsRuCK2E4aI
6
+ cJCVHsWzz4M1rYG9ICtenTynE8Xahdf1n74sGjmd4cXY67V1b6EUXutOUH1JIa4n
7
+ R/rDSvqvK/Fuj3B8r1Or87HwFqLdMEjCUd08GCGXtERAeswgaoQqXfM05x2V8cdp
8
+ 7UJdo2w0uPjEauDl0AD8lWNEWInTLw61uXkNkjfG04kMDmcgi8ZxK9epBmBjeX88
9
+ byVAoKxOj0vXUCN9LDsJ4p1cQ+URqQPJUS88jBKNSi2S+S7V29CzauSHa/7yLnFK
10
+ JOA55NXHpFfV9XCmeQHvq52bIBp1qfW5Umif0Gjv9v11P0bl3k9neJ1psLKRCZ8=
11
+ =Ycnq
12
12
  -----END PGP SIGNATURE-----