passenger 5.3.4 → 5.3.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +13 -0
  3. data/CODE_OF_CONDUCT.md +1 -1
  4. data/build/cxx_tests.rb +12 -1
  5. data/build/misc.rb +2 -1
  6. data/build/packaging.rb +2 -0
  7. data/build/support/cplusplus.rb +2 -2
  8. data/build/support/cxx_dependency_map.rb +653 -383
  9. data/dev/configkit-schemas/index.json +105 -3
  10. data/dev/show-latest-crashlog-dir +27 -0
  11. data/resources/templates/standalone/http.erb +2 -0
  12. data/src/agent/Core/AdminPanelConnector.h +2 -2
  13. data/src/agent/Core/ApplicationPool/Context.h +5 -1
  14. data/src/agent/Core/ApplicationPool/Group.h +2 -0
  15. data/src/agent/Core/ApplicationPool/Group/LifetimeAndBasics.cpp +5 -0
  16. data/src/agent/Core/ApplicationPool/Group/Miscellaneous.cpp +2 -1
  17. data/src/agent/Core/ApplicationPool/Group/ProcessListManagement.cpp +1 -1
  18. data/src/agent/Core/ApplicationPool/Group/StateInspection.cpp +12 -19
  19. data/src/agent/Core/ApplicationPool/Options.h +35 -31
  20. data/src/agent/Core/ApplicationPool/Pool/GroupUtils.cpp +2 -1
  21. data/src/agent/Core/ApplicationPool/Socket.h +1 -1
  22. data/src/agent/Core/Config.h +38 -7
  23. data/src/agent/Core/ConfigChange.cpp +13 -1
  24. data/src/agent/Core/Controller.h +3 -1
  25. data/src/agent/Core/Controller/Config.h +14 -11
  26. data/src/agent/Core/Controller/InitRequest.cpp +6 -5
  27. data/src/agent/Core/Controller/InitializationAndShutdown.cpp +3 -0
  28. data/src/agent/Core/CoreMain.cpp +149 -34
  29. data/src/agent/Core/OptionParser.h +12 -1
  30. data/src/agent/Core/SpawningKit/Config.h +1 -1
  31. data/src/agent/Core/SpawningKit/Context.h +7 -1
  32. data/src/agent/Core/SpawningKit/Exceptions.h +15 -12
  33. data/src/agent/Core/SpawningKit/README.md +34 -17
  34. data/src/agent/Core/SpawningKit/Spawner.h +5 -3
  35. data/src/agent/Core/SpawningKit/UserSwitchingRules.h +5 -2
  36. data/src/agent/Core/TelemetryCollector.h +674 -0
  37. data/src/agent/Shared/Fundamentals/AbortHandler.cpp +309 -83
  38. data/src/agent/Shared/Fundamentals/AbortHandler.h +18 -3
  39. data/src/agent/Watchdog/Config.h +21 -4
  40. data/src/agent/Watchdog/WatchdogMain.cpp +4 -1
  41. data/src/apache2_module/ConfigGeneral/AutoGeneratedDefinitions.cpp +10 -0
  42. data/src/apache2_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.cpp +5 -0
  43. data/src/apache2_module/ConfigGeneral/AutoGeneratedSetterFuncs.cpp +30 -0
  44. data/src/apache2_module/DirectoryMapper.h +24 -36
  45. data/src/apache2_module/Hooks.cpp +13 -5
  46. data/src/apache2_module/ServerConfig/AutoGeneratedManifestGeneration.cpp +20 -0
  47. data/src/apache2_module/ServerConfig/AutoGeneratedStruct.h +24 -0
  48. data/src/cxx_supportlib/AppTypeDetector/CBindings.cpp +136 -0
  49. data/src/cxx_supportlib/AppTypeDetector/CBindings.h +73 -0
  50. data/src/cxx_supportlib/{AppTypes.h → AppTypeDetector/Detector.h} +59 -132
  51. data/src/cxx_supportlib/ConfigKit/README.md +90 -2
  52. data/src/cxx_supportlib/ConfigKit/Schema.h +58 -13
  53. data/src/cxx_supportlib/ConfigKit/Store.h +128 -4
  54. data/src/cxx_supportlib/Constants.h +1 -1
  55. data/src/cxx_supportlib/ProcessManagement/Ruby.cpp +3 -3
  56. data/src/cxx_supportlib/ProcessManagement/Ruby.h +7 -2
  57. data/src/cxx_supportlib/ProcessManagement/Spawn.cpp +14 -7
  58. data/src/cxx_supportlib/ProcessManagement/Spawn.h +21 -2
  59. data/src/cxx_supportlib/ResourceLocator.h +1 -1
  60. data/src/cxx_supportlib/ServerKit/ClientRef.h +17 -7
  61. data/src/cxx_supportlib/ServerKit/HttpRequestRef.h +17 -7
  62. data/src/cxx_supportlib/Utils/IOUtils.cpp +2 -1
  63. data/src/cxx_supportlib/Utils/ProcessMetricsCollector.h +9 -6
  64. data/src/cxx_supportlib/WrapperRegistry/CBindings.cpp +85 -0
  65. data/src/cxx_supportlib/WrapperRegistry/CBindings.h +56 -0
  66. data/src/cxx_supportlib/WrapperRegistry/Entry.h +112 -0
  67. data/src/cxx_supportlib/WrapperRegistry/README.md +37 -0
  68. data/src/cxx_supportlib/WrapperRegistry/Registry.h +309 -0
  69. data/src/helper-scripts/download_binaries/extconf.rb +6 -2
  70. data/src/nginx_module/ConfigGeneral/AutoGeneratedDefinitions.c +16 -0
  71. data/src/nginx_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.c +6 -0
  72. data/src/nginx_module/ConfigGeneral/AutoGeneratedSetterFuncs.c +24 -0
  73. data/src/nginx_module/ContentHandler.c +34 -13
  74. data/src/nginx_module/ContentHandler.h +3 -3
  75. data/src/nginx_module/MainConfig/AutoGeneratedCreateFunction.c +11 -0
  76. data/src/nginx_module/MainConfig/AutoGeneratedManifestGeneration.c +23 -0
  77. data/src/nginx_module/MainConfig/AutoGeneratedStruct.h +8 -0
  78. data/src/nginx_module/config +2 -1
  79. data/src/nginx_module/ngx_http_passenger_module.c +9 -3
  80. data/src/nginx_module/ngx_http_passenger_module.h +4 -2
  81. data/src/ruby_supportlib/phusion_passenger.rb +2 -1
  82. data/src/ruby_supportlib/phusion_passenger/apache2/config_options.rb +13 -0
  83. data/src/ruby_supportlib/phusion_passenger/common_library.rb +8 -5
  84. data/src/ruby_supportlib/phusion_passenger/config/download_agent_command.rb +6 -2
  85. data/src/ruby_supportlib/phusion_passenger/config/download_nginx_engine_command.rb +6 -2
  86. data/src/ruby_supportlib/phusion_passenger/native_support.rb +7 -3
  87. data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +15 -0
  88. data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +11 -1
  89. data/src/ruby_supportlib/phusion_passenger/standalone/start_command/builtin_engine.rb +3 -1
  90. metadata +12 -4
  91. data/src/cxx_supportlib/AppTypes.cpp +0 -109
@@ -20,6 +20,7 @@ ConfigKit is a configuration management system that lets you define configuratio
20
20
  - [Flags](#flags)
21
21
  - [Defining default values](#defining-default-values)
22
22
  - [Defining custom validators](#defining-custom-validators)
23
+ - [Nested schemas](#nested-schemas)
23
24
  - [Inspecting the schema](#inspecting-the-schema)
24
25
  - [Using the store](#using-the-store)
25
26
  - [Putting data in the store](#putting-data-in-the-store)
@@ -171,9 +172,9 @@ The following types are available:
171
172
  * `UINT_TYPE` -- an unsigned integer.
172
173
  * `FLOAT_TYPE` -- a floating point number.
173
174
  * `BOOL_TYPE` -- a boolean.
174
- * `ARRAY_TYPE` -- an generic array. May contain any values.
175
+ * `ARRAY_TYPE` -- usually a generic array (which may contain any values). But with a special `add()` invocation this can indicate an array of [nested ConfigKit schemas](#nested-schemas).
175
176
  * `STRING_ARRAY_TYPE` -- an array of strings.
176
- * `OBJECT_TYPE` -- a generic JSON object. May contain any values.
177
+ * `OBJECT_TYPE` -- usually a generic JSON object (which may contain any values). But with a special `add()` invocation this can indicate a map of [nested ConfigKit schemas](#nested-schemas).
177
178
  * `ANY_TYPE` -- any JSON value.
178
179
 
179
180
  #### Flags
@@ -227,6 +228,81 @@ Miscellaneous notes about custom validators:
227
228
  - They are always run, even if the normal type validation fails. For example if the caller tries to set the "foo" key to an array value (which is incompatible with the string type), then `myValidator` will still be called.
228
229
  - All registered validators are called. A validator cannot prevent other validators from running.
229
230
 
231
+ ### Nested schemas
232
+
233
+ > **Warning:** do not confuse nested schemas with **subschemas**. The latter is a mechanism for composing multiple schemas together, not a way to define the type of a field.
234
+
235
+ It is possible to define a config field that is an array of objects, or a string map of objects, that should conform to a certain schema. We call such a schema a **nested schema**. For example:
236
+
237
+ ~~~c++
238
+ ConfigKit::Schema personSchema;
239
+ personSchema.add("name", STRING_TYPE, REQUIRED);
240
+ personSchema.add("age", INT_TYPE, OPTIONAL);
241
+ personSchema.finalize();
242
+
243
+ ConfigKit::Schema mainSchema;
244
+ mainSchema.add("people", ARRAY_TYPE, personSchema, REQUIRED);
245
+ mainSchema.add("frobnicate", BOOL_TYPE, OPTIONAL, false);
246
+ mainSchema.finalize();
247
+ ~~~
248
+
249
+ A field with a nested schema is defined by calling `add(<field name>, ARRAY_TYPE or OBJECT_TYPE, <nested schema object>, <flags>)`.
250
+
251
+ The above example mainSchema says the following format is valid:
252
+
253
+ ~~~javascript
254
+ {
255
+ "people": [
256
+ {
257
+ "name": "John",
258
+ "age": 12 // optional
259
+ },
260
+ {
261
+ "name": "Jane"
262
+ },
263
+ // ...
264
+ }
265
+ ],
266
+ "frobinate": boolean-value
267
+ }
268
+ ~~~
269
+
270
+ Nested schema fields simply accept corresponding JSON values, like this:
271
+
272
+ ~~~c++
273
+ Json::Value initialValue;
274
+ initialValue["people"][0]["name"] = "John";
275
+ initialValue["people"][0]["age"] = 12;
276
+ initialValue["people"][1]["name"] = "Jane";
277
+ ConfigKit::Store store(mainSchema, initialValue);
278
+ ~~~
279
+
280
+ Note that it is not possible to define a nested schema field with a default value. This is because the default values are taken from the nested schema. For example, take this code which inserts an empty object into the "people" array:
281
+
282
+ ~~~c++
283
+ ConfigKit::Schema personSchema;
284
+ personSchema.add("name", STRING_TYPE, OPTIONAL, "anonymous");
285
+ personSchema.finalize();
286
+
287
+ ConfigKit::Schema mainSchema;
288
+ mainSchema.add("people", ARRAY_TYPE, personSchema, REQUIRED);
289
+ mainSchema.finalize();
290
+
291
+ Json::Value initialValue;
292
+ initialValue["people"][0] = Json::objectValue;
293
+ ConfigKit::Store store(mainSchema, initialValue);
294
+ ~~~
295
+
296
+ Because personSchema defines a default value of "anonymous" on its "name" field, the above code would result in the following effective values:
297
+
298
+ ~~~json
299
+ {
300
+ "people": [
301
+ { "name": "anonymous" }
302
+ ]
303
+ }
304
+ ~~~
305
+
230
306
  ### Inspecting the schema
231
307
 
232
308
  You can inspect the schema using the `inspect()` method. It returns a Json::Value in the following format:
@@ -248,6 +324,17 @@ You can inspect the schema using the `inspect()` method. It returns a Json::Valu
248
324
  "password": {
249
325
  "type": "string",
250
326
  "secret": true
327
+ },
328
+ "people": {
329
+ "type": "array",
330
+ "nested_schema": {
331
+ "name": {
332
+ "type": "string"
333
+ },
334
+ "age": {
335
+ "type": "integer"
336
+ }
337
+ }
251
338
  }
252
339
  }
253
340
  ~~~
@@ -258,6 +345,7 @@ Description of the members:
258
345
  - `required`: whether this key is required.
259
346
  - `has_default_value`: "static" if a static a default value is defined, "dynamic" if a dynamic default value is defined.
260
347
  - `default_value`: the static default value. This field is absent when there is no default value, or if the default value is dynamic.
348
+ - `nested_schema`: if this field has a [nested schema](#nested-schemas), then a description of that nested schema is stored here.
261
349
 
262
350
  ## Using the store
263
351
 
@@ -60,18 +60,22 @@ public:
60
60
  Flags flags;
61
61
  ValueGetter defaultValueGetter;
62
62
  ValueFilter inspectFilter;
63
+ // Can only be non-NULL when type == ARRAY_TYPE or OBJECT_TYPE.
64
+ const Schema *nestedSchema;
63
65
 
64
66
  Entry()
65
67
  : type(UNKNOWN_TYPE),
66
- flags(OPTIONAL)
68
+ flags(OPTIONAL),
69
+ nestedSchema(NULL)
67
70
  { }
68
71
 
69
72
  Entry(Type _type, Flags _flags, const ValueGetter &_defaultValueGetter,
70
- const ValueFilter &_inspectFilter)
73
+ const ValueFilter &_inspectFilter, const Schema *_nestedSchema = NULL)
71
74
  : type(_type),
72
75
  flags(_flags),
73
76
  defaultValueGetter(_defaultValueGetter),
74
- inspectFilter(_inspectFilter)
77
+ inspectFilter(_inspectFilter),
78
+ nestedSchema(_nestedSchema)
75
79
  { }
76
80
 
77
81
  bool tryTypecastValue(const Json::Value &val, Json::Value &result) const {
@@ -117,25 +121,34 @@ public:
117
121
  return false;
118
122
  }
119
123
  case ARRAY_TYPE:
120
- if (val.isConvertibleTo(Json::arrayValue)) {
121
- result = val;
122
- return true;
124
+ case OBJECT_TYPE: {
125
+ Json::ValueType targetType;
126
+ if (type == ARRAY_TYPE) {
127
+ targetType = Json::arrayValue;
123
128
  } else {
124
- return false;
129
+ targetType = Json::objectValue;
125
130
  }
126
- case OBJECT_TYPE:
127
- if (val.isConvertibleTo(Json::objectValue)) {
128
- result = val;
129
- return true;
131
+ if (val.isConvertibleTo(targetType)) {
132
+ if (nestedSchema != NULL) {
133
+ return tryTypecastArrayOrObjectValueWithNestedSchema(val,
134
+ result, "user_value");
135
+ } else {
136
+ result = val;
137
+ return true;
138
+ }
130
139
  } else {
131
140
  return false;
132
141
  }
142
+ }
133
143
  default:
134
144
  result = val;
135
145
  return true;
136
146
  }
137
147
  }
138
148
 
149
+ bool tryTypecastArrayOrObjectValueWithNestedSchema(const Json::Value &val,
150
+ Json::Value &result, const char *userOrEffectiveValue) const;
151
+
139
152
  Json::Value inspect() const {
140
153
  Json::Value result(Json::objectValue);
141
154
  inspect(result);
@@ -161,6 +174,9 @@ public:
161
174
  doc["default_value"] = Schema::getStaticDefaultValue(*this);
162
175
  }
163
176
  }
177
+ if (nestedSchema != NULL) {
178
+ doc["nested_schema"] = nestedSchema->inspect();
179
+ }
164
180
  }
165
181
  };
166
182
 
@@ -208,6 +224,11 @@ private:
208
224
 
209
225
  static Json::Value getStaticDefaultValue(const Schema::Entry &entry);
210
226
 
227
+ static bool validateNestedSchemaArrayValue(const HashedStaticString &key,
228
+ const Entry &entry, const Json::Value &value, vector<Error> &errors);
229
+ static bool validateNestedSchemaObjectValue(const HashedStaticString &key,
230
+ const Entry &entry, const Json::Value &value, vector<Error> &errors);
231
+
211
232
  public:
212
233
  Schema()
213
234
  : finalized(false)
@@ -237,6 +258,20 @@ public:
237
258
  }
238
259
  }
239
260
 
261
+ /**
262
+ * Register a new schema entry whose value corresponds to a nested schema.
263
+ */
264
+ EntryBuilder add(const HashedStaticString &key, Type type,
265
+ const Schema &nestedSchema, unsigned int flags)
266
+ {
267
+ assert(!finalized);
268
+ assert(nestedSchema.finalized);
269
+ assert(type == ARRAY_TYPE || type == OBJECT_TYPE);
270
+ Entry entry(type, (Flags) flags, ValueGetter(), ValueFilter(),
271
+ &nestedSchema);
272
+ return EntryBuilder(entries.insert(key, entry)->value);
273
+ }
274
+
240
275
  /**
241
276
  * Register a new schema entry with a dynamic default value.
242
277
  */
@@ -407,7 +442,12 @@ public:
407
442
  }
408
443
  case ARRAY_TYPE:
409
444
  if (value.isConvertibleTo(Json::arrayValue)) {
410
- return true;
445
+ if (entry->nestedSchema == NULL) {
446
+ return true;
447
+ } else {
448
+ return validateNestedSchemaArrayValue(key, *entry,
449
+ value, errors);
450
+ }
411
451
  } else {
412
452
  errors.push_back(Error("'{{" + key + "}}' must be an array"));
413
453
  return false;
@@ -428,7 +468,12 @@ public:
428
468
  }
429
469
  case OBJECT_TYPE:
430
470
  if (value.isObject()) {
431
- return true;
471
+ if (entry->nestedSchema == NULL) {
472
+ return true;
473
+ } else {
474
+ return validateNestedSchemaObjectValue(key, *entry,
475
+ value, errors);
476
+ }
432
477
  } else {
433
478
  errors.push_back(Error("'{{" + key + "}}' must be a JSON object"));
434
479
  return false;
@@ -94,8 +94,16 @@ private:
94
94
  Json::Value getEffectiveValue(const Store &store) const {
95
95
  if (userValue.isNull()) {
96
96
  return getDefaultValue(store);
97
- } else {
97
+ } else if (schemaEntry->nestedSchema == NULL) {
98
98
  return userValue;
99
+ } else {
100
+ // The user value may contain nulls that should
101
+ // be populated with the default value from the
102
+ // corresponding nested schema.
103
+ Json::Value result;
104
+ schemaEntry->tryTypecastArrayOrObjectValueWithNestedSchema(
105
+ userValue, result, "effective_value");
106
+ return result;
99
107
  }
100
108
  }
101
109
  };
@@ -105,12 +113,20 @@ private:
105
113
  bool updatedOnce;
106
114
 
107
115
  static Json::Value getEffectiveValue(const Json::Value &userValue,
108
- const Json::Value &defaultValue)
116
+ const Json::Value &defaultValue, const Schema::Entry &schemaEntry)
109
117
  {
110
118
  if (userValue.isNull()) {
111
119
  return defaultValue;
112
- } else {
120
+ } else if (schemaEntry.nestedSchema == NULL) {
113
121
  return userValue;
122
+ } else {
123
+ // The user value may contain nulls that should
124
+ // be populated with the default value from the
125
+ // corresponding nested schema.
126
+ Json::Value result;
127
+ schemaEntry.tryTypecastArrayOrObjectValueWithNestedSchema(
128
+ userValue, result, "effective_value");
129
+ return result;
114
130
  }
115
131
  }
116
132
 
@@ -425,7 +441,8 @@ public:
425
441
  const Json::Value &effectiveValue =
426
442
  subdoc["effective_value"] =
427
443
  getEffectiveValue(subdoc["user_value"],
428
- subdoc["default_value"]);
444
+ subdoc["default_value"],
445
+ *entry.schemaEntry);
429
446
  schema->validateValue(it.getKey(), effectiveValue, tmpErrors);
430
447
 
431
448
  result[it.getKey()] = subdoc;
@@ -585,6 +602,39 @@ public:
585
602
  };
586
603
 
587
604
 
605
+ inline bool
606
+ Schema::Entry::tryTypecastArrayOrObjectValueWithNestedSchema(const Json::Value &val,
607
+ Json::Value &result, const char *userOrEffectiveValue) const
608
+ {
609
+ assert(type == ARRAY_TYPE || type == OBJECT_TYPE);
610
+ assert(nestedSchema != NULL);
611
+ assert(!val.isNull());
612
+ assert(val.isConvertibleTo(Json::arrayValue)
613
+ || val.isConvertibleTo(Json::objectValue));
614
+
615
+ bool ok = true;
616
+ result = val;
617
+
618
+ Json::Value::iterator it, end = result.end();
619
+ for (it = result.begin(); it != end; it++) {
620
+ Json::Value &userSubdoc = *it;
621
+ if (!userSubdoc.isConvertibleTo(Json::objectValue)) {
622
+ ok = false;
623
+ continue;
624
+ }
625
+
626
+ vector<Error> errors;
627
+ Json::Value preview = Store(*nestedSchema).previewUpdate(
628
+ userSubdoc, errors);
629
+ Json::Value::const_iterator p_it, p_end = preview.end();
630
+ for (p_it = preview.begin(); p_it != p_end; p_it++) {
631
+ const Json::Value &previewSubdoc = *p_it;
632
+ userSubdoc[p_it.name()] = previewSubdoc[userOrEffectiveValue];
633
+ }
634
+ }
635
+ return ok;
636
+ }
637
+
588
638
  inline Json::Value
589
639
  Schema::getValueFromSubSchema(
590
640
  const Store &store,
@@ -648,6 +698,80 @@ Schema::getStaticDefaultValue(const Schema::Entry &entry) {
648
698
  return Store::maybeFilterSecret(storeEntry, storeEntry.getDefaultValue(Store()));
649
699
  }
650
700
 
701
+ inline bool
702
+ Schema::validateNestedSchemaArrayValue(const HashedStaticString &key,
703
+ const Schema::Entry &entry, const Json::Value &value, vector<Error> &errors)
704
+ {
705
+ bool warnedAboutNonObjectValue = false;
706
+ bool result = true;
707
+
708
+ Json::Value::const_iterator it, end = value.end();
709
+ for (it = value.begin(); it != end; it++) {
710
+ if (!it->isConvertibleTo(Json::objectValue)) {
711
+ if (!warnedAboutNonObjectValue) {
712
+ warnedAboutNonObjectValue = true;
713
+ result = false;
714
+ errors.push_back(Error(
715
+ "'{{" + key + "}}' may only contain JSON objects"));
716
+ }
717
+ continue;
718
+ }
719
+
720
+ Store store(*entry.nestedSchema);
721
+ vector<Error> nestedSchemaErrors;
722
+ if (store.update(*it, nestedSchemaErrors)) {
723
+ continue;
724
+ }
725
+
726
+ vector<Error>::const_iterator e_it, e_end = nestedSchemaErrors.end();
727
+ for (e_it = nestedSchemaErrors.begin(); e_it != e_end; e_it++) {
728
+ errors.push_back(Error("'{{" + key + "}}' element "
729
+ + Passenger::toString(it.index() + 1) + " is invalid: "
730
+ + e_it->getMessage()));
731
+ }
732
+ result = false;
733
+ }
734
+
735
+ return result;
736
+ }
737
+
738
+ inline bool
739
+ Schema::validateNestedSchemaObjectValue(const HashedStaticString &key,
740
+ const Schema::Entry &entry, const Json::Value &value, vector<Error> &errors)
741
+ {
742
+ bool warnedAboutNonObjectValue = false;
743
+ bool result = true;
744
+
745
+ Json::Value::const_iterator it, end = value.end();
746
+ for (it = value.begin(); it != end; it++) {
747
+ if (!it->isConvertibleTo(Json::objectValue)) {
748
+ if (!warnedAboutNonObjectValue) {
749
+ warnedAboutNonObjectValue = true;
750
+ result = false;
751
+ errors.push_back(Error(
752
+ "'{{" + key + "}}' may only contain JSON objects"));
753
+ }
754
+ continue;
755
+ }
756
+
757
+ Store store(*entry.nestedSchema);
758
+ vector<Error> nestedSchemaErrors;
759
+ if (store.update(*it, nestedSchemaErrors)) {
760
+ continue;
761
+ }
762
+
763
+ vector<Error>::const_iterator e_it, e_end = nestedSchemaErrors.end();
764
+ for (e_it = nestedSchemaErrors.begin(); e_it != e_end; e_it++) {
765
+ errors.push_back(Error("'{{" + key + "}}' key '"
766
+ + it.name() + "' is invalid: "
767
+ + e_it->getMessage()));
768
+ }
769
+ result = false;
770
+ }
771
+
772
+ return result;
773
+ }
774
+
651
775
 
652
776
  } // namespace ConfigKit
653
777
  } // namespace Passenger
@@ -81,7 +81,7 @@
81
81
  #define PASSENGER_API_VERSION_MAJOR 0
82
82
  #define PASSENGER_API_VERSION_MINOR 3
83
83
  #define PASSENGER_DEFAULT_USER "nobody"
84
- #define PASSENGER_VERSION "5.3.4"
84
+ #define PASSENGER_VERSION "5.3.5"
85
85
  #define POOL_HELPER_THREAD_STACK_SIZE 262144
86
86
  #define PROCESS_SHUTDOWN_TIMEOUT 60
87
87
  #define PROCESS_SHUTDOWN_TIMEOUT_DISPLAY "1 minute"
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2017 Phusion Holding B.V.
3
+ * Copyright (c) 2017-2018 Phusion Holding B.V.
4
4
  *
5
5
  * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
6
  * trademarks of Phusion Holding B.V.
@@ -42,7 +42,7 @@ using namespace std;
42
42
  void
43
43
  runInternalRubyTool(const ResourceLocator &resourceLocator,
44
44
  const string &ruby, const vector<string> &args, int *status,
45
- string *output)
45
+ SubprocessOutput *output, size_t maxOutputSize)
46
46
  {
47
47
  string locationConfigFileEnv = "PASSENGER_LOCATION_CONFIGURATION_FILE="
48
48
  + resourceLocator.getInstallSpec();
@@ -95,7 +95,7 @@ runInternalRubyTool(const ResourceLocator &resourceLocator,
95
95
  if (output == NULL) {
96
96
  runCommand(command, info);
97
97
  } else {
98
- runCommandAndCaptureOutput(command, info, *output);
98
+ runCommandAndCaptureOutput(command, info, *output, maxOutputSize);
99
99
  }
100
100
  if (status != NULL) {
101
101
  *status = info.status;