passenger 5.0.0.beta3 → 5.0.0.rc1

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 (218) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/.editorconfig +11 -5
  5. data/CHANGELOG +38 -0
  6. data/CONTRIBUTING.md +1 -4
  7. data/Gemfile +0 -1
  8. data/Gemfile.lock +0 -2
  9. data/Rakefile +33 -33
  10. data/bin/passenger +1 -1
  11. data/bin/passenger-config +1 -1
  12. data/bin/passenger-install-apache2-module +800 -800
  13. data/bin/passenger-install-nginx-module +592 -592
  14. data/bin/passenger-memory-stats +127 -127
  15. data/bin/passenger-status +216 -216
  16. data/build/agents.rb +127 -127
  17. data/build/apache2.rb +87 -87
  18. data/build/basics.rb +60 -60
  19. data/build/common_library.rb +165 -165
  20. data/build/cplusplus_support.rb +51 -51
  21. data/build/cxx_tests.rb +268 -268
  22. data/build/debian.rb +143 -143
  23. data/build/documentation.rb +58 -58
  24. data/build/integration_tests.rb +81 -81
  25. data/build/misc.rb +132 -132
  26. data/build/nginx.rb +20 -20
  27. data/build/node_tests.rb +7 -7
  28. data/build/oxt_tests.rb +14 -14
  29. data/build/packaging.rb +570 -570
  30. data/build/preprocessor.rb +260 -260
  31. data/build/rake_extensions.rb +71 -71
  32. data/build/ruby_extension.rb +29 -29
  33. data/build/ruby_tests.rb +6 -6
  34. data/build/test_basics.rb +37 -37
  35. data/debian.template/control.template +3 -5
  36. data/dev/copy_boost_headers +134 -134
  37. data/dev/install_scripts_bootstrap_code.rb +25 -25
  38. data/dev/list_tests +20 -20
  39. data/dev/ruby_server.rb +223 -223
  40. data/dev/runner +18 -18
  41. data/doc/ServerOptimizationGuide.txt.md +55 -2
  42. data/doc/Users guide Nginx.txt +0 -26
  43. data/doc/Users guide Standalone.txt +5 -1
  44. data/doc/users_guide_snippets/tips.txt +9 -0
  45. data/ext/common/ApplicationPool2/Group.h +23 -11
  46. data/ext/common/ApplicationPool2/Implementation.cpp +32 -7
  47. data/ext/common/ApplicationPool2/Pool.h +22 -17
  48. data/ext/common/ApplicationPool2/SmartSpawner.h +4 -1
  49. data/ext/common/ApplicationPool2/Spawner.h +1 -1
  50. data/ext/common/Constants.h +1 -1
  51. data/ext/common/agents/Base.cpp +35 -20
  52. data/ext/common/agents/HelperAgent/Main.cpp +8 -1
  53. data/ext/common/agents/HelperAgent/OptionParser.h +18 -4
  54. data/ext/common/agents/HelperAgent/RequestHandler.h +2 -83
  55. data/ext/common/agents/HelperAgent/RequestHandler/ForwardResponse.cpp +54 -1
  56. data/ext/common/agents/HelperAgent/RequestHandler/InitRequest.cpp +7 -4
  57. data/ext/common/agents/Main.cpp +1 -1
  58. data/ext/common/agents/Watchdog/Main.cpp +54 -19
  59. data/ext/nginx/Configuration.c +7 -0
  60. data/ext/nginx/ContentHandler.c +9 -1
  61. data/helper-scripts/backtrace-sanitizer.rb +106 -87
  62. data/helper-scripts/crash-watch.rb +32 -0
  63. data/helper-scripts/download_binaries/extconf.rb +38 -38
  64. data/helper-scripts/meteor-loader.rb +107 -107
  65. data/helper-scripts/prespawn +101 -101
  66. data/helper-scripts/rack-loader.rb +96 -96
  67. data/helper-scripts/rack-preloader.rb +137 -137
  68. data/lib/phusion_passenger.rb +292 -292
  69. data/lib/phusion_passenger/abstract_installer.rb +438 -438
  70. data/lib/phusion_passenger/active_support3_extensions/init.rb +168 -170
  71. data/lib/phusion_passenger/admin_tools.rb +20 -20
  72. data/lib/phusion_passenger/admin_tools/instance.rb +178 -178
  73. data/lib/phusion_passenger/admin_tools/instance_registry.rb +61 -61
  74. data/lib/phusion_passenger/admin_tools/memory_stats.rb +267 -267
  75. data/lib/phusion_passenger/apache2/config_options.rb +182 -182
  76. data/lib/phusion_passenger/common_library.rb +479 -485
  77. data/lib/phusion_passenger/config/about_command.rb +161 -161
  78. data/lib/phusion_passenger/config/admin_command_command.rb +129 -129
  79. data/lib/phusion_passenger/config/agent_compiler.rb +121 -121
  80. data/lib/phusion_passenger/config/build_native_support_command.rb +43 -43
  81. data/lib/phusion_passenger/config/command.rb +25 -25
  82. data/lib/phusion_passenger/config/compile_agent_command.rb +62 -62
  83. data/lib/phusion_passenger/config/compile_nginx_engine_command.rb +88 -73
  84. data/lib/phusion_passenger/config/detach_process_command.rb +72 -72
  85. data/lib/phusion_passenger/config/download_agent_command.rb +246 -227
  86. data/lib/phusion_passenger/config/download_nginx_engine_command.rb +245 -224
  87. data/lib/phusion_passenger/config/install_agent_command.rb +144 -132
  88. data/lib/phusion_passenger/config/install_standalone_runtime_command.rb +205 -185
  89. data/lib/phusion_passenger/config/installation_utils.rb +204 -204
  90. data/lib/phusion_passenger/config/list_instances_command.rb +64 -64
  91. data/lib/phusion_passenger/config/main.rb +152 -152
  92. data/lib/phusion_passenger/config/nginx_engine_compiler.rb +319 -300
  93. data/lib/phusion_passenger/config/reopen_logs_command.rb +67 -67
  94. data/lib/phusion_passenger/config/restart_app_command.rb +155 -155
  95. data/lib/phusion_passenger/config/system_metrics_command.rb +13 -13
  96. data/lib/phusion_passenger/config/utils.rb +95 -95
  97. data/lib/phusion_passenger/config/validate_install_command.rb +198 -198
  98. data/lib/phusion_passenger/console_text_template.rb +25 -25
  99. data/lib/phusion_passenger/constants.rb +90 -90
  100. data/lib/phusion_passenger/debug_logging.rb +106 -106
  101. data/lib/phusion_passenger/loader_shared_helpers.rb +447 -432
  102. data/lib/phusion_passenger/message_channel.rb +312 -312
  103. data/lib/phusion_passenger/message_client.rb +176 -176
  104. data/lib/phusion_passenger/native_support.rb +369 -369
  105. data/lib/phusion_passenger/nginx/config_options.rb +297 -297
  106. data/lib/phusion_passenger/packaging.rb +131 -131
  107. data/lib/phusion_passenger/platform_info.rb +360 -360
  108. data/lib/phusion_passenger/platform_info/apache.rb +767 -767
  109. data/lib/phusion_passenger/platform_info/apache_detector.rb +199 -199
  110. data/lib/phusion_passenger/platform_info/binary_compatibility.rb +107 -107
  111. data/lib/phusion_passenger/platform_info/compiler.rb +570 -570
  112. data/lib/phusion_passenger/platform_info/curl.rb +32 -32
  113. data/lib/phusion_passenger/platform_info/cxx_portability.rb +188 -188
  114. data/lib/phusion_passenger/platform_info/depcheck.rb +372 -372
  115. data/lib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +109 -109
  116. data/lib/phusion_passenger/platform_info/depcheck_specs/compiler_toolchain.rb +4 -4
  117. data/lib/phusion_passenger/platform_info/depcheck_specs/gems.rb +10 -34
  118. data/lib/phusion_passenger/platform_info/depcheck_specs/libs.rb +101 -101
  119. data/lib/phusion_passenger/platform_info/depcheck_specs/ruby.rb +5 -5
  120. data/lib/phusion_passenger/platform_info/depcheck_specs/utilities.rb +13 -13
  121. data/lib/phusion_passenger/platform_info/linux.rb +55 -55
  122. data/lib/phusion_passenger/platform_info/operating_system.rb +149 -149
  123. data/lib/phusion_passenger/platform_info/ruby.rb +468 -448
  124. data/lib/phusion_passenger/platform_info/zlib.rb +9 -9
  125. data/lib/phusion_passenger/plugin.rb +66 -66
  126. data/lib/phusion_passenger/preloader_shared_helpers.rb +126 -126
  127. data/lib/phusion_passenger/public_api.rb +191 -191
  128. data/lib/phusion_passenger/rack/out_of_band_gc.rb +93 -94
  129. data/lib/phusion_passenger/rack/thread_handler_extension.rb +231 -227
  130. data/lib/phusion_passenger/request_handler.rb +567 -577
  131. data/lib/phusion_passenger/request_handler/thread_handler.rb +379 -381
  132. data/lib/phusion_passenger/ruby_core_enhancements.rb +86 -86
  133. data/lib/phusion_passenger/ruby_core_io_enhancements.rb +74 -74
  134. data/lib/phusion_passenger/simple_benchmarking.rb +25 -25
  135. data/lib/phusion_passenger/standalone/app_finder.rb +153 -150
  136. data/lib/phusion_passenger/standalone/command.rb +44 -40
  137. data/lib/phusion_passenger/standalone/config_utils.rb +53 -53
  138. data/lib/phusion_passenger/standalone/control_utils.rb +38 -59
  139. data/lib/phusion_passenger/standalone/main.rb +73 -73
  140. data/lib/phusion_passenger/standalone/start_command.rb +697 -685
  141. data/lib/phusion_passenger/standalone/start_command/builtin_engine.rb +193 -155
  142. data/lib/phusion_passenger/standalone/start_command/nginx_engine.rb +162 -133
  143. data/lib/phusion_passenger/standalone/status_command.rb +64 -64
  144. data/lib/phusion_passenger/standalone/stop_command.rb +72 -72
  145. data/lib/phusion_passenger/standalone/version_command.rb +9 -9
  146. data/lib/phusion_passenger/union_station/connection.rb +32 -32
  147. data/lib/phusion_passenger/union_station/core.rb +251 -251
  148. data/lib/phusion_passenger/union_station/transaction.rb +126 -126
  149. data/lib/phusion_passenger/utils.rb +199 -167
  150. data/lib/phusion_passenger/utils/ansi_colors.rb +128 -128
  151. data/lib/phusion_passenger/utils/download.rb +196 -196
  152. data/lib/phusion_passenger/utils/file_system_watcher.rb +158 -158
  153. data/lib/phusion_passenger/utils/hosts_file_parser.rb +101 -101
  154. data/lib/phusion_passenger/utils/lock.rb +31 -31
  155. data/lib/phusion_passenger/utils/native_support_utils.rb +31 -31
  156. data/lib/phusion_passenger/utils/progress_bar.rb +26 -26
  157. data/lib/phusion_passenger/utils/shellwords.rb +20 -20
  158. data/lib/phusion_passenger/utils/terminal_choice_menu.rb +206 -206
  159. data/lib/phusion_passenger/utils/unseekable_socket.rb +272 -272
  160. data/lib/phusion_passenger/vendor/crash_watch/app.rb +129 -0
  161. data/lib/phusion_passenger/vendor/crash_watch/gdb_controller.rb +341 -0
  162. data/lib/phusion_passenger/vendor/crash_watch/version.rb +24 -0
  163. data/lib/phusion_passenger/vendor/daemon_controller.rb +877 -0
  164. data/lib/phusion_passenger/vendor/daemon_controller/lock_file.rb +127 -0
  165. data/lib/phusion_passenger/vendor/daemon_controller/spawn.rb +26 -0
  166. data/lib/phusion_passenger/vendor/daemon_controller/version.rb +29 -0
  167. data/packaging/rpm/passenger_spec/passenger.spec.template +0 -1
  168. data/passenger.gemspec +0 -1
  169. data/resources/templates/config/nginx_engine_compiler/possible_solutions_for_download_and_extraction_problems.txt.erb +27 -0
  170. data/resources/templates/standalone/config.erb +19 -15
  171. data/test/integration_tests/apache2_tests.rb +566 -566
  172. data/test/integration_tests/downloaded_binaries_tests.rb +126 -125
  173. data/test/integration_tests/native_packaging_spec.rb +296 -296
  174. data/test/integration_tests/nginx_tests.rb +393 -393
  175. data/test/integration_tests/shared/example_webapp_tests.rb +282 -280
  176. data/test/integration_tests/source_packaging_test.rb +138 -138
  177. data/test/integration_tests/spec_helper.rb +5 -5
  178. data/test/integration_tests/standalone_tests.rb +367 -367
  179. data/test/ruby/debug_logging_spec.rb +133 -133
  180. data/test/ruby/message_channel_spec.rb +186 -186
  181. data/test/ruby/rack/loader_spec.rb +28 -28
  182. data/test/ruby/rack/preloader_spec.rb +34 -34
  183. data/test/ruby/rails3.0/loader_spec.rb +12 -12
  184. data/test/ruby/rails3.0/preloader_spec.rb +18 -18
  185. data/test/ruby/rails3.1/loader_spec.rb +12 -12
  186. data/test/ruby/rails3.1/preloader_spec.rb +18 -18
  187. data/test/ruby/rails3.2/loader_spec.rb +12 -12
  188. data/test/ruby/rails3.2/preloader_spec.rb +18 -18
  189. data/test/ruby/rails4.0/loader_spec.rb +12 -12
  190. data/test/ruby/rails4.0/preloader_spec.rb +18 -18
  191. data/test/ruby/rails4.1/loader_spec.rb +12 -12
  192. data/test/ruby/rails4.1/preloader_spec.rb +18 -18
  193. data/test/ruby/request_handler_spec.rb +730 -730
  194. data/test/ruby/shared/loader_sharedspec.rb +224 -224
  195. data/test/ruby/shared/rails/union_station_extensions_sharedspec.rb +327 -327
  196. data/test/ruby/shared/ruby_loader_sharedspec.rb +47 -47
  197. data/test/ruby/spec_helper.rb +65 -65
  198. data/test/ruby/standalone/runtime_installer_spec.rb +384 -384
  199. data/test/ruby/union_station_spec.rb +276 -276
  200. data/test/ruby/utils/file_system_watcher_spec.rb +220 -220
  201. data/test/ruby/utils/hosts_file_parser.rb +248 -248
  202. data/test/ruby/utils/tee_input_spec.rb +215 -215
  203. data/test/ruby/utils/unseekable_socket_spec.rb +57 -57
  204. data/test/ruby/utils_spec.rb +21 -21
  205. data/test/stub/rack/config.ru +87 -87
  206. data/test/stub/rack/library.rb +8 -8
  207. data/test/stub/rack/start.rb +30 -30
  208. data/test/support/apache2_controller.rb +191 -191
  209. data/test/support/nginx_controller.rb +90 -99
  210. data/test/support/placebo-preloader.rb +57 -57
  211. data/test/support/test_helper.rb +435 -435
  212. metadata +11 -21
  213. metadata.gz.asc +7 -7
  214. data/lib/phusion_passenger/standalone/command2.rb +0 -292
  215. data/lib/phusion_passenger/standalone/start2_command.rb +0 -799
  216. data/resources/templates/standalone/download_tool_missing.txt.erb +0 -18
  217. data/resources/templates/standalone/possible_solutions_for_download_and_extraction_problems.txt.erb +0 -17
  218. data/resources/templates/standalone/run_installer_as_root.txt.erb +0 -8
@@ -390,7 +390,7 @@ private:
390
390
  "gupid: " + details.gupid + "\n"
391
391
  "UNIX_PATH_MAX: " + toString(UNIX_PATH_MAX) + "\n";
392
392
  if (!details.options->groupSecret.empty()) {
393
- "connect_password: " + details.options->groupSecret + "\n";
393
+ data.append("connect_password: " + details.options->groupSecret + "\n");
394
394
  }
395
395
  if (!config->instanceDir.empty()) {
396
396
  data.append("socket_dir: " + config->instanceDir + "/apps.s\n");
@@ -112,7 +112,7 @@
112
112
 
113
113
  #define NGINX_DOC_URL "https://www.phusionpassenger.com/documentation/Users%20guide%20Nginx.html"
114
114
 
115
- #define PASSENGER_VERSION "5.0.0.beta3"
115
+ #define PASSENGER_VERSION "5.0.0.rc1"
116
116
 
117
117
  #define POOL_HELPER_THREAD_STACK_SIZE 262144
118
118
 
@@ -110,8 +110,12 @@ static unsigned int alternativeStackSize;
110
110
  static volatile unsigned int abortHandlerCalled = 0;
111
111
  static unsigned int randomSeed = 0;
112
112
  static char **origArgv = NULL;
113
+ static const char *rubyLibDir = NULL;
114
+ static const char *passengerRoot = NULL;
115
+ static const char *defaultRuby = DEFAULT_RUBY;
113
116
  static const char *backtraceSanitizerCommand = NULL;
114
117
  static bool backtraceSanitizerPassProgramInfo = true;
118
+ static const char *crashWatch = NULL;
115
119
  static DiagnosticsDumper customDiagnosticsDumper = NULL;
116
120
  static void *customDiagnosticsDumperUserData;
117
121
 
@@ -516,19 +520,15 @@ dumpWithCrashWatch(AbortHandlerState &state) {
516
520
  pid_t child = asyncFork();
517
521
  if (child == 0) {
518
522
  closeAllFileDescriptors(2, true);
519
- execlp("crash-watch", "crash-watch", "--dump", pidStr, (char * const) 0);
520
- if (errno == ENOENT) {
521
- safePrintErr("Crash-watch is not installed. Please install it with 'gem install crash-watch' "
522
- "or download it from https://github.com/FooBarWidget/crash-watch.\n");
523
- } else {
524
- int e = errno;
525
- end = messageBuf;
526
- end = appendText(end, "crash-watch is installed, but it could not be executed! ");
527
- end = appendText(end, "(execlp() returned errno=");
528
- end = appendULL(end, e);
529
- end = appendText(end, ") Please check your file permissions or something.\n");
530
- write_nowarn(STDERR_FILENO, messageBuf, end - messageBuf);
531
- }
523
+ execlp(defaultRuby, defaultRuby, crashWatch, rubyLibDir,
524
+ passengerRoot, "--dump", pidStr, (char * const) 0);
525
+ int e = errno;
526
+ end = messageBuf;
527
+ end = appendText(end, "crash-watch is could not be executed! ");
528
+ end = appendText(end, "(execlp() returned errno=");
529
+ end = appendULL(end, e);
530
+ end = appendText(end, ") Please check your file permissions or something.\n");
531
+ write_nowarn(STDERR_FILENO, messageBuf, end - messageBuf);
532
532
  _exit(1);
533
533
 
534
534
  } else if (child == -1) {
@@ -1518,15 +1518,30 @@ initializeAgent(int argc, char **argv[], const char *processName,
1518
1518
  argc - argStartIndex);
1519
1519
  }
1520
1520
 
1521
- #ifdef __linux__
1522
- if (options.has("passenger_root")) {
1523
- ResourceLocator locator(options.get("passenger_root", true));
1524
- string ruby = options.get("default_ruby", false, DEFAULT_RUBY);
1525
- string path = ruby + " \"" + locator.getHelperScriptsDir() +
1521
+ ResourceLocator locator;
1522
+ string ruby;
1523
+
1524
+ if (options.has("passenger_root")) {
1525
+ string path;
1526
+ locator = ResourceLocator(options.get("passenger_root", true));
1527
+ ruby = options.get("default_ruby", false, DEFAULT_RUBY);
1528
+
1529
+ rubyLibDir = strdup(locator.getRubyLibDir().c_str());
1530
+ passengerRoot = strdup(options.get("passenger_root", true).c_str());
1531
+ defaultRuby = strdup(ruby.c_str());
1532
+
1533
+ #ifdef __linux__
1534
+ path = ruby + " \"" + locator.getHelperScriptsDir() +
1526
1535
  "/backtrace-sanitizer.rb\"";
1527
1536
  backtraceSanitizerCommand = strdup(path.c_str());
1528
- }
1529
- #endif
1537
+ #endif
1538
+
1539
+ path = locator.getHelperScriptsDir() + "/crash-watch.rb";
1540
+ crashWatch = strdup(path.c_str());
1541
+ } else {
1542
+ shouldDumpWithCrashWatch = false;
1543
+ }
1544
+
1530
1545
  if (backtraceSanitizerCommand == NULL) {
1531
1546
  backtraceSanitizerCommand = "c++filt -n";
1532
1547
  backtraceSanitizerPassProgramInfo = false;
@@ -975,6 +975,7 @@ setAgentsOptionsDefaults() {
975
975
  options.setDefaultInt("stat_throttle_rate", DEFAULT_STAT_THROTTLE_RATE);
976
976
  options.setDefault("server_software", SERVER_TOKEN_NAME "/" PASSENGER_VERSION);
977
977
  options.setDefaultBool("show_version_in_header", true);
978
+ options.setDefaultBool("sticky_sessions", false);
978
979
  options.setDefault("sticky_sessions_cookie_name", DEFAULT_STICKY_SESSIONS_COOKIE_NAME);
979
980
  options.setDefaultBool("turbocaching", true);
980
981
  options.setDefault("data_buffer_dir", getSystemTempDir());
@@ -985,6 +986,7 @@ setAgentsOptionsDefaults() {
985
986
  options.setDefaultBool("server_cpu_affine", false);
986
987
  options.setDefault("friendly_error_pages", "auto");
987
988
  options.setDefaultBool("rolling_restarts", false);
989
+ options.setDefaultBool("resist_deployment_errors", false);
988
990
 
989
991
  string firstAddress = options.getStrSet("server_addresses")[0];
990
992
  if (getSocketAddressType(firstAddress) == SAT_TCP) {
@@ -1000,6 +1002,7 @@ setAgentsOptionsDefaults() {
1000
1002
  }
1001
1003
 
1002
1004
  options.setDefault("default_ruby", DEFAULT_RUBY);
1005
+ options.setDefaultBool("debugger", false);
1003
1006
  if (!options.getBool("multi_app") && !options.has("app_root")) {
1004
1007
  char *pwd = getcwd(NULL, 0);
1005
1008
  options.set("app_root", pwd);
@@ -1024,7 +1027,7 @@ sanityCheckOptions() {
1024
1027
  if (!options.getBool("multi_app") && options.has("app_type")) {
1025
1028
  PassengerAppType appType = getAppType(options.get("app_type"));
1026
1029
  if (appType == PAT_NONE || appType == PAT_ERROR) {
1027
- fprintf(stderr, "ERROR: '%s' is not a valid applicaion type. Supported app types are:",
1030
+ fprintf(stderr, "ERROR: '%s' is not a valid application type. Supported app types are:",
1028
1031
  options.get("app_type").c_str());
1029
1032
  const AppTypeDefinition *definition = &appTypeDefinitions[0];
1030
1033
  while (definition->type != PAT_NONE) {
@@ -1076,6 +1079,10 @@ sanityCheckOptions() {
1076
1079
  fprintf(stderr, "ERROR: you may only specify for --threads a number greater than or equal to 1.\n");
1077
1080
  ok = false;
1078
1081
  }
1082
+ if (options.getInt("max_pool_size") < 1) {
1083
+ fprintf(stderr, "ERROR: you may only specify for --max-pool-size a number greater than or equal to 1.\n");
1084
+ ok = false;
1085
+ }
1079
1086
 
1080
1087
  if (!ok) {
1081
1088
  exit(1);
@@ -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,8 +110,11 @@ serverUsage() {
110
110
  printf(" Force friendly error pages to be always off\n");
111
111
  printf("\n");
112
112
  printf(" --ruby PATH Default Ruby interpreter to use.\n");
113
+ printf(" --debugger Enable Ruby debugger support (Enterprise only)\n");
113
114
  printf("\n");
114
115
  printf(" --rolling-restarts Enable rolling restarts (Enterprise only)\n");
116
+ printf(" --resist-deployment-errors\n");
117
+ printf(" Enable deployment error resistance (Enterprise only)\n");
115
118
  printf("\n");
116
119
  printf("Process management options (optional):\n");
117
120
  printf(" --max-pool-size N Maximum number of application processes.\n");
@@ -122,8 +125,10 @@ serverUsage() {
122
125
  printf(" --min-instances N Minimum number of application processes. Default: 1\n");
123
126
  printf("\n");
124
127
  printf("Request handling options (optional):\n");
128
+ printf(" --sticky-sessions Enable sticky sessions\n");
125
129
  printf(" --sticky-sessions-cookie-name NAME\n");
126
- printf(" Cookie name to use for sticky sessions\n");
130
+ printf(" Cookie name to use for sticky sessions.\n");
131
+ printf(" Default: " DEFAULT_STICKY_SESSIONS_COOKIE_NAME "\n");
127
132
  printf(" --vary-turbocache-by-cookie NAME\n");
128
133
  printf(" Vary the turbocache by the cookie of the given name\n");
129
134
  printf(" --disable-turbocaching\n");
@@ -263,10 +268,13 @@ parseServerOption(int argc, const char *argv[], int &i, VariantMap &options) {
263
268
  options.setBool("multi_app", true);
264
269
  i++;
265
270
  } else if (p.isFlag(argv[i], '\0', "--force-friendly-error-pages")) {
266
- options.set("friendly_error_pages", "true");
271
+ options.setBool("friendly_error_pages", true);
267
272
  i++;
268
273
  } else if (p.isFlag(argv[i], '\0', "--disable-friendly-error-pages")) {
269
- options.set("friendly_error_pages", "false");
274
+ options.setBool("friendly_error_pages", false);
275
+ i++;
276
+ } else if (p.isFlag(argv[i], '\0', "--sticky-sessions")) {
277
+ options.setBool("sticky_sessions", true);
270
278
  i++;
271
279
  } else if (p.isValueFlag(argc, i, argv[i], '\0', "--sticky-sessions-cookie-name")) {
272
280
  options.set("sticky_sessions_cookie_name", argv[i + 1]);
@@ -280,9 +288,15 @@ parseServerOption(int argc, const char *argv[], int &i, VariantMap &options) {
280
288
  } else if (p.isValueFlag(argc, i, argv[i], '\0', "--ruby")) {
281
289
  options.set("default_ruby", argv[i + 1]);
282
290
  i += 2;
291
+ } else if (p.isFlag(argv[i], '\0', "--debugger")) {
292
+ options.setBool("debugger", true);
293
+ i++;
283
294
  } else if (p.isFlag(argv[i], '\0', "--rolling-restarts")) {
284
295
  options.setBool("rolling_restarts", true);
285
296
  i++;
297
+ } else if (p.isFlag(argv[i], '\0', "--resist-deployment-errors")) {
298
+ options.setBool("resist_deployment_errors", true);
299
+ i++;
286
300
  } else if (p.isValueFlag(argc, i, argv[i], '\0', "--log-level")) {
287
301
  // We do not set log_level because, when this function is called from
288
302
  // the Watchdog, we don't want to affect the Watchdog's own log level.
@@ -23,89 +23,6 @@
23
23
  * THE SOFTWARE.
24
24
  */
25
25
 
26
- /*
27
- STAGES
28
-
29
- Accept connect password
30
- |
31
- \|/
32
- Read header
33
- |
34
- \|/
35
- +------+------+
36
- | |
37
- | |
38
- \|/ |
39
- Buffer |
40
- request |
41
- body |
42
- | |
43
- | |
44
- \|/ |
45
- Checkout <-------+
46
- session
47
- |
48
- |
49
- \|/
50
- Send header
51
- to app
52
- |
53
- |
54
- \|/
55
- Send request
56
- body to app
57
-
58
-
59
-
60
- OVERVIEW OF I/O CHANNELS, PIPES AND WATCHERS
61
-
62
-
63
- OPTIONAL: appOutputWatcher
64
- clientBodyBuffer (o)
65
- | |
66
- +----------+ | +-----------+ | +---------------+
67
- | | ------ clientInput -----> | Request | ----------------> | |
68
- | Client | fd | Handler | session | Application |
69
- | | <--- clientOutputPipe --- | | <--- appInput --- | |
70
- +----------+ | +-----------+ +---------------+
71
- |
72
- (o)
73
- clientOutputWatcher
74
-
75
-
76
-
77
- REQUEST BODY HANDLING STRATEGIES
78
-
79
- This table describes how we should handle the request body (the part in the request
80
- that comes after the request header, and may include WebSocket data), given various
81
- factors. Strategies that are listed first have precedence.
82
-
83
- Method 'Upgrade' 'Content-Length' or Application Action
84
- header 'Transfer-Encoding' socket
85
- present? header present? protocol
86
- ---------------------------------------------------------------------------------------------
87
-
88
- GET/HEAD Y Y - Reject request[1]
89
- Other Y - - Reject request[2]
90
-
91
- GET/HEAD Y N http_session Set requestBodyLength=-1, keep socket open when done forwarding.
92
- - N N http_session Set requestBodyLength=0, keep socket open when done forwarding.
93
- - N Y http_session Keep socket open when done forwarding. If Transfer-Encoding is
94
- chunked, rechunck the body during forwarding.
95
-
96
- GET/HEAD Y N session Set requestBodyLength=-1, half-close app socket when done forwarding.
97
- - N N session Set requestBodyLength=0, half-close app socket when done forwarding.
98
- - N Y session Half-close app socket when done forwarding.
99
- ---------------------------------------------------------------------------------------------
100
-
101
- [1] Supporting situations in which there is both an HTTP request body and WebSocket data
102
- is way too complicated. The RequestHandler code is complicated enough as it is,
103
- so we choose not to support requests like these.
104
- [2] RFC 6455 states that WebSocket upgrades may only happen over GET requests.
105
- We don't bother supporting non-WebSocket upgrades.
106
-
107
- */
108
-
109
26
  #ifndef _PASSENGER_REQUEST_HANDLER_H_
110
27
  #define _PASSENGER_REQUEST_HANDLER_H_
111
28
 
@@ -193,6 +110,7 @@ private:
193
110
  BenchmarkMode benchmarkMode: 3;
194
111
  bool singleAppMode: 1;
195
112
  bool showVersionInHeader: 1;
113
+ bool stickySessions: 1;
196
114
  bool gracefulExit: 1;
197
115
 
198
116
  const VariantMap *agentsOptions;
@@ -267,6 +185,7 @@ public:
267
185
  benchmarkMode(parseBenchmarkMode(_agentsOptions->get("benchmark_mode", false))),
268
186
  singleAppMode(false),
269
187
  showVersionInHeader(_agentsOptions->getBool("show_version_in_header")),
188
+ stickySessions(_agentsOptions->getBool("sticky_sessions")),
270
189
  gracefulExit(_agentsOptions->getBool("server_graceful_exit")),
271
190
 
272
191
  agentsOptions(_agentsOptions),
@@ -661,6 +661,59 @@ constructHeaderBuffersForResponse(Request *req, struct iovec *buffers,
661
661
  }
662
662
  }
663
663
 
664
+ if (req->stickySession) {
665
+ StaticString baseURI = req->options.baseURI;
666
+ if (baseURI.empty()) {
667
+ baseURI = P_STATIC_STRING("/");
668
+ }
669
+
670
+ // Note that we do NOT set HttpOnly. If we set that flag then Chrome
671
+ // doesn't send cookies over WebSocket handshakes. Confirmed on Chrome 25.
672
+
673
+ const LString *cookieName = getStickySessionCookieName(req);
674
+ unsigned int stickySessionId;
675
+ unsigned int stickySessionIdSize;
676
+ char *stickySessionIdStr;
677
+
678
+ PUSH_STATIC_BUFFER("Set-Cookie: ");
679
+
680
+ part = cookieName->start;
681
+ while (part != NULL) {
682
+ if (buffers != NULL) {
683
+ buffers[i].iov_base = (void *) part->data;
684
+ buffers[i].iov_len = part->size;
685
+ }
686
+ dataSize += part->size;
687
+ INC_BUFFER_ITER(i);
688
+ part = part->next;
689
+ }
690
+
691
+ stickySessionId = req->session->getStickySessionId();
692
+ stickySessionIdSize = uintSizeAsString(stickySessionId);
693
+ stickySessionIdStr = (char *) psg_pnalloc(req->pool, stickySessionIdSize + 1);
694
+ uintToString(stickySessionId, stickySessionIdStr, stickySessionIdSize + 1);
695
+
696
+ PUSH_STATIC_BUFFER("=");
697
+
698
+ if (buffers != NULL) {
699
+ buffers[i].iov_base = stickySessionIdStr;
700
+ buffers[i].iov_len = stickySessionIdSize;
701
+ }
702
+ dataSize += stickySessionIdSize;
703
+ INC_BUFFER_ITER(i);
704
+
705
+ PUSH_STATIC_BUFFER("; Path=");
706
+
707
+ if (buffers != NULL) {
708
+ buffers[i].iov_base = (void *) baseURI.data();
709
+ buffers[i].iov_len = baseURI.size();
710
+ }
711
+ dataSize += baseURI.size();
712
+ INC_BUFFER_ITER(i);
713
+
714
+ PUSH_STATIC_BUFFER("\r\n");
715
+ }
716
+
664
717
  if (showVersionInHeader) {
665
718
  PUSH_STATIC_BUFFER("X-Powered-By: " PROGRAM_NAME " " PASSENGER_VERSION "\r\n\r\n");
666
719
  } else {
@@ -683,7 +736,7 @@ constructDateHeaderBuffersForResponse(char *dateStr, unsigned int bufsize) {
683
736
 
684
737
  pos = appendData(pos, end, "Date: ");
685
738
  gmtime_r(&the_time, &the_tm);
686
- pos += strftime(pos, end - pos, "%a, %d %b %Y %H:%M:%S %z", &the_tm);
739
+ pos += strftime(pos, end - pos, "%a, %d %b %Y %H:%M:%S GMT", &the_tm);
687
740
  return pos - dateStr;
688
741
  }
689
742
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2011-2014 Phusion
3
+ * Copyright (c) 2011-2015 Phusion
4
4
  *
5
5
  * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  *
@@ -49,7 +49,8 @@ onRequestBegin(Client *client, Request *req) {
49
49
  : req->secureHeaders.lookupCell(PASSENGER_APP_GROUP_NAME);
50
50
  analysis.unionStationSupport = unionStationCore != NULL
51
51
  && getBoolOption(req, UNION_STATION_SUPPORT, false);
52
- req->stickySession = getBoolOption(req, PASSENGER_STICKY_SESSIONS, false);
52
+ req->stickySession = getBoolOption(req, PASSENGER_STICKY_SESSIONS,
53
+ this->stickySessions);
53
54
  req->host = req->headers.lookup(HTTP_HOST);
54
55
 
55
56
  /***************/
@@ -333,7 +334,10 @@ createNewPoolOptions(Client *client, Request *req, const HashedStaticString &app
333
334
  if (appType == NULL || appType->size == 0) {
334
335
  AppTypeDetector detector;
335
336
  PassengerAppType type = detector.checkAppRoot(options.appRoot);
336
- // TODO: check for errors
337
+ if (type == PAT_NONE || type == PAT_ERROR) {
338
+ disconnectWithError(&client, "client did not send a recognized !~PASSENGER_APP_TYPE header");
339
+ return;
340
+ }
337
341
  options.appType = getAppTypeName(type);
338
342
  } else {
339
343
  fillPoolOption(req, options.appType, "!~PASSENGER_APP_TYPE");
@@ -358,7 +362,6 @@ createNewPoolOptions(Client *client, Request *req, const HashedStaticString &app
358
362
  fillPoolOption(req, options.restartDir, "!~PASSENGER_RESTART_DIR");
359
363
  fillPoolOption(req, options.startupFile, "!~PASSENGER_STARTUP_FILE");
360
364
  fillPoolOption(req, options.loadShellEnvvars, "!~PASSENGER_LOAD_SHELL_ENVVARS");
361
- fillPoolOption(req, options.debugger, "!~PASSENGER_DEBUGGER");
362
365
  fillPoolOption(req, options.environmentVariables, "!~PASSENGER_ENV_VARS");
363
366
  fillPoolOption(req, options.raiseInternalError, "!~PASSENGER_RAISE_INTERNAL_ERROR");
364
367
  /******************/
@@ -47,7 +47,7 @@ static void
47
47
  usage(int argc, char *argv[]) {
48
48
  printf("Usage: " AGENT_EXE " <SUBCOMMAND> [options...]\n");
49
49
  printf(PROGRAM_NAME " version " PASSENGER_VERSION ".\n");
50
- printf("Type '%s help <SUBCOMMAND>' for help on a specific subcommand.\n",
50
+ printf("Type '%s <SUBCOMMAND> --help' for help on a specific subcommand.\n",
51
51
  argv[0]);
52
52
  printf("\n");
53
53
  printf("Daemon subcommands:\n");
@@ -69,6 +69,7 @@
69
69
  #include <Hooks.h>
70
70
  #include <ResourceLocator.h>
71
71
  #include <Utils.h>
72
+ #include <Utils/json.h>
72
73
  #include <Utils/Timer.h>
73
74
  #include <Utils/ScopeGuard.h>
74
75
  #include <Utils/StrIntUtils.h>
@@ -106,6 +107,7 @@ namespace WatchdogAgent {
106
107
  uid_t defaultUid;
107
108
  gid_t defaultGid;
108
109
  InstanceDirectoryPtr instanceDir;
110
+ int reportFile;
109
111
  int lockFile;
110
112
  vector<string> cleanupPidfiles;
111
113
  bool pidsCleanedUp;
@@ -118,7 +120,8 @@ namespace WatchdogAgent {
118
120
  AdminServer *adminServer;
119
121
 
120
122
  WorkingObjects()
121
- : pidsCleanedUp(false),
123
+ : reportFile(-1),
124
+ pidsCleanedUp(false),
122
125
  pidFileCleanedUp(false),
123
126
  bgloop(NULL),
124
127
  serverKitContext(NULL),
@@ -582,6 +585,8 @@ usage() {
582
585
  printf(" --no-delete-pid-file Do not delete PID file on exit\n");
583
586
  printf(" --log-file PATH Log to the given file.\n");
584
587
  printf(" --log-level LEVEL Logging level. [A] Default: %d\n", DEFAULT_LOG_LEVEL);
588
+ printf(" --report-file PATH Upon successful initialization, report instance\n");
589
+ printf(" information to the given file, in JSON format\n");
585
590
  printf(" --cleanup-pidfile PATH Upon shutdown, kill the process specified by\n");
586
591
  printf(" the given PID file\n");
587
592
  printf("\n");
@@ -705,6 +710,9 @@ parseOptions(int argc, const char *argv[], VariantMap &options) {
705
710
  } else if (p.isValueFlag(argc, i, argv[i], '\0', "--log-level")) {
706
711
  options.setInt("log_level", atoi(argv[i + 1]));
707
712
  i += 2;
713
+ } else if (p.isValueFlag(argc, i, argv[i], '\0', "--report-file")) {
714
+ options.set("report_file", argv[i + 1]);
715
+ i += 2;
708
716
  } else if (p.isValueFlag(argc, i, argv[i], '\0', "--cleanup-pidfile")) {
709
717
  vector<string> pidfiles = options.getStrSet("cleanup_pidfiles", false);
710
718
  pidfiles.push_back(argv[i + 1]);
@@ -741,7 +749,7 @@ parseOptions(int argc, const char *argv[], VariantMap &options) {
741
749
  }
742
750
 
743
751
  static void
744
- initializeBareEssentials(int argc, char *argv[]) {
752
+ initializeBareEssentials(int argc, char *argv[], WorkingObjectsPtr &wo) {
745
753
  /*
746
754
  * Some Apache installations (like on OS X) redirect stdout to /dev/null,
747
755
  * so that only stderr is redirected to the log file. We therefore
@@ -767,6 +775,9 @@ initializeBareEssentials(int argc, char *argv[]) {
767
775
 
768
776
  // Start all sub-agents with this environment variable.
769
777
  setenv("PASSENGER_USE_FEEDBACK_FD", "true", 1);
778
+
779
+ wo = boost::make_shared<WorkingObjects>();
780
+ workingObjects = wo.get();
770
781
  }
771
782
 
772
783
  static void
@@ -815,7 +826,7 @@ static void
815
826
  redirectStdinToNull() {
816
827
  int fd = open("/dev/null", O_RDONLY);
817
828
  if (fd != -1) {
818
- dup2(fd, 1);
829
+ dup2(fd, 0);
819
830
  close(fd);
820
831
  }
821
832
  }
@@ -829,10 +840,6 @@ maybeDaemonize() {
829
840
  pid = fork();
830
841
  if (pid == 0) {
831
842
  setsid();
832
- if (chdir("/") == -1) {
833
- e = errno;
834
- throw SystemException("Cannot change working directory to /", e);
835
- }
836
843
  redirectStdinToNull();
837
844
  } else if (pid == -1) {
838
845
  e = errno;
@@ -864,6 +871,21 @@ createPidFile() {
864
871
  }
865
872
  }
866
873
 
874
+ static void
875
+ openReportFile(const WorkingObjectsPtr &wo) {
876
+ TRACE_POINT();
877
+ string reportFile = agentsOptions->get("report_file", false);
878
+ if (!reportFile.empty()) {
879
+ int fd = syscalls::open(reportFile.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0600);
880
+ if (fd == -1) {
881
+ int e = errno;
882
+ throw FileSystemException("Cannot open report file " + reportFile, e, reportFile);
883
+ }
884
+
885
+ wo->reportFile = fd;
886
+ }
887
+ }
888
+
867
889
  static void
868
890
  lowerPrivilege() {
869
891
  TRACE_POINT();
@@ -928,7 +950,7 @@ lookupDefaultUidGid(uid_t &uid, gid_t &gid) {
928
950
  }
929
951
 
930
952
  static void
931
- initializeWorkingObjects(WorkingObjectsPtr &wo, InstanceDirToucherPtr &instanceDirToucher) {
953
+ initializeWorkingObjects(const WorkingObjectsPtr &wo, InstanceDirToucherPtr &instanceDirToucher) {
932
954
  TRACE_POINT();
933
955
  VariantMap &options = *agentsOptions;
934
956
  vector<string> strset;
@@ -942,8 +964,6 @@ initializeWorkingObjects(WorkingObjectsPtr &wo, InstanceDirToucherPtr &instanceD
942
964
  (" " SERVER_TOKEN_NAME "/" PASSENGER_VERSION));
943
965
  }
944
966
 
945
- wo = boost::make_shared<WorkingObjects>();
946
- workingObjects = wo.get();
947
967
  wo->resourceLocator = boost::make_shared<ResourceLocator>(agentsOptions->get("passenger_root"));
948
968
 
949
969
  UPDATE_TRACE_POINT();
@@ -1171,17 +1191,30 @@ beginWatchingAgents(const WorkingObjectsPtr &wo, vector<AgentWatcherPtr> &watche
1171
1191
 
1172
1192
  static void
1173
1193
  reportAgentsInformation(const WorkingObjectsPtr &wo, const vector<AgentWatcherPtr> &watchers) {
1194
+ TRACE_POINT();
1195
+ VariantMap report;
1196
+
1197
+ report.set("instance_dir", wo->instanceDir->getPath());
1198
+
1199
+ foreach (AgentWatcherPtr watcher, watchers) {
1200
+ watcher->reportAgentsInformation(report);
1201
+ }
1202
+
1174
1203
  if (feedbackFdAvailable()) {
1175
- TRACE_POINT();
1176
- VariantMap report;
1204
+ report.writeToFd(FEEDBACK_FD, "Agents information");
1205
+ }
1177
1206
 
1178
- report.set("instance_dir", wo->instanceDir->getPath());
1207
+ if (wo->reportFile != -1) {
1208
+ Json::Value doc;
1209
+ VariantMap::ConstIterator it;
1210
+ string str;
1179
1211
 
1180
- foreach (AgentWatcherPtr watcher, watchers) {
1181
- watcher->reportAgentsInformation(report);
1212
+ for (it = report.begin(); it != report.end(); it++) {
1213
+ doc[it->first] = it->second;
1182
1214
  }
1215
+ str = doc.toStyledString();
1183
1216
 
1184
- report.writeToFd(FEEDBACK_FD, "Agents information");
1217
+ writeExact(wo->reportFile, str.data(), str.size());
1185
1218
  }
1186
1219
  }
1187
1220
 
@@ -1214,12 +1247,13 @@ cleanup(const WorkingObjectsPtr &wo) {
1214
1247
 
1215
1248
  int
1216
1249
  watchdogMain(int argc, char *argv[]) {
1217
- initializeBareEssentials(argc, argv);
1250
+ WorkingObjectsPtr wo;
1251
+
1252
+ initializeBareEssentials(argc, argv, wo);
1218
1253
  setAgentsOptionsDefaults();
1219
1254
  sanityCheckOptions();
1220
1255
  P_NOTICE("Starting " AGENT_EXE " watchdog...");
1221
1256
  P_DEBUG("Watchdog options: " << agentsOptions->inspect());
1222
- WorkingObjectsPtr wo;
1223
1257
  InstanceDirToucherPtr instanceDirToucher;
1224
1258
  vector<AgentWatcherPtr> watchers;
1225
1259
 
@@ -1228,6 +1262,7 @@ watchdogMain(int argc, char *argv[]) {
1228
1262
  maybeSetsid();
1229
1263
  maybeDaemonize();
1230
1264
  createPidFile();
1265
+ openReportFile(wo);
1231
1266
  lowerPrivilege();
1232
1267
  initializeWorkingObjects(wo, instanceDirToucher);
1233
1268
  initializeAgentWatchers(wo, watchers);
@@ -1280,7 +1315,7 @@ watchdogMain(int argc, char *argv[]) {
1280
1315
  P_DEBUG("Web server did not exit gracefully, forcing shutdown of all agents...");
1281
1316
  }
1282
1317
  UPDATE_TRACE_POINT();
1283
- runHookScriptAndThrowOnError("after_watchdog_shutdown");
1318
+ runHookScriptAndThrowOnError("before_watchdog_shutdown");
1284
1319
  UPDATE_TRACE_POINT();
1285
1320
  AgentWatcher::stopWatching(watchers);
1286
1321
  if (shouldExitGracefully) {