passenger 4.0.36 → 4.0.37

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 (41) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/NEWS +51 -0
  5. data/README.md +3 -1
  6. data/build/integration_tests.rb +5 -1
  7. data/build/test_basics.rb +2 -2
  8. data/dev/run_travis.sh +3 -0
  9. data/doc/Users guide Nginx.txt +3 -3
  10. data/ext/common/ApplicationPool2/Group.h +2 -1
  11. data/ext/common/ApplicationPool2/Implementation.cpp +30 -1
  12. data/ext/common/ApplicationPool2/Pool.h +26 -3
  13. data/ext/common/ApplicationPool2/Process.h +39 -10
  14. data/ext/common/Constants.h +1 -1
  15. data/ext/common/MultiLibeio.cpp +4 -0
  16. data/ext/common/ServerInstanceDir.h +1 -1
  17. data/ext/common/Utils.cpp +29 -0
  18. data/ext/common/Utils.h +7 -1
  19. data/ext/common/Utils/BufferedIO.h +13 -0
  20. data/ext/common/agents/HelperAgent/Main.cpp +6 -2
  21. data/ext/common/agents/HelperAgent/RequestHandler.h +32 -1
  22. data/helper-scripts/meteor-loader.rb +126 -10
  23. data/helper-scripts/node-loader.js +5 -3
  24. data/helper-scripts/wsgi-loader.py +23 -11
  25. data/lib/phusion_passenger.rb +1 -1
  26. data/lib/phusion_passenger/config/detach_process_command.rb +96 -0
  27. data/lib/phusion_passenger/config/main.rb +1 -0
  28. data/lib/phusion_passenger/request_handler.rb +11 -4
  29. data/node_lib/phusion_passenger/httplib_emulation.js +20 -14
  30. data/test/cxx/RequestHandlerTest.cpp +80 -0
  31. data/test/integration_tests/apache2_tests.rb +57 -0
  32. data/test/integration_tests/nginx_tests.rb +62 -0
  33. data/test/node/httplib_emulation_spec.js +137 -5
  34. data/test/node/spec_helper.js +13 -0
  35. data/test/stub/node/app.js +125 -0
  36. data/test/stub/node/public/.gitignore +0 -0
  37. data/test/stub/node/tmp/.gitignore +0 -0
  38. data/test/stub/rack/config.ru +19 -0
  39. data/test/stub/wsgi/passenger_wsgi.py +37 -1
  40. metadata +6 -2
  41. metadata.gz.asc +7 -7
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YTQyM2E1ZmM5N2JlM2VlZjY5ZjUwZWUyZTU5NWFlZDZlZWE3NGU0Yg==
4
+ NzY2YjMwZGFkMjkzNDNlMjgwYWIwZjM0OTk4OTEzZDczYmNhZTUxNw==
5
5
  data.tar.gz: !binary |-
6
- YWZiMzg5YmI0MDEyOTRhZDBmZTg1ODNjZGRlMjk2MTFjNDgxNWI2Ng==
6
+ NjMwYmQ4ZWM4ZWZkOTc1OWY2NTk0OGFjYTdjYjllZGE0ZWFkMTlhMQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- NDYyNjlkYTdlMjY0ZmM0ODYyODk3NmQ5NjdlZjhiMGE0NjgwMTk2ZTAzNTg1
10
- ZjRkNWEwNmM5M2Y2YzBhZTFkZTllNGVkZWI4YjVlYTU3MGIyNGU3NTEyYmJi
11
- ZjllODk5M2Q0ZjVjOGY4OGQxYzE2NGIzNTEyNmUzZWYzZGIzM2Q=
9
+ ZWY2OGFiZTMxNTMxMmNkZGFhYTQ4Nzk3OWM4MTNlNjJjZGQ1MDkwZTA0ZTNl
10
+ MDY2N2FhOWFkNjdkYWYzYTgzNzMxMmE5ZGMzNjU2MmUwYjA4MDRlMDZmZDg2
11
+ YTk1MTlmMjJmYmI5OWQ0ZjU4YzU5MDI0M2ZkMzU2NGRkNWU5Mzk=
12
12
  data.tar.gz: !binary |-
13
- NTkwMTZmMzIzNWM1YTk3NTA1NTMzYmZjNGZmNjc5ZmY0MTQ2NGNiZmQxYTI2
14
- MGFlNjMzZGE0YTE5NWQxNjhlYjA0NmY2NzQzNDc0NTU3ZTVmOTk0OGFmNDdl
15
- YWU1MTc0Y2UxZTkxMjMyY2UxMjFlMTdjZmQ2OTg0OTEyM2Y3NzQ=
13
+ ODFhMDg0OWU1YmY2MjRiNWZjYjFkY2ZjN2MwMTZhYjA5YmNjM2E3ZDMwNTMx
14
+ M2ExZDYxZGQyNWQ2ZjFjNzA4MDhjZjIzMzA5YTQyN2E1MjVmOTQyMzU4YzBi
15
+ OGM2NDliMWNkMjQwYTBhYmFhNzhmZTZkNTUyMTVjMWE2Nzc3NTM=
@@ -2,11 +2,11 @@
2
2
  Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
3
3
  Comment: GPGTools - http://gpgtools.org
4
4
 
5
- iQEcBAABAgAGBQJS4syLAAoJECrHRaUKISqMsVsIAIfwEwJO7MHIz8Q1ct4QuKHC
6
- Ll99P56zwQ/trV4PyAEDC1NB9cpbf85vzA+45hlFx6iMqN9oLA33eQVoVvKtI3qG
7
- lBtC4SIdWRvQZBoBhTgDjmzDzGGc3UHtc9siAaxty7a2vkGZBqKXpX/okS6DYAV0
8
- TfoH8ImWg/2qBVFffKLv2ApRcMcjXdh+C0rGtLOTzU4AiTrIlFytQkDBZuMtsZOp
9
- B2jHoLhyzzZ1ZHkUpxMDA2S9jiLbzh+MQ93/kNe1eDa6WH7Gz1Z9GXGNSwo1behJ
10
- b9gp40pdnIxFFuPphiRevfrcCEprGi7a2s5q3sdYF7UVNRQBbuyauXUSI4K3a24=
11
- =zcR9
5
+ iQEcBAABAgAGBQJS6CPIAAoJECrHRaUKISqMBzMIAJc+WtmkHIzclF/yuMagWa40
6
+ 0p9dz6CINEmYQ4gCabMeRhBa/VeQauXhvR3d2cm7TyCyLqfoN6YLHnesVwGGI2vu
7
+ Kt5HbgOYGTT6cyf8QmGjubNC+VslKTZIyoapRigRRtX10tLsvAYyC9WnaOMGikWS
8
+ OKpNucWMA7UnXfsfyNa/u4L0c+pNI15DM5asjMPG46QHiYDfAKIhRzGTRovjBAOW
9
+ WaLu+qtfMJ9ui261i9KBJuPjIbbIeHZQeGDA70tvnm6na5W8A11XilYav4T8Qcv+
10
+ fGoDcJ88M6q3cYspeOJPsEEICFHvhjQ0wMm5qT/YHhLd1dqxapCidmj+nqFwxuQ=
11
+ =6pys
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
- iQEcBAABAgAGBQJS4syKAAoJECrHRaUKISqM92QH/2/DJsZccgKyRyhPpBF8Bl41
6
- zhKzJTnxddS7Q/qd5N+NL1Xqp3+P0crS8CHHV+QNjZh6jXWBBGe+1Ftcp3TZGxpw
7
- EYFzDkX8bIQQ83RxwCYah2Vj/uGuy7XKlDk0kEMSNeLlVOmBWR1yi78DomFJzcXc
8
- wPsvwRr8ZYr3++2o61LeReEhPjNSMb+tlzb3sIDrKsAMx9B0012RGFc8t9bb2Qny
9
- 9bTmJSKj8cwCBmyFvvM+Dh6wfse3wCHT6/rH0n7K40l85NNftidwUI0zhYUC3/8H
10
- Y7TcFqFBq5NzNrYlMcsyzsteePOd5HW7c6NSiGIuu6zFfLGEETWP5W5fdsps6ok=
11
- =4drC
5
+ iQEcBAABAgAGBQJS6CPIAAoJECrHRaUKISqMvrEIAKw15y9cgHaX26Mh6AYj+Bj1
6
+ jQ2aTpVBoNwhxX6dGEvLhpxxknTmvaryffRxYJX7eE8JJKP526RzJogkbgBMktqY
7
+ vxSRNSzpZpvoEztvpiy+UGVtgaUjTEaIFl9daOQbWxQkiLmvglRPMBFu7j30fU9B
8
+ 56vdqzGxqZ9eSHMqd3B+kVSnpoiVOgRCigVocU/hoblLBDankxuzNkj6tAtlX+G3
9
+ zmX0QZ+QBfWDqEvw2mVbXIQFwz9+tMCnybEctz5VJIPHaO8cco129jXYo+hcdu1Q
10
+ EUlt3bcb0/w7a2giU2WuzYdRJqQFdTF24XOOwLozx0Kf8HizpQCU7dJaz3hE79E=
11
+ =0LER
12
12
  -----END PGP SIGNATURE-----
data/NEWS CHANGED
@@ -1,3 +1,54 @@
1
+ Release 4.0.37
2
+ --------------
3
+
4
+ * Improved Node.js compatibility. Calling on() on the request object
5
+ now returns the request object itself. This fixes some issues with
6
+ Express, Connect and Formidable. Furthermore, some WebSocket-related
7
+ issues have been fixed.
8
+ * Improved Meteor support. Meteor application processes are now shut down
9
+ quicker. Previously, they linger around for 5 seconds while waiting for
10
+ all connections to terminate, but that didn't work well because WebSocket
11
+ connections were kept open indefinitely. Also, some WebSocket-related
12
+ issues have been fixed.
13
+ * Introduced a new tool `passenger-config detach-process` for gracefully
14
+ detaching an application process from the process pool. Has a similar
15
+ effect to killing the application process directly with `kill <PID>`,
16
+ but killing directly may cause the HTTP client to see an error, while
17
+ using this command guarantees that clients see no errors.
18
+ * Fixed a crash occurs when an application fails to spawn, but the HTTP
19
+ client disconnects before the error page is generated. Fixes issue #1028.
20
+ * Fixed a symlink-related security vulnerability.
21
+
22
+ Urgency: low
23
+ Scope: local exploit
24
+ Summary: writing files to arbitrary directory by hijacking temp directories
25
+ Affected versions: 4.0.5 and later
26
+ Fixed versions: 4.0.37
27
+
28
+ Description:
29
+ Phusion Passenger creates a "server instance directory" in /tmp during startup,
30
+ which is a temporary directory that Phusion Passenger uses to store working files.
31
+ This directory is deleted after Phusion Passenger exits. For various technical
32
+ reasons, this directory must have a semi-predictable filename. If a local attacker
33
+ can predict this filename, and precreates a symlink with the same filename that
34
+ points to an arbitrary directory with mode 755, owner root and group root, then
35
+ the attacker will succeed in making Phusion Passenger write files and create
36
+ subdirectories inside that target directory. The following files/subdirectories
37
+ are created:
38
+
39
+ * control_process.pid
40
+ * generation-X, where X is a number.
41
+
42
+ If you happen to have a file inside the target directory called `control_process.pid`,
43
+ then that file's contents are overwritten.
44
+
45
+ These files and directories are deleted during Phusion Passenger exit. The target
46
+ directory itself is not deleted, nor are any other contents inside the target
47
+ directory, although the symlink is.
48
+
49
+ Thanks go to Jakub Wilk for discovering this issue.
50
+
51
+
1
52
  Release 4.0.36
2
53
  --------------
3
54
 
data/README.md CHANGED
@@ -4,9 +4,11 @@
4
4
 
5
5
  What makes it so fast and reliable is its **C++** core, its **zero-copy** architecture, its **watchdog** system and its **hybrid** evented, multi-threaded and multi-process design.
6
6
 
7
+ <a href="http://vimeo.com/phusionnl/review/80475623/c16e940d1f"><img src="http://blog.phusion.nl/wp-content/uploads/2014/01/gameofthrones.jpg" height="300"></a><br><em>Phusion Passenger used in Game of Thrones Ascention</em>
8
+
7
9
  **Learn more:** [Website](https://www.phusionpassenger.com/) | [Documentation](https://www.phusionpassenger.com/documentation_and_support) | [Support resources](https://www.phusionpassenger.com/documentation_and_support) | [Github](https://github.com/phusion/passenger) | [Twitter](https://twitter.com/phusion_nl) | [Blog](http://blog.phusion.nl/)
8
10
 
9
- <center><img src="http://blog.phusion.nl/wp-content/uploads/2012/07/Passenger_chair_256x256.jpg" width="160" height="160" alt="Phusion Passenger"></center>
11
+ <a href="https://www.phusionpassenger.com"><center><img src="http://blog.phusion.nl/wp-content/uploads/2012/07/Passenger_chair_256x256.jpg" width="160" height="160" alt="Phusion Passenger"></center></a>
10
12
 
11
13
  ## Installation
12
14
 
@@ -59,7 +59,11 @@ task 'test:integration:nginx' => dependencies do
59
59
  require 'shellwords'
60
60
  command << " -e #{Shellwords.escape(grep)}"
61
61
  end
62
- sh "cd test && exec #{command}"
62
+ repeat = true
63
+ while repeat
64
+ sh "cd test && exec #{command}"
65
+ repeat = boolean_option('REPEAT')
66
+ end
63
67
  end
64
68
  end
65
69
 
@@ -1,5 +1,5 @@
1
1
  # Phusion Passenger - https://www.phusionpassenger.com/
2
- # Copyright (c) 2010-2013 Phusion
2
+ # Copyright (c) 2010-2014 Phusion
3
3
  #
4
4
  # "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
5
5
  #
@@ -77,6 +77,6 @@ task 'test:install_deps' do
77
77
  end
78
78
  end
79
79
  if boolean_option('NODE_MODULES', default)
80
- sh "npm install mocha should sinon"
80
+ sh "npm install mocha should sinon express"
81
81
  end
82
82
  end
@@ -111,6 +111,7 @@ fi
111
111
 
112
112
  if [[ "$TEST_NGINX" = 1 ]]; then
113
113
  install_base_test_deps
114
+ install_node_and_modules
114
115
  run ./bin/passenger-install-nginx-module --auto --prefix=/tmp/nginx --auto-download
115
116
  run rake test:integration:nginx
116
117
  fi
@@ -120,6 +121,7 @@ if [[ "$TEST_APACHE2" = 1 ]]; then
120
121
  run sudo apt-get install -y --no-install-recommends \
121
122
  apache2-mpm-worker apache2-threaded-dev
122
123
  install_base_test_deps
124
+ install_node_and_modules
123
125
  run ./bin/passenger-install-apache2-module --auto #--no-update-config
124
126
  run rvmsudo ./bin/passenger-install-apache2-module --auto --no-compile
125
127
  run rake test:integration:apache2
@@ -137,6 +139,7 @@ if [[ "$TEST_DEBIAN_PACKAGING" = 1 ]]; then
137
139
  ruby1.8 ruby1.8-dev ruby1.9.1 ruby1.9.1-dev rubygems libev-dev gdebi-core \
138
140
  source-highlight
139
141
  install_test_deps_with_doctools
142
+ install_node_and_modules
140
143
  run rake debian:dev debian:dev:reinstall
141
144
  run rake test:integration:native_packaging SUDO=1
142
145
  run env PASSENGER_LOCATION_CONFIGURATION_FILE=/usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini \
@@ -561,9 +561,9 @@ server {
561
561
  ==== passenger_ruby <filename>
562
562
  The `passenger_ruby` option allows one to specify the Ruby interpreter to use. Similarly, the `passenger_python` and `passenger_nodejs` options are for specifying the Python interpreter and Node.js commands, respectively.
563
563
 
564
- In versions prior to 4.0.0, only a single Ruby version was supported for the entire Nginx instance, so `passenger_ruby` may only occur in the global server configuration. Also, the `passenger_python` option was not supported.
564
+ In versions prior to 4.0.0, only a single Ruby version was supported for the entire Nginx instance, so `passenger_ruby` may only occur in the global server configuration. Also, the `passenger_python`/`passenger_nodejs` options were not supported.
565
565
 
566
- Since version 4.0.0, the `passenger_python` option was added. Also, Phusion Passenger supports multiple Ruby or Python interpreters in the same Nginx instance. And so, since version 4.0.0, this option may occur in the following places:
566
+ Since version 4.0.0, Phusion Passenger supports multiple Ruby interpreters in the same Nginx instance. And so, since version 4.0.0, this option may occur in the following places:
567
567
 
568
568
  * In the 'http' configuration block.
569
569
  * In a 'server' configuration block.
@@ -574,7 +574,7 @@ The `passenger_ruby` in the `http` block - that is, the one that `passenger-inst
574
574
 
575
575
  The `passenger_ruby` directive in the `http` block is also used as the default Ruby interpreter for Ruby web apps. You don't *have* to specify a `passenger_ruby` in the `http` block though, because the default is to use the first `ruby` command found in `$PATH`.
576
576
 
577
- The `passenger_python` and `passenger_nodejs` options works in a similar manner, but apply to Python and Node.js instead.
577
+ The `passenger_python` and `passenger_nodejs` options work in a similar manner, but apply to Python and Node.js instead.
578
578
 
579
579
  You can also override `passenger_ruby` and other directives in specific contexts if you want to use a different interpreter for that web app. For example:
580
580
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2011-2013 Phusion
3
+ * Copyright (c) 2011-2014 Phusion
4
4
  *
5
5
  * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  *
@@ -510,6 +510,7 @@ public:
510
510
  } else if (&destination == &detachedProcesses) {
511
511
  assert(process->isAlive());
512
512
  process->enabled = Process::DETACHED;
513
+ process->abortLongRunningConnections();
513
514
  } else {
514
515
  P_BUG("Unknown destination list");
515
516
  }
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2011-2013 Phusion
3
+ * Copyright (c) 2011-2014 Phusion
4
4
  *
5
5
  * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  *
@@ -35,6 +35,7 @@
35
35
  #include <Exceptions.h>
36
36
  #include <MessageReadersWriters.h>
37
37
  #include <Utils/ScopeGuard.h>
38
+ #include <Utils/MessageIO.h>
38
39
 
39
40
  namespace Passenger {
40
41
  namespace ApplicationPool2 {
@@ -1225,12 +1226,40 @@ Group::generateSecret(const SuperGroupPtr &superGroup) {
1225
1226
  }
1226
1227
 
1227
1228
 
1229
+ PoolPtr
1230
+ Process::getPool() const {
1231
+ assert(getLifeStatus() != DEAD);
1232
+ return getGroup()->getPool();
1233
+ }
1234
+
1228
1235
  SuperGroupPtr
1229
1236
  Process::getSuperGroup() const {
1230
1237
  assert(getLifeStatus() != DEAD);
1231
1238
  return getGroup()->getSuperGroup();
1232
1239
  }
1233
1240
 
1241
+ void
1242
+ Process::sendAbortLongRunningConnectionsMessage(const string &address) {
1243
+ boost::function<void ()> func = boost::bind(
1244
+ realSendAbortLongRunningConnectionsMessage, address);
1245
+ return getPool()->nonInterruptableThreads.create_thread(
1246
+ boost::bind(runAndPrintExceptions, func, false),
1247
+ "Sending detached message to process " + toString(pid),
1248
+ 256 * 1024);
1249
+ }
1250
+
1251
+ void
1252
+ Process::realSendAbortLongRunningConnectionsMessage(string address) {
1253
+ TRACE_POINT();
1254
+ FileDescriptor fd(connectToServer(address));
1255
+ unsigned long long timeout = 3000000;
1256
+ vector<string> args;
1257
+
1258
+ UPDATE_TRACE_POINT();
1259
+ args.push_back("abort_long_running_connections");
1260
+ writeArrayMessage(fd, args, &timeout);
1261
+ }
1262
+
1234
1263
  string
1235
1264
  Process::inspect() const {
1236
1265
  assert(getLifeStatus() != DEAD);
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2011-2013 Phusion
3
+ * Copyright (c) 2011-2014 Phusion
4
4
  *
5
5
  * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  *
@@ -149,6 +149,7 @@ public:
149
149
 
150
150
  enum LifeStatus {
151
151
  ALIVE,
152
+ PREPARED_FOR_SHUTDOWN,
152
153
  SHUTTING_DOWN,
153
154
  SHUT_DOWN
154
155
  } lifeStatus;
@@ -953,6 +954,7 @@ public:
953
954
  }
954
955
  }
955
956
 
957
+ /** Must be called right after construction. */
956
958
  void initialize() {
957
959
  LockGuard l(syncher);
958
960
  interruptableThreads.create_thread(
@@ -972,10 +974,31 @@ public:
972
974
  debugSupport = boost::make_shared<DebugSupport>();
973
975
  }
974
976
 
975
- void destroy() {
977
+ /** Should be called right after the HelperAgent has received
978
+ * the message to exit gracefully. This will tell processes to
979
+ * abort any long-running connections, e.g. WebSocket connections,
980
+ * because the RequestHandler has to wait until all connections are
981
+ * finished before proceeding with shutdown.
982
+ */
983
+ void prepareForShutdown() {
976
984
  TRACE_POINT();
977
985
  ScopedLock lock(syncher);
978
986
  assert(lifeStatus == ALIVE);
987
+ lifeStatus = PREPARED_FOR_SHUTDOWN;
988
+ vector<ProcessPtr> processes = getProcesses(false);
989
+ foreach (ProcessPtr process, processes) {
990
+ if (process->abortLongRunningConnections()) {
991
+ // Ensure that the process is not immediately respawned.
992
+ process->getGroup()->options.minProcesses = 0;
993
+ }
994
+ }
995
+ }
996
+
997
+ /** Must be called right before destruction. */
998
+ void destroy() {
999
+ TRACE_POINT();
1000
+ ScopedLock lock(syncher);
1001
+ assert(lifeStatus == ALIVE || lifeStatus == PREPARED_FOR_SHUTDOWN);
979
1002
 
980
1003
  lifeStatus = SHUTTING_DOWN;
981
1004
 
@@ -1004,7 +1027,7 @@ public:
1004
1027
  void asyncGet(const Options &options, const GetCallback &callback, bool lockNow = true) {
1005
1028
  DynamicScopedLock lock(syncher, lockNow);
1006
1029
 
1007
- assert(lifeStatus == ALIVE);
1030
+ assert(lifeStatus == ALIVE || lifeStatus == PREPARED_FOR_SHUTDOWN);
1008
1031
  verifyInvariants();
1009
1032
  P_TRACE(2, "asyncGet(appGroupName=" << options.getAppGroupName() << ")");
1010
1033
  vector<Callback> actions;
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2011-2013 Phusion
3
+ * Copyright (c) 2011-2014 Phusion
4
4
  *
5
5
  * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  *
@@ -113,20 +113,21 @@ public:
113
113
  * ## Life time
114
114
  *
115
115
  * A Process object lives until the containing Group calls `detach(process)`,
116
- * which indicates that it wants this Process to should down. This causes
117
- * the Process to enter the `detached() == true` state. Processes in this
118
- * state are stored in the `detachedProcesses` collection in the Group and
119
- * are no longer eligible for receiving requests. They will be removed from
120
- * the Group and destroyed when all of the following applies:
121
- *
122
- * 1. the OS process is gone.
123
- * 2. `sessions == 0`
116
+ * which indicates that it wants this Process to shut down. This causes
117
+ * `signalDetached()` to be called, which may or may not send a message
118
+ * to the process. After this, the Process object is stored in the
119
+ * `detachedProcesses` collection in the Group and are no longer eligible for
120
+ * receiving requests. Once all requests on this Process have finished,
121
+ * `triggerShutdown()` will be called, which will send a message to the
122
+ * process telling it to shut down. Once the process is gone, `cleanup()` is
123
+ * called, and the Process object is removed from the collection.
124
124
  *
125
125
  * This means that a Group outlives all its Processes, a Process outlives all
126
126
  * its Sessions, and a Process also outlives the OS process.
127
127
  */
128
128
  class Process: public boost::enable_shared_from_this<Process> {
129
- private:
129
+ // Actually private, but marked public so that unit tests can access the fields.
130
+ public:
130
131
  friend class Group;
131
132
 
132
133
  /** A mutex to protect access to `lifeStatus`. */
@@ -147,6 +148,9 @@ private:
147
148
  /** The handle inside the associated Group's process priority queue. */
148
149
  PriorityQueue<Process>::Handle pqHandle;
149
150
 
151
+ void sendAbortLongRunningConnectionsMessage(const string &address);
152
+ static void realSendAbortLongRunningConnectionsMessage(string address);
153
+
150
154
  static bool
151
155
  isZombie(pid_t pid) {
152
156
  string filename = "/proc/" + toString(pid) + "/status";
@@ -308,6 +312,7 @@ public:
308
312
  } oobwStatus;
309
313
  /** Caches whether or not the OS process still exists. */
310
314
  mutable bool m_osProcessExists;
315
+ bool longRunningConnectionsAborted;
311
316
  /** Time at which shutdown began. */
312
317
  time_t shutdownStartTime;
313
318
  /** Collected by Pool::collectAnalytics(). */
@@ -346,6 +351,7 @@ public:
346
351
  enabled(ENABLED),
347
352
  oobwStatus(OOBW_NOT_ACTIVE),
348
353
  m_osProcessExists(true),
354
+ longRunningConnectionsAborted(false),
349
355
  shutdownStartTime(0)
350
356
  {
351
357
  SpawnerConfigPtr config;
@@ -408,6 +414,13 @@ public:
408
414
  this->group = group;
409
415
  }
410
416
 
417
+ /**
418
+ * Thread-safe.
419
+ * @pre getLifeState() != DEAD
420
+ * @post result != NULL
421
+ */
422
+ PoolPtr getPool() const;
423
+
411
424
  /**
412
425
  * Thread-safe.
413
426
  * @pre getLifeState() != DEAD
@@ -439,6 +452,22 @@ public:
439
452
  return lifeStatus;
440
453
  }
441
454
 
455
+ bool abortLongRunningConnections() {
456
+ bool sent = false;
457
+ if (!longRunningConnectionsAborted) {
458
+ SocketList::iterator it, end = sockets->end();
459
+ for (it = sockets->begin(); it != end; it++) {
460
+ Socket *socket = &(*it);
461
+ if (socket->name == "control") {
462
+ sendAbortLongRunningConnectionsMessage(socket->address);
463
+ sent = true;
464
+ }
465
+ }
466
+ longRunningConnectionsAborted = true;
467
+ }
468
+ return sent;
469
+ }
470
+
442
471
  bool canTriggerShutdown() const {
443
472
  return getLifeStatus() == ALIVE && sessions == 0;
444
473
  }
@@ -88,7 +88,7 @@
88
88
 
89
89
  #define NGINX_DOC_URL "http://www.modrails.com/documentation/Users%20guide%20Nginx.html"
90
90
 
91
- #define PASSENGER_VERSION "4.0.36"
91
+ #define PASSENGER_VERSION "4.0.37"
92
92
 
93
93
  #define POOL_HELPER_THREAD_STACK_SIZE 262144
94
94