passenger 5.3.7 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +14 -0
  3. data/build/agent.rb +4 -2
  4. data/build/support/cxx_dependency_map.rb +134 -0
  5. data/resources/templates/standalone/server.erb +1 -0
  6. data/src/agent/AgentMain.cpp +4 -0
  7. data/src/agent/Core/ApplicationPool/Group/StateInspection.cpp +1 -1
  8. data/src/agent/Core/ApplicationPool/Options.h +7 -7
  9. data/src/agent/Core/ApplicationPool/Process.h +3 -0
  10. data/src/agent/Core/Config.h +9 -2
  11. data/src/agent/Core/Controller/Config.h +27 -6
  12. data/src/agent/Core/Controller/InitRequest.cpp +12 -7
  13. data/src/agent/Core/Controller/InitializationAndShutdown.cpp +2 -0
  14. data/src/agent/Core/CoreMain.cpp +62 -33
  15. data/src/agent/Core/OptionParser.h +6 -0
  16. data/src/agent/Core/SpawningKit/Spawner.h +20 -5
  17. data/src/agent/Core/SpawningKit/UserSwitchingRules.h +13 -6
  18. data/src/agent/Core/TelemetryCollector.h +1 -0
  19. data/src/agent/FileReadHelper/FileReadHelperMain.cpp +198 -0
  20. data/src/agent/Watchdog/Config.h +1 -0
  21. data/src/apache2_module/ConfigGeneral/AutoGeneratedDefinitions.cpp +5 -0
  22. data/src/apache2_module/ConfigGeneral/AutoGeneratedSetterFuncs.cpp +15 -0
  23. data/src/apache2_module/DirConfig/AutoGeneratedCreateFunction.cpp +5 -0
  24. data/src/apache2_module/DirConfig/AutoGeneratedManifestGeneration.cpp +13 -0
  25. data/src/apache2_module/DirConfig/AutoGeneratedMergeFunction.cpp +7 -0
  26. data/src/apache2_module/DirConfig/AutoGeneratedStruct.h +13 -0
  27. data/src/apache2_module/DirectoryMapper.h +14 -3
  28. data/src/apache2_module/Hooks.cpp +15 -4
  29. data/src/cxx_supportlib/AppLocalConfigFileUtils.h +148 -0
  30. data/src/cxx_supportlib/AppTypeDetector/CBindings.cpp +12 -1
  31. data/src/cxx_supportlib/AppTypeDetector/CBindings.h +2 -0
  32. data/src/cxx_supportlib/AppTypeDetector/Detector.h +38 -4
  33. data/src/cxx_supportlib/Constants.h +1 -1
  34. data/src/nginx_module/ConfigGeneral/AutoGeneratedDefinitions.c +16 -0
  35. data/src/nginx_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.c +6 -0
  36. data/src/nginx_module/ConfigGeneral/AutoGeneratedSetterFuncs.c +12 -0
  37. data/src/nginx_module/Configuration.c +20 -0
  38. data/src/nginx_module/ContentHandler.c +301 -23
  39. data/src/nginx_module/ContentHandler.h +5 -0
  40. data/src/nginx_module/LocationConfig/AutoGeneratedCreateFunction.c +10 -0
  41. data/src/nginx_module/LocationConfig/AutoGeneratedManifestGeneration.c +27 -0
  42. data/src/nginx_module/LocationConfig/AutoGeneratedMergeFunction.c +3 -0
  43. data/src/nginx_module/LocationConfig/AutoGeneratedStruct.h +7 -0
  44. data/src/nginx_module/ngx_http_passenger_module.h +6 -1
  45. data/src/ruby_supportlib/phusion_passenger.rb +6 -5
  46. data/src/ruby_supportlib/phusion_passenger/apache2/config_options.rb +6 -0
  47. data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +14 -0
  48. data/src/ruby_supportlib/phusion_passenger/standalone/app_finder.rb +1 -0
  49. data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +11 -1
  50. data/src/ruby_supportlib/phusion_passenger/standalone/start_command/builtin_engine.rb +1 -0
  51. metadata +4 -2
@@ -41,6 +41,7 @@ passenger_enabled on;
41
41
  <%= nginx_option(app, :spawn_method) %>
42
42
  <%= nginx_option(app, :app_type) %>
43
43
  <%= nginx_option(app, :startup_file) %>
44
+ <%= nginx_option(app, :app_start_command) %>
44
45
  <%= nginx_option(app, :start_timeout) %>
45
46
  <%= nginx_option(app, :min_instances) %>
46
47
  <%= nginx_option(app, :max_request_queue_size) %>
@@ -36,6 +36,7 @@ int systemMetricsMain(int argc, char *argv[]);
36
36
  int tempDirToucherMain(int argc, char *argv[]);
37
37
  int spawnEnvSetupperMain(int argc, char *argv[]);
38
38
  int execHelperMain(int argc, char *argv[]);
39
+ int fileReadHelperMain(int argc, char *argv[]);
39
40
 
40
41
  static bool
41
42
  isHelp(const char *arg) {
@@ -58,6 +59,7 @@ usage(int argc, char *argv[]) {
58
59
  printf("Utility subcommands:\n");
59
60
  printf(" system-metrics\n");
60
61
  printf(" exec-helper\n");
62
+ printf(" file-read-helper\n");
61
63
  }
62
64
 
63
65
  static bool
@@ -90,6 +92,8 @@ dispatchSubcommand(int argc, char *argv[]) {
90
92
  exit(spawnEnvSetupperMain(argc, argv));
91
93
  } else if (strcmp(argv[1], "exec-helper") == 0) {
92
94
  exit(execHelperMain(argc, argv));
95
+ } else if (strcmp(argv[1], "file-read-helper") == 0) {
96
+ exit(fileReadHelperMain(argc, argv));
93
97
  } else if (strcmp(argv[1], "test-binary") == 0) {
94
98
  printf("PASS\n");
95
99
  exit(0);
@@ -233,7 +233,7 @@ Group::inspectConfigInAdminPanelFormat(Json::Value &result) const {
233
233
 
234
234
  result["type"] = NON_EMPTY_SVAL(options.appType);
235
235
  result["startup_file"] = NON_EMPTY_SVAL(options.startupFile);
236
- result["start_command"] = NON_EMPTY_SVAL(replaceAll(options.startCommand,
236
+ result["start_command"] = NON_EMPTY_SVAL(replaceAll(options.appStartCommand,
237
237
  P_STATIC_STRING("\t"), P_STATIC_STRING(" ")));
238
238
  result["ruby"] = SVAL(options.ruby, DEFAULT_RUBY);
239
239
  result["python"] = SVAL(options.python, DEFAULT_PYTHON);
@@ -85,7 +85,7 @@ private:
85
85
  result.push_back(&options.appGroupName);
86
86
  result.push_back(&options.appLogFile);
87
87
  result.push_back(&options.appType);
88
- result.push_back(&options.startCommand);
88
+ result.push_back(&options.appStartCommand);
89
89
  result.push_back(&options.startupFile);
90
90
  result.push_back(&options.processTitle);
91
91
 
@@ -181,15 +181,15 @@ public:
181
181
  /** The application's type, used for determining the command to invoke to
182
182
  * spawn an application process as well as determining the startup file's
183
183
  * filename. It can be one of the app type names in AppType.cpp, or the
184
- * empty string (default). In case of the latter, 'startCommand' and
184
+ * empty string (default). In case of the latter, 'appStartCommand' and
185
185
  * 'startupFile' (which MUST be set) will dictate the startup command
186
186
  * and the startup file's filename. */
187
187
  StaticString appType;
188
188
 
189
- /** The command for spawning the application process. This is a list of
190
- * arguments, separated by '\t', e.g. "ruby\tfoo.rb". Only used
191
- * during spawning and only if appType.empty(). */
192
- StaticString startCommand;
189
+ /** The shell command string for spawning the application process.
190
+ * Only used during spawning and only if appType.empty().
191
+ */
192
+ StaticString appStartCommand;
193
193
 
194
194
  /** Filename of the application's startup file. Only actually used for
195
195
  * determining user switching info. Only used during spawning. */
@@ -629,7 +629,7 @@ public:
629
629
  } else if (entry.language == P_STATIC_STRING("meteor")) {
630
630
  interpreter = escapeShell(ruby);
631
631
  } else {
632
- return startCommand;
632
+ return appStartCommand;
633
633
  }
634
634
 
635
635
  return interpreter + " " + escapeShell(resourceLocator.getHelperScriptsDir()
@@ -601,6 +601,9 @@ public:
601
601
  if (inputPipe != -1) {
602
602
  inputPipe.close();
603
603
  }
604
+ if (type == SpawningKit::Result::GENERIC) {
605
+ syscalls::kill(getPid(), SIGTERM);
606
+ }
604
607
  }
605
608
 
606
609
  bool shutdownTimeoutExpired() const {
@@ -160,6 +160,7 @@ using namespace std;
160
160
  * server_software string - default("Phusion_Passenger/5.3.7")
161
161
  * show_version_in_header boolean - default(true)
162
162
  * single_app_mode_app_root string - default,read_only
163
+ * single_app_mode_app_start_command string - read_only
163
164
  * single_app_mode_app_type string - read_only
164
165
  * single_app_mode_startup_file string - read_only
165
166
  * standalone_engine string - default
@@ -253,6 +254,10 @@ private:
253
254
  errors.push_back(Error("If '{{multi_app_mode}}' is set,"
254
255
  " then '{{single_app_mode_startup_file}}' may not be set"));
255
256
  }
257
+ if (!config["single_app_mode_app_start_command"].isNull()) {
258
+ errors.push_back(Error("If '{{multi_app_mode}}' is set,"
259
+ " then '{{single_app_mode_app_start_command}}' may not be set"));
260
+ }
256
261
  }
257
262
 
258
263
  static void validateSingleAppMode(const ConfigKit::Store &config,
@@ -264,8 +269,9 @@ private:
264
269
  return;
265
270
  }
266
271
 
267
- // single_app_mode_app_type and single_app_mode_startup_file are
268
- // autodetected in initializeSingleAppMode()
272
+ // single_app_mode_app_type, single_app_mode_startup_file and
273
+ // single_app_mode_app_start_command are autodetected in
274
+ // initializeSingleAppMode() so no need to validate them.
269
275
 
270
276
  ControllerSingleAppModeSchema::validateAppType("single_app_mode_app_type",
271
277
  wrapperRegistry, config, errors);
@@ -425,6 +431,7 @@ public:
425
431
  ControllerSingleAppModeSchema::getDefaultAppRoot);
426
432
  add("single_app_mode_app_type", STRING_TYPE, OPTIONAL | READ_ONLY);
427
433
  add("single_app_mode_startup_file", STRING_TYPE, OPTIONAL | READ_ONLY);
434
+ add("single_app_mode_app_start_command", STRING_TYPE, OPTIONAL | READ_ONLY);
428
435
 
429
436
  // Add subschema: controllerServerKit
430
437
  controllerServerKit.translator.setPrefixAndFinalize("controller_");
@@ -223,9 +223,10 @@ public:
223
223
  * (do not edit: following text is automatically generated
224
224
  * by 'rake configkit_schemas_inline_comments')
225
225
  *
226
- * app_root string - default,read_only
227
- * app_type string required read_only
228
- * startup_file string required read_only
226
+ * app_root string - default,read_only
227
+ * app_start_command string - read_only
228
+ * app_type string - read_only
229
+ * startup_file string - read_only
229
230
  *
230
231
  * END
231
232
  */
@@ -235,9 +236,11 @@ struct ControllerSingleAppModeSchema: public ConfigKit::Schema {
235
236
 
236
237
  addWithDynamicDefault("app_root", STRING_TYPE, OPTIONAL | READ_ONLY | CACHE_DEFAULT_VALUE,
237
238
  getDefaultAppRoot);
238
- add("app_type", STRING_TYPE, REQUIRED | READ_ONLY);
239
- add("startup_file", STRING_TYPE, REQUIRED | READ_ONLY);
239
+ add("app_type", STRING_TYPE, OPTIONAL | READ_ONLY);
240
+ add("startup_file", STRING_TYPE, OPTIONAL | READ_ONLY);
241
+ add("app_start_command", STRING_TYPE, OPTIONAL | READ_ONLY);
240
242
 
243
+ addValidator(validateAppTypeOrAppStartCommandSet);
241
244
  addValidator(boost::bind(validateAppType, "app_type", wrapperRegistry,
242
245
  boost::placeholders::_1, boost::placeholders::_2));
243
246
  addNormalizer(normalizeAppRoot);
@@ -257,6 +260,21 @@ struct ControllerSingleAppModeSchema: public ConfigKit::Schema {
257
260
  return result;
258
261
  }
259
262
 
263
+ static void validateAppTypeOrAppStartCommandSet(const ConfigKit::Store &config,
264
+ vector<ConfigKit::Error> &errors)
265
+ {
266
+ typedef ConfigKit::Error Error;
267
+
268
+ if (config["app_type"].isNull() && config["app_start_command"].isNull()) {
269
+ errors.push_back(Error(
270
+ "Either '{{app_type}}' or '{{app_start_command}}' must be set"));
271
+ }
272
+ if (!config["app_type"].isNull() && config["startup_file"].isNull()) {
273
+ errors.push_back(Error(
274
+ "If '{{app_type}}' is set, then '{{startup_file}}' must also be set"));
275
+ }
276
+ }
277
+
260
278
  static void validateAppType(const string &appTypeKey,
261
279
  const WrapperRegistry::Registry *wrapperRegistry,
262
280
  const ConfigKit::Store &config, vector<ConfigKit::Error> &errors)
@@ -290,7 +308,10 @@ struct ControllerSingleAppModeSchema: public ConfigKit::Schema {
290
308
 
291
309
  static Json::Value normalizeStartupFile(const Json::Value &effectiveValues) {
292
310
  Json::Value updates;
293
- updates["startup_file"] = absolutizePath(effectiveValues["startup_file"].asString());
311
+ if (effectiveValues.isMember("startup_file")) {
312
+ updates["startup_file"] = absolutizePath(
313
+ effectiveValues["startup_file"].asString());
314
+ }
294
315
  return updates;
295
316
  }
296
317
  };
@@ -337,13 +337,18 @@ Controller::createNewPoolOptions(Client *client, Request *req,
337
337
 
338
338
  const LString *appType = secureHeaders.lookup("!~PASSENGER_APP_TYPE");
339
339
  if (appType == NULL || appType->size == 0) {
340
- AppTypeDetector::Detector detector(*wrapperRegistry);
341
- AppTypeDetector::Detector::Result result = detector.checkAppRoot(options.appRoot);
342
- if (result.isNull()) {
343
- disconnectWithError(&client, "client did not send a recognized !~PASSENGER_APP_TYPE header");
344
- return;
340
+ const LString *appStartCommand = secureHeaders.lookup("!~PASSENGER_APP_START_COMMAND");
341
+ if (appStartCommand == NULL || appStartCommand->size == 0) {
342
+ AppTypeDetector::Detector detector(*wrapperRegistry);
343
+ AppTypeDetector::Detector::Result result = detector.checkAppRoot(options.appRoot);
344
+ if (result.isNull()) {
345
+ disconnectWithError(&client, "client did not send a recognized !~PASSENGER_APP_TYPE header");
346
+ return;
347
+ }
348
+ options.appType = result.wrapperRegistryEntry->language;
349
+ } else {
350
+ fillPoolOption(req, options.appStartCommand, "!~PASSENGER_APP_START_COMMAND");
345
351
  }
346
- options.appType = result.wrapperRegistryEntry->language;
347
352
  } else {
348
353
  fillPoolOption(req, options.appType, "!~PASSENGER_APP_TYPE");
349
354
  }
@@ -360,7 +365,7 @@ Controller::createNewPoolOptions(Client *client, Request *req,
360
365
  fillPoolOption(req, options.group, "!~PASSENGER_GROUP");
361
366
  fillPoolOption(req, options.minProcesses, "!~PASSENGER_MIN_PROCESSES");
362
367
  fillPoolOption(req, options.spawnMethod, "!~PASSENGER_SPAWN_METHOD");
363
- fillPoolOption(req, options.startCommand, "!~PASSENGER_START_COMMAND");
368
+ fillPoolOption(req, options.appStartCommand, "!~PASSENGER_APP_START_COMMAND");
364
369
  fillPoolOptionSecToMsec(req, options.startTimeout, "!~PASSENGER_START_TIMEOUT");
365
370
  fillPoolOption(req, options.maxPreloaderIdleTime, "!~PASSENGER_MAX_PRELOADER_IDLE_TIME");
366
371
  fillPoolOption(req, options.maxRequestQueueSize, "!~PASSENGER_MAX_REQUEST_QUEUE_SIZE");
@@ -112,11 +112,13 @@ Controller::initialize() {
112
112
  string environment = config["default_environment"].asString();
113
113
  string appType = singleAppModeConfig->get("app_type").asString();
114
114
  string startupFile = singleAppModeConfig->get("startup_file").asString();
115
+ string appStartCommand = singleAppModeConfig->get("app_start_command").asString();
115
116
 
116
117
  options->appRoot = appRoot;
117
118
  options->environment = environment;
118
119
  options->appType = appType;
119
120
  options->startupFile = startupFile;
121
+ options->appStartCommand = appStartCommand;
120
122
  *options = options->copyAndPersist();
121
123
  poolOptionsCache.insert(options->getAppGroupName(), options);
122
124
  }
@@ -258,53 +258,83 @@ initializeSingleAppMode() {
258
258
  }
259
259
 
260
260
  WorkingObjects *wo = workingObjects;
261
- string appType, startupFile;
261
+ string appType, startupFile, appStartCommand;
262
262
  string appRoot = coreConfig->get("single_app_mode_app_root").asString();
263
263
 
264
- if (coreConfig->get("single_app_mode_app_type").isNull()) {
264
+ if (!coreConfig->get("single_app_mode_app_type").isNull()
265
+ && !coreConfig->get("single_app_mode_app_start_command").isNull())
266
+ {
267
+ fprintf(stderr, "ERROR: it is not allowed for both --app-type and"
268
+ " --app-start-command to be set.\n");
269
+ exit(1);
270
+ }
271
+
272
+ if (!coreConfig->get("single_app_mode_app_start_command").isNull()) {
273
+ // The config specified that this is a generic app or a Kuria app.
274
+ appStartCommand = coreConfig->get("single_app_mode_app_start_command").asString();
275
+ } else if (coreConfig->get("single_app_mode_app_type").isNull()) {
276
+ // Autodetect whether this is generic app, Kuria app or auto-supported app.
265
277
  P_DEBUG("Autodetecting application type...");
266
- AppTypeDetector::Detector detector(*coreWrapperRegistry, NULL, 0);
267
- AppTypeDetector::Detector::Result result = detector.checkAppRoot(appRoot);
268
- if (result.isNull()) {
269
- fprintf(stderr, "ERROR: unable to autodetect what kind of application "
270
- "lives in %s. Please specify information about the app using "
271
- "--app-type and --startup-file, or specify a correct location to "
272
- "the application you want to serve.\n"
273
- "Type '" SHORT_PROGRAM_NAME " core --help' for more information.\n",
274
- appRoot.c_str());
275
- exit(1);
276
- }
278
+ AppTypeDetector::Detector detector(*coreWrapperRegistry);
279
+ AppTypeDetector::Detector::Result detectorResult = detector.checkAppRoot(appRoot);
277
280
 
278
- appType = result.wrapperRegistryEntry->language;
281
+ if (!detectorResult.appStartCommand.empty()) {
282
+ // This is a generic or Kuria app.
283
+ appStartCommand = detectorResult.appStartCommand;
284
+ } else {
285
+ // This is an auto-supported app.
286
+ if (coreConfig->get("single_app_mode_app_type").isNull()) {
287
+ if (detectorResult.isNull()) {
288
+ fprintf(stderr, "ERROR: unable to autodetect what kind of application "
289
+ "lives in %s. Please specify information about the app using "
290
+ "--app-type, --startup-file and --app-start-command, or specify a "
291
+ "correct location to the application you want to serve.\n"
292
+ "Type '" SHORT_PROGRAM_NAME " core --help' for more information.\n",
293
+ appRoot.c_str());
294
+ exit(1);
295
+ }
296
+ appType = detectorResult.wrapperRegistryEntry->language;
297
+ } else {
298
+ appType = coreConfig->get("single_app_mode_app_type").asString();
299
+ }
300
+ }
279
301
  } else {
302
+ // This is an auto-supported app.
280
303
  appType = coreConfig->get("single_app_mode_app_type").asString();
281
304
  }
282
305
 
283
- if (coreConfig->get("single_app_mode_startup_file").isNull()) {
284
- const WrapperRegistry::Entry &entry = coreWrapperRegistry->lookup(appType);
285
- if (entry.defaultStartupFiles.empty()) {
286
- startupFile = appRoot + "/";
306
+ if (!appType.empty()) {
307
+ if (coreConfig->get("single_app_mode_startup_file").isNull()) {
308
+ const WrapperRegistry::Entry &entry = coreWrapperRegistry->lookup(appType);
309
+ if (entry.defaultStartupFiles.empty()) {
310
+ startupFile = appRoot + "/";
311
+ } else {
312
+ startupFile = appRoot + "/" + entry.defaultStartupFiles[0];
313
+ }
287
314
  } else {
288
- startupFile = appRoot + "/" + entry.defaultStartupFiles[0];
315
+ startupFile = coreConfig->get("single_app_mode_startup_file").asString();
316
+ }
317
+ if (!fileExists(startupFile)) {
318
+ fprintf(stderr, "ERROR: unable to find expected startup file %s."
319
+ " Please specify its correct path with --startup-file.\n",
320
+ startupFile.c_str());
321
+ exit(1);
289
322
  }
290
- } else {
291
- startupFile = coreConfig->get("single_app_mode_startup_file").asString();
292
- }
293
- if (!fileExists(startupFile)) {
294
- fprintf(stderr, "ERROR: unable to find expected startup file %s."
295
- " Please specify its correct path with --startup-file.\n",
296
- startupFile.c_str());
297
- exit(1);
298
323
  }
299
324
 
300
325
  wo->singleAppModeConfig["app_root"] = appRoot;
301
- wo->singleAppModeConfig["app_type"] = appType;
302
- wo->singleAppModeConfig["startup_file"] = startupFile;
303
326
 
304
327
  P_NOTICE(SHORT_PROGRAM_NAME " core running in single-application mode.");
305
- P_NOTICE("Serving app : " << appRoot);
306
- P_NOTICE("App type : " << appType);
307
- P_NOTICE("App startup file: " << startupFile);
328
+ P_NOTICE("Serving app : " << appRoot);
329
+ if (!appType.empty()) {
330
+ P_NOTICE("App type : " << appType);
331
+ P_NOTICE("App startup file : " << startupFile);
332
+ wo->singleAppModeConfig["app_type"] = appType;
333
+ wo->singleAppModeConfig["startup_file"] = startupFile;
334
+ } else {
335
+ P_NOTICE("App start command: " << appStartCommand);
336
+ wo->singleAppModeConfig["app_start_command"] = appStartCommand;
337
+ }
308
338
  }
309
339
 
310
340
  static void
@@ -852,7 +882,6 @@ initializeSecurityUpdateChecker() {
852
882
 
853
883
  static void
854
884
  initializeTelemetryCollector() {
855
- return; // disable for now
856
885
  TRACE_POINT();
857
886
  WorkingObjects &wo = *workingObjects;
858
887
 
@@ -109,6 +109,9 @@ coreUsage() {
109
109
  printf(" (single-app mode only)\n");
110
110
  printf(" --startup-file PATH The path of the app's startup file, relative to\n");
111
111
  printf(" the app root directory (single-app mode only)\n");
112
+ printf(" --app-start-command COMMAND\n");
113
+ printf(" The command string with which to start the app\n");
114
+ printf(" (single-app mode only)\n");
112
115
  printf(" --spawn-method NAME Spawn method to use. Can either be 'smart' or\n");
113
116
  printf(" 'direct'. Default: %s\n", DEFAULT_SPAWN_METHOD);
114
117
  printf(" --load-shell-envvars Load shell startup files before loading application\n");
@@ -317,6 +320,9 @@ parseCoreOption(int argc, const char *argv[], int &i, Json::Value &updates) {
317
320
  } else if (p.isValueFlag(argc, i, argv[i], '\0', "--startup-file")) {
318
321
  updates["single_app_mode_startup_file"] = argv[i + 1];
319
322
  i += 2;
323
+ } else if (p.isValueFlag(argc, i, argv[i], '\0', "--app-start-command")) {
324
+ updates["single_app_mode_app_start_command"] = argv[i + 1];
325
+ i += 2;
320
326
  } else if (p.isValueFlag(argc, i, argv[i], '\0', "--spawn-method")) {
321
327
  updates["default_spawn_method"] = argv[i + 1];
322
328
  i += 2;
@@ -31,6 +31,7 @@
31
31
 
32
32
  #include <modp_b64.h>
33
33
 
34
+ #include <AppLocalConfigFileUtils.h>
34
35
  #include <LoggingKit/Logging.h>
35
36
  #include <SystemTools/SystemTime.h>
36
37
  #include <Core/SpawningKit/Context.h>
@@ -79,8 +80,7 @@ protected:
79
80
  void setConfigFromAppPoolOptions(Config *config, Json::Value &extraArgs,
80
81
  const AppPoolOptions &options)
81
82
  {
82
- string startCommand = options.getStartCommand(*context->resourceLocator,
83
- *context->wrapperRegistry);
83
+ TRACE_POINT();
84
84
  string envvarsData;
85
85
  try {
86
86
  envvarsData = modp::b64_decode(options.environmentVariables.data(),
@@ -91,15 +91,30 @@ protected:
91
91
  envvarsData.clear();
92
92
  }
93
93
 
94
+ AppLocalConfig appLocalConfig = parseAppLocalConfigFile(options.appRoot);
95
+ string startCommand;
96
+
97
+ if (appLocalConfig.appSupportsKuriaProtocol) {
98
+ config->genericApp = false;
99
+ config->startsUsingWrapper = false;
100
+ config->startCommand = options.appStartCommand;
101
+ } else if (options.appType.empty()) {
102
+ config->genericApp = true;
103
+ config->startCommand = options.appStartCommand;
104
+ } else {
105
+ startCommand = options.getStartCommand(*context->resourceLocator,
106
+ *context->wrapperRegistry);
107
+ config->genericApp = false;
108
+ config->startsUsingWrapper = true;
109
+ config->startCommand = startCommand;
110
+ }
111
+
94
112
  config->appGroupName = options.getAppGroupName();
95
113
  config->appRoot = options.appRoot;
96
114
  config->logLevel = options.logLevel;
97
- config->genericApp = false;
98
- config->startsUsingWrapper = true;
99
115
  config->wrapperSuppliedByThirdParty = false;
100
116
  config->findFreePort = false;
101
117
  config->loadShellEnvvars = options.loadShellEnvvars;
102
- config->startCommand = startCommand;
103
118
  config->startupFile = options.getStartupFile(*context->wrapperRegistry);
104
119
  config->appType = options.appType;
105
120
  config->appEnv = options.environment;
@@ -98,8 +98,8 @@ prepareUserSwitching(const AppPoolOptions &options,
98
98
 
99
99
  UPDATE_TRACE_POINT();
100
100
  string defaultGroup;
101
- string startupFile = absolutizePath(options.getStartupFile(wrapperRegistry),
102
- absolutizePath(options.appRoot));
101
+ // This is the file that determines what user we lower privilege to.
102
+ string referenceFile;
103
103
  struct passwd &pwd = info.lveUserPwd;
104
104
  boost::shared_array<char> &pwdBuf = info.lveUserPwdStrBuf;
105
105
  struct passwd *userInfo;
@@ -109,6 +109,13 @@ prepareUserSwitching(const AppPoolOptions &options,
109
109
  boost::shared_array<char> grpBuf;
110
110
  int ret;
111
111
 
112
+ if (options.appType.empty()) {
113
+ referenceFile = absolutizePath(options.appRoot);
114
+ } else {
115
+ referenceFile = absolutizePath(options.getStartupFile(wrapperRegistry),
116
+ absolutizePath(options.appRoot));
117
+ }
118
+
112
119
  // _SC_GETPW_R_SIZE_MAX/_SC_GETGR_R_SIZE_MAX are not maximums:
113
120
  // http://tomlee.co/2012/10/problems-with-large-linux-unix-groups-and-getgrgid_r-getgrnam_r/
114
121
  pwdBufSize = std::max<long>(1024 * 128, sysconf(_SC_GETPW_R_SIZE_MAX));
@@ -158,9 +165,9 @@ prepareUserSwitching(const AppPoolOptions &options,
158
165
  }
159
166
  } else {
160
167
  struct stat buf;
161
- if (syscalls::lstat(startupFile.c_str(), &buf) == -1) {
168
+ if (syscalls::lstat(referenceFile.c_str(), &buf) == -1) {
162
169
  int e = errno;
163
- throw SystemException("Cannot lstat(\"" + startupFile +
170
+ throw SystemException("Cannot lstat(\"" + referenceFile +
164
171
  "\")", e);
165
172
  }
166
173
  ret = getpwuid_r(buf.st_uid, &pwd, pwdBuf.get(),
@@ -187,10 +194,10 @@ prepareUserSwitching(const AppPoolOptions &options,
187
194
  if (options.group == "!STARTUP_FILE!") {
188
195
  struct stat buf;
189
196
 
190
- if (syscalls::lstat(startupFile.c_str(), &buf) == -1) {
197
+ if (syscalls::lstat(referenceFile.c_str(), &buf) == -1) {
191
198
  int e = errno;
192
199
  throw SystemException("Cannot lstat(\"" +
193
- startupFile + "\")", e);
200
+ referenceFile + "\")", e);
194
201
  }
195
202
 
196
203
  ret = getgrgid_r(buf.st_gid, &grp, grpBuf.get(), grpBufSize,