passenger 3.9.2.beta → 4.0.0.rc4

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 (159) hide show
  1. data/.travis.yml +3 -0
  2. data/NEWS +77 -7
  3. data/README.md +3 -11
  4. data/bin/passenger-install-apache2-module +24 -20
  5. data/bin/passenger-install-nginx-module +25 -23
  6. data/build/agents.rb +11 -0
  7. data/build/apache2.rb +9 -5
  8. data/build/basics.rb +37 -30
  9. data/build/common_library.rb +4 -1
  10. data/build/cplusplus_support.rb +5 -5
  11. data/build/cxx_tests.rb +28 -8
  12. data/build/integration_tests.rb +6 -3
  13. data/build/nginx.rb +3 -3
  14. data/build/packaging.rb +95 -57
  15. data/build/ruby_extension.rb +34 -21
  16. data/build/ruby_tests.rb +4 -2
  17. data/build/test_basics.rb +1 -1
  18. data/dev/run_travis.sh +36 -1
  19. data/doc/Users guide Apache.html +425 -308
  20. data/doc/Users guide Apache.idmap.txt +78 -70
  21. data/doc/Users guide Apache.index.sqlite3 +0 -0
  22. data/doc/Users guide Apache.txt +33 -92
  23. data/doc/Users guide Nginx.html +519 -220
  24. data/doc/Users guide Nginx.idmap.txt +78 -60
  25. data/doc/Users guide Nginx.txt +115 -26
  26. data/doc/Users guide Standalone.html +8 -2
  27. data/doc/users_guide_snippets/analysis_and_system_maintenance.txt +1 -7
  28. data/doc/users_guide_snippets/installation.txt +167 -22
  29. data/doc/users_guide_snippets/rackup_specifications.txt +4 -0
  30. data/doc/users_guide_snippets/since_version.txt +1 -0
  31. data/doc/users_guide_snippets/support_information.txt +3 -7
  32. data/doc/users_guide_snippets/tips.txt +0 -24
  33. data/ext/apache2/Configuration.cpp +11 -33
  34. data/ext/apache2/Configuration.hpp +3 -18
  35. data/ext/apache2/DirectoryMapper.h +20 -70
  36. data/ext/apache2/Hooks.cpp +2 -2
  37. data/ext/common/AgentsStarter.cpp +0 -2
  38. data/ext/common/AgentsStarter.h +0 -1
  39. data/ext/common/AgentsStarter.hpp +1 -3
  40. data/ext/common/ApplicationPool2/AppTypes.cpp +74 -0
  41. data/ext/common/ApplicationPool2/AppTypes.h +202 -0
  42. data/ext/common/ApplicationPool2/Common.h +12 -10
  43. data/ext/common/ApplicationPool2/DirectSpawner.h +256 -0
  44. data/ext/common/ApplicationPool2/DummySpawner.h +90 -0
  45. data/ext/common/ApplicationPool2/Group.h +311 -94
  46. data/ext/common/ApplicationPool2/Implementation.cpp +405 -145
  47. data/ext/common/ApplicationPool2/Options.h +24 -26
  48. data/ext/common/ApplicationPool2/PipeWatcher.h +20 -13
  49. data/ext/common/ApplicationPool2/Pool.h +326 -183
  50. data/ext/common/ApplicationPool2/Process.h +205 -55
  51. data/ext/common/ApplicationPool2/README.md +1 -1
  52. data/ext/common/ApplicationPool2/Session.h +21 -10
  53. data/ext/common/ApplicationPool2/SmartSpawner.h +801 -0
  54. data/ext/common/ApplicationPool2/Spawner.h +141 -1149
  55. data/ext/common/ApplicationPool2/SpawnerFactory.h +132 -0
  56. data/ext/common/ApplicationPool2/SuperGroup.h +146 -223
  57. data/ext/common/Constants.h +4 -2
  58. data/ext/common/Exceptions.h +23 -1
  59. data/ext/common/Logging.cpp +17 -6
  60. data/ext/common/Logging.h +37 -7
  61. data/ext/common/ResourceLocator.h +1 -1
  62. data/ext/common/Utils.cpp +49 -1
  63. data/ext/common/Utils.h +13 -4
  64. data/ext/common/{AnsiColorConstants.h → Utils/AnsiColorConstants.h} +0 -0
  65. data/ext/common/{BCrypt.cpp → Utils/BCrypt.cpp} +0 -0
  66. data/ext/common/{BCrypt.h → Utils/BCrypt.h} +0 -0
  67. data/ext/common/{Blowfish.c → Utils/Blowfish.c} +0 -0
  68. data/ext/common/{Blowfish.h → Utils/Blowfish.h} +0 -0
  69. data/ext/common/Utils/CachedFileStat.hpp +27 -25
  70. data/ext/common/Utils/Curl.h +184 -0
  71. data/ext/common/{HttpConstants.h → Utils/HttpConstants.h} +3 -0
  72. data/ext/common/Utils/IOUtils.cpp +6 -2
  73. data/ext/common/{IniFile.h → Utils/IniFile.h} +0 -0
  74. data/ext/common/Utils/LargeFiles.cpp +30 -0
  75. data/ext/common/Utils/LargeFiles.h +40 -0
  76. data/ext/common/Utils/StrIntUtils.cpp +72 -8
  77. data/ext/common/Utils/StrIntUtils.h +24 -2
  78. data/ext/common/Utils/StringMap.h +12 -2
  79. data/ext/common/Utils/VariantMap.h +51 -2
  80. data/ext/common/Utils/jsoncpp.cpp +1 -1
  81. data/ext/common/agents/Base.cpp +147 -11
  82. data/ext/common/agents/HelperAgent/AgentOptions.h +14 -6
  83. data/ext/common/agents/HelperAgent/Main.cpp +79 -19
  84. data/ext/common/agents/HelperAgent/RequestHandler.h +36 -16
  85. data/ext/common/agents/LoggingAgent/LoggingServer.h +3 -5
  86. data/ext/common/agents/LoggingAgent/Main.cpp +2 -4
  87. data/ext/common/agents/LoggingAgent/RemoteSender.h +18 -24
  88. data/ext/common/agents/SpawnPreparer.cpp +7 -0
  89. data/ext/common/agents/Watchdog/Main.cpp +96 -38
  90. data/ext/nginx/Configuration.c +26 -22
  91. data/ext/nginx/Configuration.h +4 -2
  92. data/ext/nginx/ContentHandler.c +23 -52
  93. data/ext/nginx/ContentHandler.h +5 -11
  94. data/ext/nginx/config +10 -3
  95. data/ext/nginx/ngx_http_passenger_module.c +21 -6
  96. data/ext/nginx/ngx_http_passenger_module.h +4 -1
  97. data/ext/oxt/dynamic_thread_group.hpp +9 -1
  98. data/ext/oxt/system_calls.cpp +2 -2
  99. data/ext/ruby/extconf.rb +2 -1
  100. data/helper-scripts/backtrace-sanitizer.rb +2 -0
  101. data/helper-scripts/wsgi-loader.py +54 -21
  102. data/lib/phusion_passenger.rb +5 -3
  103. data/lib/phusion_passenger/abstract_installer.rb +18 -41
  104. data/lib/phusion_passenger/admin_tools/memory_stats.rb +2 -2
  105. data/lib/phusion_passenger/admin_tools/server_instance.rb +2 -2
  106. data/lib/phusion_passenger/common_library.rb +23 -3
  107. data/lib/phusion_passenger/debug_logging.rb +10 -3
  108. data/lib/phusion_passenger/packaging.rb +1 -0
  109. data/lib/phusion_passenger/platform_info.rb +113 -115
  110. data/lib/phusion_passenger/platform_info/compiler.rb +224 -134
  111. data/lib/phusion_passenger/platform_info/cxx_portability.rb +143 -0
  112. data/lib/phusion_passenger/platform_info/depcheck.rb +371 -0
  113. data/lib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +124 -0
  114. data/lib/phusion_passenger/platform_info/depcheck_specs/compiler_toolchain.rb +97 -0
  115. data/lib/phusion_passenger/platform_info/depcheck_specs/gems.rb +39 -0
  116. data/lib/phusion_passenger/platform_info/depcheck_specs/libs.rb +118 -0
  117. data/lib/phusion_passenger/platform_info/depcheck_specs/ruby.rb +137 -0
  118. data/lib/phusion_passenger/platform_info/depcheck_specs/utilities.rb +15 -0
  119. data/lib/phusion_passenger/platform_info/operating_system.rb +6 -5
  120. data/lib/phusion_passenger/platform_info/ruby.rb +45 -34
  121. data/lib/phusion_passenger/request_handler.rb +35 -22
  122. data/lib/phusion_passenger/request_handler/thread_handler.rb +5 -6
  123. data/lib/phusion_passenger/ruby_core_enhancements.rb +7 -1
  124. data/lib/phusion_passenger/standalone/runtime_installer.rb +43 -34
  125. data/lib/phusion_passenger/utils/robust_interruption.rb +34 -18
  126. data/passenger.gemspec +25 -0
  127. data/resources/templates/standalone/config.erb +3 -1
  128. data/test/config.json.travis +2 -2
  129. data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +37 -5
  130. data/test/cxx/ApplicationPool2/PoolTest.cpp +143 -50
  131. data/test/cxx/ApplicationPool2/ProcessTest.cpp +8 -0
  132. data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +28 -17
  133. data/test/cxx/ApplicationPool2/SpawnerTestCases.cpp +31 -26
  134. data/test/cxx/RequestHandlerTest.cpp +17 -1
  135. data/test/cxx/UtilsTest.cpp +84 -10
  136. data/test/integration_tests/apache2_tests.rb +49 -163
  137. data/test/integration_tests/hello_world_wsgi_spec.rb +2 -2
  138. data/test/integration_tests/mycook_spec.rb +1 -1
  139. data/test/integration_tests/nginx_tests.rb +37 -19
  140. data/test/ruby/request_handler_spec.rb +1 -0
  141. data/test/ruby/spec_helper.rb +52 -1
  142. data/test/stub/nginx/nginx.conf.erb +2 -0
  143. data/test/stub/rack/start.rb +5 -0
  144. data/test/stub/rails3.0/Gemfile.lock +30 -30
  145. data/test/stub/rails3.1/Gemfile +1 -1
  146. data/test/stub/rails3.1/Gemfile.lock +3 -3
  147. data/test/stub/rails3.2/Gemfile +1 -1
  148. data/test/stub/rails3.2/Gemfile.lock +4 -4
  149. data/test/stub/rails_apps/2.3/mycook/app/controllers/welcome_controller.rb +1 -1
  150. data/test/stub/rails_apps/2.3/mycook/app/helpers/recipes_helper.rb +2 -0
  151. data/test/stub/rails_apps/2.3/mycook/app/helpers/test_helper.rb +2 -0
  152. data/test/stub/rails_apps/2.3/mycook/app/helpers/uploads_helper.rb +2 -0
  153. data/test/stub/rails_apps/2.3/mycook/app/helpers/welcome_helper.rb +2 -0
  154. data/test/support/nginx_controller.rb +2 -1
  155. metadata +160 -156
  156. data/build/gempackagetask.rb +0 -99
  157. data/build/packagetask.rb +0 -186
  158. data/ext/common/StringListCreator.h +0 -83
  159. data/lib/phusion_passenger/dependencies.rb +0 -657
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2010, 2011, 2012 Phusion
3
+ * Copyright (c) 2010-2013 Phusion
4
4
  *
5
5
  * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  *
@@ -235,7 +235,7 @@ private:
235
235
  this_thread::disable_syscall_interruption dsi;
236
236
  requestSocket = createUnixServer(getRequestSocketFilename().c_str());
237
237
 
238
- int ret;
238
+ int ret, e;
239
239
  do {
240
240
  ret = chmod(getRequestSocketFilename().c_str(), S_ISVTX |
241
241
  S_IRUSR | S_IWUSR | S_IXUSR |
@@ -244,6 +244,44 @@ private:
244
244
  } while (ret == -1 && errno == EINTR);
245
245
 
246
246
  setNonBlocking(requestSocket);
247
+
248
+ if (!options.requestSocketLink.empty()) {
249
+ struct stat buf;
250
+
251
+ // If this is a symlink then we'll want to check the file the symlink
252
+ // points to, so we use stat() instead of lstat().
253
+ ret = syscalls::stat(options.requestSocketLink.c_str(), &buf);
254
+ if (ret == 0 || (ret == -1 && errno == ENOENT)) {
255
+ if (ret == -1 || buf.st_mode & S_IFSOCK) {
256
+ if (syscalls::unlink(options.requestSocketLink.c_str()) == -1) {
257
+ e = errno;
258
+ throw FileSystemException("Cannot delete existing socket file '" +
259
+ options.requestSocketLink + "'", e, options.requestSocketLink);
260
+ }
261
+ } else {
262
+ throw RuntimeException("File '" + options.requestSocketLink +
263
+ "' already exists and is not a Unix domain socket");
264
+ }
265
+ } else if (ret == -1 && errno != ENOENT) {
266
+ e = errno;
267
+ throw FileSystemException("Cannot stat() file '" + options.requestSocketLink + "'",
268
+ e,
269
+ options.requestSocketLink);
270
+ }
271
+
272
+ do {
273
+ ret = symlink(getRequestSocketFilename().c_str(),
274
+ options.requestSocketLink.c_str());
275
+ } while (ret == -1 && errno == EINTR);
276
+ if (ret == -1) {
277
+ e = errno;
278
+ throw FileSystemException("Cannot create a symlink '" +
279
+ options.requestSocketLink +
280
+ "' to '" + getRequestSocketFilename() + "'",
281
+ e,
282
+ options.requestSocketLink);
283
+ }
284
+ }
247
285
  }
248
286
 
249
287
  /**
@@ -287,14 +325,6 @@ private:
287
325
  }
288
326
  }
289
327
 
290
- void resetWorkerThreadInactivityTimers() {
291
- requestHandler->resetInactivityTimer();
292
- }
293
-
294
- unsigned long long minWorkerThreadInactivityTime() const {
295
- return requestHandler->inactivityTime();
296
- }
297
-
298
328
  void onSigquit(ev::sig &signal, int revents) {
299
329
  requestHandler->inspect(cerr);
300
330
  cerr.flush();
@@ -314,14 +344,27 @@ private:
314
344
 
315
345
  static void dumpDiagnosticsOnCrash(void *userData) {
316
346
  Server *self = (Server *) userData;
347
+
348
+ cerr << "### Request handler state\n";
317
349
  self->requestHandler->inspect(cerr);
350
+ cerr << "\n";
318
351
  cerr.flush();
352
+
353
+ cerr << "### Pool state (simple)\n";
319
354
  // Do not lock, the crash may occur within the pool.
320
355
  Pool::InspectOptions options;
321
356
  options.verbose = true;
322
- cerr << "\n" << self->pool->inspect(options, false);
357
+ cerr << self->pool->inspect(options, false);
358
+ cerr << "\n";
323
359
  cerr.flush();
324
- cerr << "\n" << oxt::thread::all_backtraces();
360
+
361
+ cerr << "### Pool state (XML)\n";
362
+ cerr << self->pool->toXml(true, false);
363
+ cerr << "\n\n";
364
+ cerr.flush();
365
+
366
+ cerr << "### Backtraces\n";
367
+ cerr << oxt::thread::all_backtraces();
325
368
  cerr.flush();
326
369
  }
327
370
 
@@ -349,15 +392,24 @@ public:
349
392
  if (geteuid() == 0 && !options.userSwitching) {
350
393
  lowerPrivilege(options.defaultUser, options.defaultGroup);
351
394
  }
395
+
396
+ UPDATE_TRACE_POINT();
397
+ randomGenerator = make_shared<RandomGenerator>();
398
+ // Check whether /dev/urandom is actually random.
399
+ // https://code.google.com/p/phusion-passenger/issues/detail?id=516
400
+ if (randomGenerator->generateByteString(16) == randomGenerator->generateByteString(16)) {
401
+ throw RuntimeException("Your random number device, /dev/urandom, appears to be broken. "
402
+ "It doesn't seem to be returning random data. Please fix this.");
403
+ }
352
404
 
353
405
  UPDATE_TRACE_POINT();
354
406
  loggerFactory = make_shared<UnionStation::LoggerFactory>(options.loggingAgentAddress,
355
407
  "logging", options.loggingAgentPassword);
356
- randomGenerator = make_shared<RandomGenerator>();
357
408
  spawnerFactory = make_shared<SpawnerFactory>(poolLoop.safe,
358
- resourceLocator, generation, randomGenerator);
409
+ resourceLocator, generation, make_shared<SpawnerConfig>(randomGenerator));
359
410
  pool = make_shared<Pool>(poolLoop.safe.get(), spawnerFactory, loggerFactory,
360
411
  randomGenerator);
412
+ pool->initialize();
361
413
  pool->setMax(options.maxPoolSize);
362
414
  //pool->setMaxPerApp(maxInstancesPerApp);
363
415
  pool->setMaxIdleTime(options.poolIdleTime * 1000000);
@@ -402,11 +454,17 @@ public:
402
454
  }
403
455
 
404
456
  messageServer.reset();
457
+ P_DEBUG("Destroying application pool...");
405
458
  pool->destroy();
459
+ uninstallDiagnosticsDumper();
406
460
  pool.reset();
407
- requestHandler.reset();
408
461
  poolLoop.stop();
409
462
  requestLoop.stop();
463
+ requestHandler.reset();
464
+
465
+ if (!options.requestSocketLink.empty()) {
466
+ syscalls::unlink(options.requestSocketLink.c_str());
467
+ }
410
468
 
411
469
  P_TRACE(2, "All threads have been shut down.");
412
470
  }
@@ -443,7 +501,6 @@ public:
443
501
  uninstallDiagnosticsDumper();
444
502
  throw SystemException("select() failed", e);
445
503
  }
446
- uninstallDiagnosticsDumper();
447
504
 
448
505
  if (FD_ISSET(feedbackFd, &fds)) {
449
506
  /* If the watchdog has been killed then we'll kill all descendant
@@ -459,12 +516,15 @@ public:
459
516
  _exit(2); // In case killpg() fails.
460
517
  } else {
461
518
  /* We received an exit command. We want to exit 5 seconds after
462
- * all worker threads have become inactive.
519
+ * all clients have disconnected have become inactive.
463
520
  */
464
- resetWorkerThreadInactivityTimers();
465
- while (minWorkerThreadInactivityTime() < 5000) {
521
+ P_DEBUG("Received command to exit gracefully. "
522
+ "Waiting until 5 seconds after all clients have disconnected...");
523
+ while (requestHandler->inactivityTime() < 5000) {
466
524
  syscalls::usleep(250000);
467
525
  }
526
+ P_DEBUG("It's now 5 seconds after all clients have disconnected. "
527
+ "Proceeding with graceful exit.");
468
528
  }
469
529
  }
470
530
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2011, 2012 Phusion
3
+ * Copyright (c) 2011-2013 Phusion
4
4
  *
5
5
  * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  *
@@ -98,12 +98,12 @@
98
98
  #include <EventedBufferedInput.h>
99
99
  #include <MessageReadersWriters.h>
100
100
  #include <Constants.h>
101
- #include <HttpConstants.h>
102
101
  #include <UnionStation.h>
103
102
  #include <ApplicationPool2/Pool.h>
104
103
  #include <Utils/StrIntUtils.h>
105
104
  #include <Utils/IOUtils.h>
106
105
  #include <Utils/HttpHeaderBufferer.h>
106
+ #include <Utils/HttpConstants.h>
107
107
  #include <Utils/Template.h>
108
108
  #include <Utils/Timer.h>
109
109
  #include <Utils/Dechunker.h>
@@ -795,10 +795,15 @@ private:
795
795
  string::size_type begin = headerData.find(' ');
796
796
  string::size_type end = headerData.find("\r\n");
797
797
  if (begin != string::npos && end != string::npos) {
798
- StaticString status(headerData.data() + begin, end - begin);
799
- headerData.append("Status: ");
800
- headerData.append(status);
801
- headerData.append("\r\n");
798
+ StaticString statusValue(headerData.data() + begin, end - begin);
799
+ char header[statusValue.size() + 20];
800
+ char *pos = header;
801
+ const char *end = header + statusValue.size() + 20;
802
+
803
+ pos = appendData(pos, end, "Status: ");
804
+ pos = appendData(pos, end, statusValue);
805
+ pos = appendData(pos, end, "\r\n");
806
+ headerData.append(header);
802
807
  return true;
803
808
  } else {
804
809
  disconnectWithError(client, "application sent malformed response: the HTTP status line is invalid.");
@@ -925,6 +930,21 @@ private:
925
930
  headerData.append("X-Powered-By: Phusion Passenger\r\n");
926
931
  }
927
932
 
933
+ // Add Date header. https://code.google.com/p/phusion-passenger/issues/detail?id=485
934
+ if (lookupHeader(headerData, "Date", "date").empty()) {
935
+ char dateStr[60];
936
+ char *pos = dateStr;
937
+ const char *end = dateStr + sizeof(dateStr) - 1;
938
+ time_t the_time = time(NULL);
939
+ struct tm the_tm;
940
+
941
+ pos = appendData(pos, end, "Date: ");
942
+ localtime_r(&the_time, &the_tm);
943
+ pos += strftime(pos, end - pos, "%a, %d %b %G %H:%M:%S %Z", &the_tm);
944
+ pos = appendData(pos, end, "\r\n");
945
+ headerData.append(dateStr, pos - dateStr);
946
+ }
947
+
928
948
  // Detect out of band work request
929
949
  Header oobw = lookupHeader(headerData, "X-Passenger-Request-OOB-Work", "x-passenger-request-oob-work");
930
950
  if (!oobw.empty()) {
@@ -1064,8 +1084,9 @@ private:
1064
1084
  RH_TRACE(client, 3, "Waiting until the client socket is writable again.");
1065
1085
  client->clientOutputWatcher.start();
1066
1086
  consumed(0, true);
1067
- } else if (e == EPIPE) {
1087
+ } else if (e == EPIPE || e == ECONNRESET) {
1068
1088
  // If the client closed the connection then disconnect quietly.
1089
+ RH_TRACE(client, 3, "Client stopped reading prematurely");
1069
1090
  if (client->useUnionStation()) {
1070
1091
  client->logMessage("Disconnecting: client stopped reading prematurely");
1071
1092
  }
@@ -1384,7 +1405,7 @@ private:
1384
1405
 
1385
1406
  void checkConnectPassword(const ClientPtr &client, const char *data, unsigned int len) {
1386
1407
  RH_TRACE(client, 3, "Given connect password: \"" << cEscapeString(StaticString(data, len)) << "\"");
1387
- if (StaticString(data, len) == options.requestSocketPassword) {
1408
+ if (constantTimeCompare(StaticString(data, len), options.requestSocketPassword)) {
1388
1409
  RH_TRACE(client, 3, "Connect password is correct; reading header");
1389
1410
  client->state = Client::READING_HEADER;
1390
1411
  client->freeBufferedConnectPassword();
@@ -1527,6 +1548,7 @@ private:
1527
1548
  fillPoolOption(client, options.appType, "PASSENGER_APP_TYPE");
1528
1549
  fillPoolOption(client, options.environment, "PASSENGER_ENV");
1529
1550
  fillPoolOption(client, options.ruby, "PASSENGER_RUBY");
1551
+ fillPoolOption(client, options.python, "PASSENGER_PYTHON");
1530
1552
  fillPoolOption(client, options.user, "PASSENGER_USER");
1531
1553
  fillPoolOption(client, options.group, "PASSENGER_GROUP");
1532
1554
  fillPoolOption(client, options.minProcesses, "PASSENGER_MIN_INSTANCES");
@@ -1745,7 +1767,7 @@ private:
1745
1767
  client->endScopeLog(&client->scopeLogs.getFromPool, false);
1746
1768
  shared_ptr<SpawnException> e2 = dynamic_pointer_cast<SpawnException>(e);
1747
1769
  if (e2 != NULL) {
1748
- if (e2->getErrorPage().empty()) {
1770
+ if (strip(e2->getErrorPage()).empty()) {
1749
1771
  RH_WARN(client, "Cannot checkout session. " << e2->what());
1750
1772
  writeErrorResponse(client, e2->what());
1751
1773
  } else {
@@ -1938,6 +1960,7 @@ private:
1938
1960
  1, client->appOutputBuffer);
1939
1961
  if (ret == -1 && errno != EAGAIN) {
1940
1962
  disconnectWithAppSocketWriteError(client, errno);
1963
+ // TODO: what about other errors?
1941
1964
  } else if (!client->appOutputBuffer.empty()) {
1942
1965
  client->state = Client::SENDING_HEADER_TO_APP;
1943
1966
  client->appOutputWatcher.start();
@@ -1952,9 +1975,10 @@ private:
1952
1975
 
1953
1976
  ssize_t ret = gatheredWrite(client->session->fd(), NULL, 0, client->appOutputBuffer);
1954
1977
  if (ret == -1) {
1955
- if (errno != EAGAIN && errno != EPIPE) {
1978
+ if (errno != EAGAIN && errno != EPIPE && errno != ECONNRESET) {
1956
1979
  disconnectWithAppSocketWriteError(client, errno);
1957
1980
  }
1981
+ // TODO: what about other errors?
1958
1982
  } else if (client->appOutputBuffer.empty()) {
1959
1983
  client->appOutputWatcher.stop();
1960
1984
  sendBodyToApp(client);
@@ -2009,7 +2033,7 @@ private:
2009
2033
  RH_TRACE(client, 3, "Waiting until the application socket is writable again.");
2010
2034
  client->clientInput->stop();
2011
2035
  client->appOutputWatcher.start();
2012
- } else if (e == EPIPE) {
2036
+ } else if (e == EPIPE || e == ECONNRESET) {
2013
2037
  // Client will be disconnected after response forwarding is done.
2014
2038
  client->clientInput->stop();
2015
2039
  syscalls::shutdown(client->fd, SHUT_RD);
@@ -2073,7 +2097,7 @@ private:
2073
2097
  RH_TRACE(client, 3, "Waiting until the application socket is writable again.");
2074
2098
  client->appOutputWatcher.start();
2075
2099
  consumed(0, true);
2076
- } else if (e == EPIPE) {
2100
+ } else if (e == EPIPE || e == ECONNRESET) {
2077
2101
  // Client will be disconnected after response forwarding is done.
2078
2102
  syscalls::shutdown(client->fd, SHUT_RD);
2079
2103
  consumed(0, true);
@@ -2136,10 +2160,6 @@ public:
2136
2160
  }
2137
2161
  }
2138
2162
 
2139
- void resetInactivityTimer() {
2140
- libev->run(boost::bind(&Timer::start, &inactivityTimer));
2141
- }
2142
-
2143
2163
  unsigned long long inactivityTime() const {
2144
2164
  unsigned long long result;
2145
2165
  libev->run(boost::bind(&RequestHandler::getInactivityTime, this, &result));
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2010-2012 Phusion
3
+ * Copyright (c) 2010-2013 Phusion
4
4
  *
5
5
  * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  *
@@ -1084,14 +1084,12 @@ public:
1084
1084
  const string &unionStationGatewayAddress = DEFAULT_UNION_STATION_GATEWAY_ADDRESS,
1085
1085
  unsigned short unionStationGatewayPort = DEFAULT_UNION_STATION_GATEWAY_PORT,
1086
1086
  const string &unionStationGatewayCert = "",
1087
- const string &unionStationProxyAddress = "",
1088
- const string &unionStationProxyPort = "")
1087
+ const string &unionStationProxyAddress = "")
1089
1088
  : EventedMessageServer(loop, fd, accountsDatabase),
1090
1089
  remoteSender(unionStationGatewayAddress,
1091
1090
  unionStationGatewayPort,
1092
1091
  unionStationGatewayCert,
1093
- unionStationProxyAddress,
1094
- unionStationProxyPort),
1092
+ unionStationProxyAddress),
1095
1093
  garbageCollectionTimer(loop),
1096
1094
  sinkFlushingTimer(loop),
1097
1095
  exitTimer(loop)
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2010-2012 Phusion
3
+ * Copyright (c) 2010-2013 Phusion
4
4
  *
5
5
  * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  *
@@ -166,7 +166,6 @@ main(int argc, char *argv[]) {
166
166
  false, DEFAULT_UNION_STATION_GATEWAY_PORT);
167
167
  string unionStationGatewayCert = options.get("union_station_gateway_cert", false);
168
168
  string unionStationProxyAddress = options.get("union_station_proxy_address", false);
169
- string unionStationProxyType = options.get("union_station_proxy_type", false);
170
169
 
171
170
  curl_global_init(CURL_GLOBAL_ALL);
172
171
 
@@ -246,8 +245,7 @@ main(int argc, char *argv[]) {
246
245
  unionStationGatewayAddress,
247
246
  unionStationGatewayPort,
248
247
  unionStationGatewayCert,
249
- unionStationProxyAddress,
250
- unionStationProxyType);
248
+ unionStationProxyAddress);
251
249
  loggingServer = &server;
252
250
 
253
251
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2010 Phusion
3
+ * Copyright (c) 2010-2013 Phusion
4
4
  *
5
5
  * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  *
@@ -43,6 +43,7 @@
43
43
  #include <Utils/SystemTime.h>
44
44
  #include <Utils/ScopeGuard.h>
45
45
  #include <Utils/Base64.h>
46
+ #include <Utils/Curl.h>
46
47
 
47
48
  namespace Passenger {
48
49
 
@@ -72,8 +73,7 @@ private:
72
73
  string ip;
73
74
  unsigned short port;
74
75
  string certificate;
75
- string proxyAddress;
76
- string proxyType;
76
+ const CurlProxyInfo *proxyInfo;
77
77
 
78
78
  CURL *curl;
79
79
  struct curl_slist *headers;
@@ -105,16 +105,6 @@ private:
105
105
  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
106
106
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlDataReceived);
107
107
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
108
- if (!proxyAddress.empty()) {
109
- curl_easy_setopt(curl, CURLOPT_PROXY, proxyAddress.c_str());
110
- if (proxyType.empty() || proxyType == "http") {
111
- curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
112
- } else if (proxyType == "socks5") {
113
- curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
114
- } else {
115
- throw RuntimeException("Only 'http' and 'socks5' proxies are supported.");
116
- }
117
- }
118
108
  if (certificate.empty()) {
119
109
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
120
110
  } else {
@@ -126,6 +116,7 @@ private:
126
116
  * certificate then it doesn't matter.
127
117
  */
128
118
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
119
+ setCurlProxy(curl, *proxyInfo);
129
120
  responseBody.clear();
130
121
  }
131
122
 
@@ -142,13 +133,12 @@ private:
142
133
 
143
134
  public:
144
135
  Server(const string &ip, const string &hostName, unsigned short port, const string &cert,
145
- const string &proxyAddress, const string &proxyType)
136
+ const CurlProxyInfo *proxyInfo)
146
137
  {
147
138
  this->ip = ip;
148
139
  this->port = port;
149
140
  certificate = cert;
150
- this->proxyAddress = proxyAddress;
151
- this->proxyType = proxyType;
141
+ this->proxyInfo = proxyInfo;
152
142
 
153
143
  hostHeader = "Host: " + hostName;
154
144
  headers = NULL;
@@ -247,7 +237,7 @@ private:
247
237
  CURLcode code = curl_easy_perform(curl);
248
238
  curl_formfree(post);
249
239
 
250
- if (code == 0) {
240
+ if (code == CURLE_OK) {
251
241
  guard.clear();
252
242
  // TODO: check response
253
243
  return true;
@@ -264,8 +254,7 @@ private:
264
254
  string gatewayAddress;
265
255
  unsigned short gatewayPort;
266
256
  string certificate;
267
- string proxyAddress;
268
- string proxyType;
257
+ CurlProxyInfo proxyInfo;
269
258
  BlockingQueue<Item> queue;
270
259
  oxt::thread *thr;
271
260
 
@@ -320,7 +309,7 @@ private:
320
309
  servers.clear();
321
310
  for (it = ips.begin(); it != ips.end(); it++) {
322
311
  ServerPtr server = make_shared<Server>(*it, gatewayAddress, gatewayPort,
323
- certificate, proxyAddress, proxyType);
312
+ certificate, &proxyInfo);
324
313
  if (server->ping()) {
325
314
  servers.push_back(server);
326
315
  } else {
@@ -441,18 +430,23 @@ private:
441
430
 
442
431
  public:
443
432
  RemoteSender(const string &gatewayAddress, unsigned short gatewayPort, const string &certificate,
444
- const string &proxyAddress, const string &proxyType)
433
+ const string &proxyAddress)
445
434
  : queue(1024)
446
435
  {
436
+ TRACE_POINT();
447
437
  this->gatewayAddress = gatewayAddress;
448
438
  this->gatewayPort = gatewayPort;
449
439
  this->certificate = certificate;
450
- this->proxyAddress = proxyAddress;
451
- this->proxyType = proxyType;
440
+ try {
441
+ this->proxyInfo = prepareCurlProxy(proxyAddress);
442
+ } catch (const ArgumentException &e) {
443
+ throw RuntimeException("Invalid Union Station proxy address \"" +
444
+ proxyAddress + "\": " + e.what());
445
+ }
452
446
  thr = new oxt::thread(
453
447
  boost::bind(&RemoteSender::threadMain, this),
454
448
  "RemoteSender thread",
455
- 1024 * 64
449
+ 1024 * 512
456
450
  );
457
451
  }
458
452