passenger 5.0.25 → 5.0.26

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 (128) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +20 -0
  3. data/CONTRIBUTORS +1 -0
  4. data/build/cxx_dependency_map.rb +7338 -7104
  5. data/build/cxx_tests.rb +3 -3
  6. data/build/misc.rb +1 -0
  7. data/dev/index_cxx_dependencies.rb +3 -2
  8. data/resources/templates/standalone/config.erb +1 -1
  9. data/resources/templates/standalone/http.erb +1 -0
  10. data/resources/templates/standalone/server.erb +1 -0
  11. data/src/agent/Core/ApplicationPool/AbstractSession.h +83 -0
  12. data/src/agent/Core/ApplicationPool/Common.h +6 -4
  13. data/src/agent/Core/ApplicationPool/Options.h +4 -1
  14. data/src/agent/Core/ApplicationPool/Pool.h +2 -2
  15. data/src/agent/Core/ApplicationPool/Pool/AnalyticsCollection.cpp +3 -6
  16. data/src/agent/Core/ApplicationPool/Pool/GeneralUtils.cpp +3 -3
  17. data/src/agent/Core/ApplicationPool/Session.h +15 -27
  18. data/src/agent/Core/ApplicationPool/TestSession.h +188 -0
  19. data/src/agent/Core/Controller.h +15 -6
  20. data/src/agent/Core/Controller/CheckoutSession.cpp +13 -5
  21. data/src/agent/Core/Controller/ForwardResponse.cpp +20 -2
  22. data/src/agent/Core/Controller/Hooks.cpp +15 -2
  23. data/src/agent/Core/Controller/InitRequest.cpp +5 -1
  24. data/src/agent/Core/Controller/InitializationAndShutdown.cpp +1 -0
  25. data/src/agent/Core/Controller/Request.h +11 -4
  26. data/src/agent/Core/Controller/SendRequest.cpp +34 -13
  27. data/src/agent/Core/Controller/StateInspectionAndConfiguration.cpp +2 -2
  28. data/src/agent/Core/CoreMain.cpp +27 -1
  29. data/src/agent/Core/OptionParser.h +11 -1
  30. data/src/agent/Core/SpawningKit/DirectSpawner.h +1 -0
  31. data/src/agent/Core/SpawningKit/SmartSpawner.h +1 -0
  32. data/src/agent/Core/SpawningKit/Spawner.h +21 -1
  33. data/src/agent/SpawnPreparer/SpawnPreparerMain.cpp +1 -1
  34. data/src/agent/UstRouter/OptionParser.h +7 -1
  35. data/src/agent/UstRouter/UstRouterMain.cpp +27 -1
  36. data/src/cxx_supportlib/Algorithms/MovingAverage.h +223 -0
  37. data/src/cxx_supportlib/Constants.h +2 -2
  38. data/src/cxx_supportlib/DataStructures/StringKeyTable.h +96 -40
  39. data/src/cxx_supportlib/ResourceLocator.h +33 -14
  40. data/src/cxx_supportlib/ServerKit/Channel.h +198 -69
  41. data/src/cxx_supportlib/ServerKit/Errors.h +6 -1
  42. data/src/cxx_supportlib/ServerKit/HttpRequest.h +20 -1
  43. data/src/cxx_supportlib/ServerKit/HttpServer.h +124 -32
  44. data/src/cxx_supportlib/ServerKit/Server.h +65 -1
  45. data/src/cxx_supportlib/Utils/IOUtils.cpp +12 -22
  46. data/src/cxx_supportlib/Utils/JsonUtils.h +87 -1
  47. data/src/cxx_supportlib/Utils/StrIntUtils.cpp +16 -1
  48. data/src/cxx_supportlib/Utils/StrIntUtils.h +31 -1
  49. data/src/cxx_supportlib/Utils/VariantMap.h +6 -1
  50. data/src/cxx_supportlib/WatchdogLauncher.h +17 -9
  51. data/src/cxx_supportlib/vendor-copy/libuv/AUTHORS +43 -0
  52. data/src/cxx_supportlib/vendor-copy/libuv/ChangeLog +350 -1
  53. data/src/cxx_supportlib/vendor-copy/libuv/Makefile.am +9 -1
  54. data/src/cxx_supportlib/vendor-copy/libuv/README.md +48 -0
  55. data/src/cxx_supportlib/vendor-copy/libuv/checksparse.sh +1 -0
  56. data/src/cxx_supportlib/vendor-copy/libuv/common.gypi +5 -5
  57. data/src/cxx_supportlib/vendor-copy/libuv/configure.ac +2 -1
  58. data/src/cxx_supportlib/vendor-copy/libuv/gyp_uv.py +0 -3
  59. data/src/cxx_supportlib/vendor-copy/libuv/include/uv-version.h +5 -1
  60. data/src/cxx_supportlib/vendor-copy/libuv/include/uv.h +30 -3
  61. data/src/cxx_supportlib/vendor-copy/libuv/src/fs-poll.c +3 -3
  62. data/src/cxx_supportlib/vendor-copy/libuv/src/inet.c +0 -4
  63. data/src/cxx_supportlib/vendor-copy/libuv/src/queue.h +17 -1
  64. data/src/cxx_supportlib/vendor-copy/libuv/src/threadpool.c +10 -10
  65. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/aix.c +84 -166
  66. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/android-ifaddrs.c +11 -11
  67. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/async.c +7 -1
  68. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/atomic-ops.h +17 -0
  69. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/core.c +140 -21
  70. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/darwin.c +15 -11
  71. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/dl.c +4 -7
  72. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/freebsd.c +52 -37
  73. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/fs.c +181 -60
  74. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/fsevents.c +39 -34
  75. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/getaddrinfo.c +4 -4
  76. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/internal.h +3 -1
  77. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/kqueue.c +12 -4
  78. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-core.c +38 -15
  79. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-inotify.c +36 -8
  80. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-syscalls.c +4 -4
  81. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-syscalls.h +2 -2
  82. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/loop-watcher.c +6 -1
  83. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/loop.c +28 -8
  84. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/netbsd.c +18 -16
  85. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/openbsd.c +18 -16
  86. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/pipe.c +3 -3
  87. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/process.c +18 -6
  88. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/proctitle.c +2 -2
  89. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/pthread-fixes.c +1 -0
  90. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/signal.c +2 -0
  91. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/stream.c +47 -30
  92. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/sunos.c +13 -11
  93. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/tcp.c +43 -8
  94. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/thread.c +21 -15
  95. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/tty.c +16 -2
  96. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/udp.c +54 -14
  97. data/src/cxx_supportlib/vendor-copy/libuv/src/uv-common.c +104 -21
  98. data/src/cxx_supportlib/vendor-copy/libuv/src/uv-common.h +14 -1
  99. data/src/cxx_supportlib/vendor-copy/libuv/src/version.c +1 -5
  100. data/src/cxx_supportlib/vendor-copy/libuv/uv.gyp +22 -1
  101. data/src/nginx_module/CacheLocationConfig.c +52 -0
  102. data/src/nginx_module/CacheLocationConfig.c.erb +13 -1
  103. data/src/nginx_module/Configuration.c +1 -0
  104. data/src/nginx_module/Configuration.h +1 -0
  105. data/src/nginx_module/ConfigurationCommands.c +20 -0
  106. data/src/nginx_module/ConfigurationFields.h +4 -0
  107. data/src/nginx_module/CreateLocationConfig.c +8 -0
  108. data/src/nginx_module/MergeLocationConfig.c +12 -0
  109. data/src/nginx_module/config +31 -13
  110. data/src/nginx_module/ngx_http_passenger_module.c +4 -0
  111. data/src/ruby_supportlib/phusion_passenger.rb +1 -1
  112. data/src/ruby_supportlib/phusion_passenger/constants.rb +1 -1
  113. data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +11 -1
  114. data/src/ruby_supportlib/phusion_passenger/platform_info/apache.rb +6 -1
  115. data/src/ruby_supportlib/phusion_passenger/rack/thread_handler_extension.rb +32 -31
  116. data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +13 -2
  117. data/src/ruby_supportlib/phusion_passenger/standalone/config_utils.rb +1 -0
  118. data/src/ruby_supportlib/phusion_passenger/standalone/start_command/builtin_engine.rb +6 -1
  119. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core.rb +6 -0
  120. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/api.rb +29 -19
  121. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/context.rb +2 -2
  122. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/request_reporter.rb +2 -3
  123. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/simple_json.rb +2 -1
  124. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/spec_helper.rb +2 -0
  125. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/time_point.rb +3 -17
  126. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/transaction.rb +7 -10
  127. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/utils.rb +11 -9
  128. metadata +5 -2
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2011-2015 Phusion Holding B.V.
3
+ * Copyright (c) 2011-2016 Phusion Holding B.V.
4
4
  *
5
5
  * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
6
  * trademarks of Phusion Holding B.V.
@@ -119,6 +119,8 @@ private:
119
119
  typedef ServerKit::FileBufferedChannel FileBufferedChannel;
120
120
  typedef ServerKit::FileBufferedFdSinkChannel FileBufferedFdSinkChannel;
121
121
 
122
+ // If you change this value, make sure that Request::sessionCheckoutTry
123
+ // has enough bits.
122
124
  static const unsigned int MAX_SESSION_CHECKOUT_TRY = 10;
123
125
 
124
126
  unsigned int statThrottleRate;
@@ -218,12 +220,12 @@ private:
218
220
  /****** Stage: checkout session ******/
219
221
 
220
222
  void checkoutSession(Client *client, Request *req);
221
- static void sessionCheckedOut(const SessionPtr &session,
223
+ static void sessionCheckedOut(const AbstractSessionPtr &session,
222
224
  const ExceptionPtr &e, void *userData);
223
225
  void sessionCheckedOutFromAnotherThread(Client *client, Request *req,
224
- SessionPtr session, ExceptionPtr e);
226
+ AbstractSessionPtr session, ExceptionPtr e);
225
227
  void sessionCheckedOutFromEventLoopThread(Client *client, Request *req,
226
- const SessionPtr &session, const ExceptionPtr &e);
228
+ const AbstractSessionPtr &session, const ExceptionPtr &e);
227
229
  void maybeSend100Continue(Client *client, Request *req);
228
230
  void initiateSession(Client *client, Request *req);
229
231
  static void checkoutSessionLater(Request *req);
@@ -261,7 +263,7 @@ private:
261
263
  void sendHeaderToAppWithHttpProtocolWithBuffering(Request *req, unsigned int offset,
262
264
  HttpHeaderConstructionCache &cache);
263
265
  void sendBodyToApp(Client *client, Request *req);
264
- void halfCloseAppSink(Client *client, Request *req);
266
+ void maybeHalfCloseAppSinkBecauseRequestBodyEndReached(Client *client, Request *req);
265
267
  Channel::Result whenSendingRequest_onRequestBody(Client *client, Request *req,
266
268
  const MemoryKit::mbuf &buffer, int errcode);
267
269
  static void resumeRequestBodyChannelWhenAppSinkIdle(Channel *_channel,
@@ -376,10 +378,17 @@ protected:
376
378
  void deinitializeAppResponse(Client *client, Request *req);
377
379
  virtual Channel::Result onRequestBody(Client *client, Request *req,
378
380
  const MemoryKit::mbuf &buffer, int errcode);
381
+ virtual void onNextRequestEarlyReadError(Client *client, Request *req, int errcode);
379
382
  virtual bool shouldDisconnectClientOnShutdown(Client *client);
380
383
  virtual bool supportsUpgrade(Client *client, Request *req);
381
384
 
382
385
 
386
+ /****** Marked virtual so that unit tests can mock these ******/
387
+
388
+ virtual void asyncGetFromApplicationPool(Request *req,
389
+ ApplicationPool2::GetCallback callback);
390
+
391
+
383
392
  public:
384
393
  ResourceLocator *resourceLocator;
385
394
  PoolPtr appPool;
@@ -390,7 +399,7 @@ public:
390
399
 
391
400
  Controller(ServerKit::Context *context, const VariantMap *_agentsOptions,
392
401
  unsigned int _threadNumber = 1);
393
- ~Controller();
402
+ virtual ~Controller();
394
403
  void initialize();
395
404
 
396
405
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2011-2015 Phusion Holding B.V.
3
+ * Copyright (c) 2011-2016 Phusion Holding B.V.
4
4
  *
5
5
  * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
6
  * trademarks of Phusion Holding B.V.
@@ -70,7 +70,7 @@ Controller::checkoutSession(Client *client, Request *req) {
70
70
  #ifdef DEBUG_CC_EVENT_LOOP_BLOCKING
71
71
  req->timeBeforeAccessingApplicationPool = ev_now(getLoop());
72
72
  #endif
73
- appPool->asyncGet(options, callback, true, req->useUnionStation() ? &req->stopwatchLogs.getFromPool : NULL);
73
+ asyncGetFromApplicationPool(req, callback);
74
74
  #ifdef DEBUG_CC_EVENT_LOOP_BLOCKING
75
75
  if (!req->timedAppPoolGet) {
76
76
  req->timedAppPoolGet = true;
@@ -82,7 +82,15 @@ Controller::checkoutSession(Client *client, Request *req) {
82
82
  }
83
83
 
84
84
  void
85
- Controller::sessionCheckedOut(const SessionPtr &session, const ExceptionPtr &e,
85
+ Controller::asyncGetFromApplicationPool(Request *req, ApplicationPool2::GetCallback callback) {
86
+ appPool->asyncGet(req->options, callback, true,
87
+ req->useUnionStation()
88
+ ? &req->stopwatchLogs.getFromPool
89
+ : NULL);
90
+ }
91
+
92
+ void
93
+ Controller::sessionCheckedOut(const AbstractSessionPtr &session, const ExceptionPtr &e,
86
94
  void *userData)
87
95
  {
88
96
  Request *req = static_cast<Request *>(userData);
@@ -101,7 +109,7 @@ Controller::sessionCheckedOut(const SessionPtr &session, const ExceptionPtr &e,
101
109
 
102
110
  void
103
111
  Controller::sessionCheckedOutFromAnotherThread(Client *client, Request *req,
104
- SessionPtr session, ExceptionPtr e)
112
+ AbstractSessionPtr session, ExceptionPtr e)
105
113
  {
106
114
  SKC_LOG_EVENT(Controller, client, "sessionCheckedOutFromAnotherThread");
107
115
  sessionCheckedOutFromEventLoopThread(client, req, session, e);
@@ -110,7 +118,7 @@ Controller::sessionCheckedOutFromAnotherThread(Client *client, Request *req,
110
118
 
111
119
  void
112
120
  Controller::sessionCheckedOutFromEventLoopThread(Client *client, Request *req,
113
- const SessionPtr &session, const ExceptionPtr &e)
121
+ const AbstractSessionPtr &session, const ExceptionPtr &e)
114
122
  {
115
123
  if (req->ended()) {
116
124
  return;
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2011-2015 Phusion Holding B.V.
3
+ * Copyright (c) 2011-2016 Phusion Holding B.V.
4
4
  *
5
5
  * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
6
  * trademarks of Phusion Holding B.V.
@@ -295,6 +295,7 @@ Controller::onAppSourceData(Client *client, Request *req, const MemoryKit::mbuf
295
295
  // EOF
296
296
  UPDATE_TRACE_POINT();
297
297
  SKC_TRACE(client, 2, "Application sent EOF");
298
+ SKC_TRACE(client, 2, "Not keep-aliving application session connection");
298
299
  req->session->close(true, false);
299
300
  endRequest(&client, &req);
300
301
  return Channel::Result(0, false);
@@ -1078,7 +1079,24 @@ Controller::handleAppResponseBodyEnd(Client *client, Request *req) {
1078
1079
 
1079
1080
  OXT_FORCE_INLINE void
1080
1081
  Controller::keepAliveAppConnection(Client *client, Request *req) {
1081
- req->session->close(true, req->appResponse.wantKeepAlive);
1082
+ if (req->halfClosePolicy == Request::HALF_CLOSE_PERFORMED) {
1083
+ SKC_TRACE(client, 2, "Not keep-aliving application session connection"
1084
+ " because it had been half-closed before");
1085
+ req->session->close(true, false);
1086
+ } else {
1087
+ // halfClosePolicy is initialized in sendHeaderToApp(). That method is
1088
+ // called immediately after checking out a session, before any events
1089
+ // from the appSource channel can be received.
1090
+ assert(req->halfClosePolicy != Request::HALF_CLOSE_POLICY_UNINITIALIZED);
1091
+ if (req->appResponse.wantKeepAlive) {
1092
+ SKC_TRACE(client, 2, "Keep-aliving application session connection");
1093
+ req->session->close(true, true);
1094
+ } else {
1095
+ SKC_TRACE(client, 2, "Not keep-aliving application session connection"
1096
+ " because application did not allow it");
1097
+ req->session->close(true, false);
1098
+ }
1099
+ }
1082
1100
  }
1083
1101
 
1084
1102
  void
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2011-2015 Phusion Holding B.V.
3
+ * Copyright (c) 2011-2016 Phusion Holding B.V.
4
4
  *
5
5
  * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
6
  * trademarks of Phusion Holding B.V.
@@ -129,8 +129,8 @@ Controller::reinitializeRequest(Client *client, Request *req) {
129
129
  req->requestBodyBuffering = false;
130
130
  req->https = false;
131
131
  req->stickySession = false;
132
- req->halfCloseAppConnection = false;
133
132
  req->sessionCheckoutTry = 0;
133
+ req->halfClosePolicy = Request::HALF_CLOSE_POLICY_UNINITIALIZED;
134
134
  req->appResponseInitialized = false;
135
135
  req->strip100ContinueHeader = false;
136
136
  req->hasPragmaHeader = false;
@@ -258,6 +258,19 @@ Controller::onRequestBody(Client *client, Request *req, const MemoryKit::mbuf &b
258
258
  }
259
259
  }
260
260
 
261
+ void
262
+ Controller::onNextRequestEarlyReadError(Client *client, Request *req, int errcode) {
263
+ ParentClass::onNextRequestEarlyReadError(client, req, errcode);
264
+ if (req->halfClosePolicy == Request::HALF_CLOSE_UPON_NEXT_REQUEST_EARLY_READ_ERROR) {
265
+ SKC_TRACE(client, 3, "Half-closing application socket with SHUT_WR"
266
+ " because the next request's early read error has been detected: "
267
+ << ServerKit::getErrorDesc(errcode) << " (errno=" << errcode << ")");
268
+ req->halfClosePolicy = Request::HALF_CLOSE_PERFORMED;
269
+ assert(req->session != NULL);
270
+ ::shutdown(req->session->fd(), SHUT_WR);
271
+ }
272
+ }
273
+
261
274
  bool
262
275
  Controller::shouldDisconnectClientOnShutdown(Client *client) {
263
276
  return ParentClass::shouldDisconnectClientOnShutdown(client) || !gracefulExit;
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2011-2015 Phusion Holding B.V.
3
+ * Copyright (c) 2011-2016 Phusion Holding B.V.
4
4
  *
5
5
  * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
6
  * trademarks of Phusion Holding B.V.
@@ -188,6 +188,9 @@ Controller::fillPoolOptionsFromAgentsOptions(Options &options) {
188
188
  if (agentsOptions->has("meteor_app_settings")) {
189
189
  options.meteorAppSettings = agentsOptions->get("meteor_app_settings");
190
190
  }
191
+ if (agentsOptions->has("app_file_descriptor_ulimit")) {
192
+ options.fileDescriptorUlimit = agentsOptions->getUint("app_file_descriptor_ulimit");
193
+ }
191
194
 
192
195
  options.logLevel = getLogLevel();
193
196
  options.integrationMode = agentsOptions->get("integration_mode",
@@ -378,6 +381,7 @@ Controller::createNewPoolOptions(Client *client, Request *req,
378
381
  fillPoolOption(req, options.restartDir, "!~PASSENGER_RESTART_DIR");
379
382
  fillPoolOption(req, options.startupFile, "!~PASSENGER_STARTUP_FILE");
380
383
  fillPoolOption(req, options.loadShellEnvvars, "!~PASSENGER_LOAD_SHELL_ENVVARS");
384
+ fillPoolOption(req, options.fileDescriptorUlimit, "!~PASSENGER_APP_FILE_DESCRIPTOR_ULIMIT");
381
385
  fillPoolOption(req, options.raiseInternalError, "!~PASSENGER_RAISE_INTERNAL_ERROR");
382
386
  /******************/
383
387
 
@@ -143,6 +143,7 @@ Controller::Controller(ServerKit::Context *context, const VariantMap *_agentsOpt
143
143
  }
144
144
 
145
145
  Controller::~Controller() {
146
+ ev_check_stop(getLoop(), &checkWatcher);
146
147
  psg_destroy_pool(stringPool);
147
148
  }
148
149
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2011-2015 Phusion Holding B.V.
3
+ * Copyright (c) 2011-2016 Phusion Holding B.V.
4
4
  *
5
5
  * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
6
  * trademarks of Phusion Holding B.V.
@@ -59,6 +59,13 @@ public:
59
59
  WAITING_FOR_APP_OUTPUT
60
60
  };
61
61
 
62
+ enum HalfClosePolicy {
63
+ HALF_CLOSE_POLICY_UNINITIALIZED,
64
+ HALF_CLOSE_UPON_REACHING_REQUEST_BODY_END,
65
+ HALF_CLOSE_UPON_NEXT_REQUEST_EARLY_READ_ERROR,
66
+ HALF_CLOSE_PERFORMED
67
+ };
68
+
62
69
  ev_tstamp startedAt;
63
70
 
64
71
  State state: 3;
@@ -66,16 +73,16 @@ public:
66
73
  bool requestBodyBuffering: 1;
67
74
  bool https: 1;
68
75
  bool stickySession: 1;
69
- bool halfCloseAppConnection: 1;
70
76
 
71
77
  // Range: 0..MAX_SESSION_CHECKOUT_TRY
72
- boost::uint8_t sessionCheckoutTry;
78
+ boost::uint8_t sessionCheckoutTry: 4;
79
+ HalfClosePolicy halfClosePolicy: 2;
73
80
  bool appResponseInitialized: 1;
74
81
  bool strip100ContinueHeader: 1;
75
82
  bool hasPragmaHeader: 1;
76
83
 
77
84
  Options options;
78
- SessionPtr session;
85
+ AbstractSessionPtr session;
79
86
  const LString *host;
80
87
 
81
88
  ServerKit::FdSinkChannel appSink;
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2011-2015 Phusion Holding B.V.
3
+ * Copyright (c) 2011-2016 Phusion Holding B.V.
4
4
  *
5
5
  * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
6
  * trademarks of Phusion Holding B.V.
@@ -89,19 +89,38 @@ Controller::sendHeaderToApp(Client *client, Request *req) {
89
89
  SKC_TRACE(client, 2, "Sending headers to application with " <<
90
90
  req->session->getProtocol() << " protocol");
91
91
  req->state = Request::SENDING_HEADER_TO_APP;
92
+ P_ASSERT_EQ(req->halfClosePolicy, Request::HALF_CLOSE_POLICY_UNINITIALIZED);
92
93
 
93
- /**
94
- * HTTP does not formally support half-closing, and Node.js treats a
95
- * half-close as a full close, so we only half-close session sockets, not
96
- * HTTP sockets.
97
- */
98
94
  if (req->session->getProtocol() == "session") {
99
95
  UPDATE_TRACE_POINT();
100
- req->halfCloseAppConnection = req->bodyType != Request::RBT_NO_BODY;
96
+ if (req->bodyType == Request::RBT_NO_BODY) {
97
+ // When there is no request body we will try to keep-alive the
98
+ // application connection, so half-close the application
99
+ // connection upon encountering the next request's early error
100
+ // in order not to break the keep-alive.
101
+ req->halfClosePolicy = Request::HALF_CLOSE_UPON_NEXT_REQUEST_EARLY_READ_ERROR;
102
+ } else {
103
+ // When there is a request body we won't try to keep-alive
104
+ // the application connection, so it's safe to half-close immediately
105
+ // upon reaching the end of the request body.
106
+ req->halfClosePolicy = Request::HALF_CLOSE_UPON_REACHING_REQUEST_BODY_END;
107
+ }
101
108
  sendHeaderToAppWithSessionProtocol(client, req);
102
109
  } else {
103
110
  UPDATE_TRACE_POINT();
104
- req->halfCloseAppConnection = false;
111
+ if (req->bodyType == Request::RBT_UPGRADE) {
112
+ req->halfClosePolicy = Request::HALF_CLOSE_UPON_REACHING_REQUEST_BODY_END;
113
+ } else {
114
+ // HTTP does not formally support half-closing. Some apps support
115
+ // HTTP with half-closing, others (such as Node.js http.Server with
116
+ // default settings) treat a half-close as a full close. Furthermore,
117
+ // we always try to keep-alive the application connection.
118
+ //
119
+ // So we can't half-close immediately upon reaching the end of the
120
+ // request body. The app might not have yet sent a response by then.
121
+ // We only half-close upon the next request's early error.
122
+ req->halfClosePolicy = Request::HALF_CLOSE_UPON_NEXT_REQUEST_EARLY_READ_ERROR;
123
+ }
105
124
  sendHeaderToAppWithHttpProtocol(client, req);
106
125
  }
107
126
 
@@ -944,15 +963,17 @@ Controller::sendBodyToApp(Client *client, Request *req) {
944
963
  // data is forwarded.
945
964
  SKC_TRACE(client, 2, "No body to send to application");
946
965
  req->state = Request::WAITING_FOR_APP_OUTPUT;
947
- halfCloseAppSink(client, req);
966
+ maybeHalfCloseAppSinkBecauseRequestBodyEndReached(client, req);
948
967
  }
949
968
  }
950
969
 
951
970
  void
952
- Controller::halfCloseAppSink(Client *client, Request *req) {
971
+ Controller::maybeHalfCloseAppSinkBecauseRequestBodyEndReached(Client *client, Request *req) {
953
972
  P_ASSERT_EQ(req->state, Request::WAITING_FOR_APP_OUTPUT);
954
- if (req->halfCloseAppConnection) {
955
- SKC_TRACE(client, 3, "Half-closing application socket with SHUT_WR");
973
+ if (req->halfClosePolicy == Request::HALF_CLOSE_UPON_REACHING_REQUEST_BODY_END) {
974
+ SKC_TRACE(client, 3, "Half-closing application socket with SHUT_WR"
975
+ " because end of request body reached");
976
+ req->halfClosePolicy = Request::HALF_CLOSE_PERFORMED;
956
977
  ::shutdown(req->session->fd(), SHUT_WR);
957
978
  }
958
979
  }
@@ -1007,7 +1028,7 @@ Controller::whenSendingRequest_onRequestBody(Client *client, Request *req,
1007
1028
  // care of ending the request, once all response
1008
1029
  // data is forwarded.
1009
1030
  req->state = Request::WAITING_FOR_APP_OUTPUT;
1010
- halfCloseAppSink(client, req);
1031
+ maybeHalfCloseAppSinkBecauseRequestBodyEndReached(client, req);
1011
1032
  return Channel::Result(0, true);
1012
1033
  } else {
1013
1034
  const unsigned int BUFSIZE = 1024;
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2014-2015 Phusion Holding B.V.
3
+ * Copyright (c) 2014-2016 Phusion Holding B.V.
4
4
  *
5
5
  * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
6
  * trademarks of Phusion Holding B.V.
@@ -117,7 +117,7 @@ Controller::inspectRequestStateAsJson(const Request *req) const {
117
117
 
118
118
  if (req->session != NULL) {
119
119
  Json::Value &sessionDoc = doc["session"] = Json::Value(Json::objectValue);
120
- const Session *session = req->session.get();
120
+ const AbstractSession *session = req->session.get();
121
121
 
122
122
  if (req->session->isClosed()) {
123
123
  sessionDoc["closed"] = true;
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2010-2015 Phusion Holding B.V.
3
+ * Copyright (c) 2010-2016 Phusion Holding B.V.
4
4
  *
5
5
  * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
6
  * trademarks of Phusion Holding B.V.
@@ -40,6 +40,7 @@
40
40
  #include <sys/socket.h>
41
41
  #include <sys/stat.h>
42
42
  #include <sys/un.h>
43
+ #include <sys/resource.h>
43
44
  #include <cstring>
44
45
  #include <cassert>
45
46
  #include <cerrno>
@@ -259,6 +260,30 @@ initializeSingleAppMode() {
259
260
  P_NOTICE("App startup file: " << options.get("startup_file"));
260
261
  }
261
262
 
263
+ static void
264
+ setUlimits() {
265
+ TRACE_POINT();
266
+ VariantMap &options = *agentsOptions;
267
+
268
+ if (options.has("core_file_descriptor_ulimit")) {
269
+ unsigned int number = options.getUint("core_file_descriptor_ulimit");
270
+ struct rlimit limit;
271
+ int ret;
272
+
273
+ limit.rlim_cur = number;
274
+ limit.rlim_max = number;
275
+ do {
276
+ ret = setrlimit(RLIMIT_NOFILE, &limit);
277
+ } while (ret == -1 && errno == EINTR);
278
+
279
+ if (ret == -1) {
280
+ int e = errno;
281
+ P_ERROR("Unable to set file descriptor ulimit to " << number
282
+ << ": " << strerror(e) << " (errno=" << e << ")");
283
+ }
284
+ }
285
+ }
286
+
262
287
  static void
263
288
  makeFileWorldReadableAndWritable(const string &path) {
264
289
  int ret;
@@ -960,6 +985,7 @@ runCore() {
960
985
  UPDATE_TRACE_POINT();
961
986
  initializePrivilegedWorkingObjects();
962
987
  initializeSingleAppMode();
988
+ setUlimits();
963
989
  startListening();
964
990
  createPidFile();
965
991
  lowerPrivilege();
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2010-2015 Phusion Holding B.V.
3
+ * Copyright (c) 2010-2016 Phusion Holding B.V.
4
4
  *
5
5
  * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
6
  * trademarks of Phusion Holding B.V.
@@ -118,6 +118,8 @@ coreUsage() {
118
118
  printf(" --meteor-app-settings PATH\n");
119
119
  printf(" File with settings for a Meteor (non-bundled) app.\n");
120
120
  printf(" (passed to Meteor using --settings)\n");
121
+ printf(" --app-file-descriptor-ulimit NUMBER\n");
122
+ printf(" Set custom file descriptor ulimit for the app\n");
121
123
  printf(" --debugger Enable Ruby debugger support (Enterprise only)\n");
122
124
  printf("\n");
123
125
  printf(" --rolling-restarts Enable rolling restarts (Enterprise only)\n");
@@ -185,6 +187,8 @@ coreUsage() {
185
187
  printf(" Default: number of CPU cores (%d)\n",
186
188
  boost::thread::hardware_concurrency());
187
189
  printf(" --cpu-affine Enable per-thread CPU affinity (Linux only)\n");
190
+ printf(" --core-file-descriptor-ulimit NUMBER\n");
191
+ printf(" Set custom file descriptor ulimit for the core\n");
188
192
  printf(" -h, --help Show this help\n");
189
193
  printf("\n");
190
194
  printf("API account privilege levels (ordered from most to least privileges):\n");
@@ -345,6 +349,9 @@ parseCoreOption(int argc, const char *argv[], int &i, VariantMap &options) {
345
349
  } else if (p.isValueFlag(argc, i, argv[i], '\0', "--meteor-app-settings")) {
346
350
  options.set("meteor_app_settings", argv[i + 1]);
347
351
  i += 2;
352
+ } else if (p.isValueFlag(argc, i, argv[i], '\0', "--app-file-descriptor-ulimit")) {
353
+ options.setUint("app_file_descriptor_ulimit", atoi(argv[i + 1]));
354
+ i += 2;
348
355
  } else if (p.isFlag(argv[i], '\0', "--debugger")) {
349
356
  options.setBool("debugger", true);
350
357
  i++;
@@ -393,6 +400,9 @@ parseCoreOption(int argc, const char *argv[], int &i, VariantMap &options) {
393
400
  } else if (p.isFlag(argv[i], '\0', "--cpu-affine")) {
394
401
  options.setBool("core_cpu_affine", true);
395
402
  i++;
403
+ } else if (p.isValueFlag(argc, i, argv[i], '\0', "--core-file-descriptor-ulimit")) {
404
+ options.setUint("core_file_descriptor_ulimit", atoi(argv[i + 1]));
405
+ i += 2;
396
406
  } else if (!startsWith(argv[i], "-")) {
397
407
  if (!options.has("app_root")) {
398
408
  options.set("app_root", argv[i]);