passenger 5.1.7 → 5.1.8
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.
- checksums.yaml +4 -4
- data/CHANGELOG +13 -2
- data/CONTRIBUTING.md +1 -1
- data/build/agent.rb +1 -1
- data/build/cxx_tests.rb +6 -0
- data/build/support/cxx_dependency_map.rb +1286 -391
- data/build/support/general.rb +0 -26
- data/resources/templates/standalone/rails_asset_pipeline.erb +2 -2
- data/src/agent/Core/ApiServer.h +49 -44
- data/src/agent/Core/ApplicationPool/Pool.h +1 -1
- data/src/agent/Core/ApplicationPool/Process.h +1 -1
- data/src/agent/Core/ApplicationPool/Socket.h +1 -1
- data/src/agent/Core/Controller.h +16 -8
- data/src/agent/Core/Controller/CheckoutSession.cpp +1 -1
- data/src/agent/Core/Controller/Config.cpp +68 -0
- data/src/agent/Core/Controller/Config.h +70 -34
- data/src/agent/Core/Controller/ForwardResponse.cpp +5 -5
- data/src/agent/Core/Controller/Hooks.cpp +5 -14
- data/src/agent/Core/Controller/Implementation.cpp +1 -1
- data/src/agent/Core/Controller/InitRequest.cpp +31 -29
- data/src/agent/Core/Controller/InitializationAndShutdown.cpp +4 -4
- data/src/agent/Core/Controller/InternalUtils.cpp +3 -3
- data/src/agent/Core/Controller/Miscellaneous.cpp +1 -1
- data/src/agent/Core/Controller/Request.h +2 -2
- data/src/agent/Core/Controller/SendRequest.cpp +5 -5
- data/src/agent/Core/Controller/StateInspection.cpp +1 -1
- data/src/agent/Core/Controller/TurboCaching.h +2 -2
- data/src/agent/Core/CoreMain.cpp +2 -2
- data/src/agent/Core/ResponseCache.h +3 -3
- data/src/agent/Core/SpawningKit/BackgroundIOCapturer.h +3 -3
- data/src/agent/Core/SpawningKit/DirectSpawner.h +2 -2
- data/src/agent/Core/SpawningKit/PipeWatcher.h +3 -3
- data/src/agent/Core/SpawningKit/SmartSpawner.h +2 -2
- data/src/agent/Core/SpawningKit/Spawner.h +1 -1
- data/src/agent/Core/UnionStation/Connection.h +1 -1
- data/src/agent/Core/UnionStation/Context.h +1 -1
- data/src/agent/Core/UnionStation/Transaction.h +1 -1
- data/src/agent/Shared/ApiServerUtils.h +73 -27
- data/src/agent/Shared/Base.cpp +61 -73
- data/src/agent/UstRouter/ApiServer.h +34 -45
- data/src/agent/UstRouter/Controller.h +86 -60
- data/src/agent/UstRouter/RemoteSender.h +1 -1
- data/src/agent/UstRouter/RemoteSink.h +1 -1
- data/src/agent/Watchdog/ApiServer.h +42 -50
- data/src/agent/Watchdog/WatchdogMain.cpp +1 -1
- data/src/apache2_module/Configuration.hpp +1 -1
- data/src/apache2_module/Hooks.cpp +27 -13
- data/src/cxx_supportlib/AppTypes.h +1 -1
- data/src/cxx_supportlib/BackgroundEventLoop.cpp +1 -1
- data/src/cxx_supportlib/ConfigKit/AsyncUtils.h +86 -0
- data/src/cxx_supportlib/ConfigKit/Common.h +6 -3
- data/src/cxx_supportlib/ConfigKit/IN_PRACTICE.md +1039 -0
- data/src/cxx_supportlib/ConfigKit/README.md +112 -497
- data/src/cxx_supportlib/ConfigKit/Schema.h +78 -15
- data/src/cxx_supportlib/ConfigKit/Store.h +272 -53
- data/src/cxx_supportlib/ConfigKit/SubComponentUtils.h +59 -0
- data/src/cxx_supportlib/ConfigKit/Utils.h +26 -65
- data/src/cxx_supportlib/ConfigKit/ValidationUtils.h +69 -0
- data/src/cxx_supportlib/ConfigKit/VariantMapUtils.h +7 -4
- data/src/cxx_supportlib/Constants.h +4 -1
- data/src/cxx_supportlib/Crypto.cpp +1 -1
- data/src/cxx_supportlib/DataStructures/StringKeyTable.h +26 -7
- data/src/cxx_supportlib/FileDescriptor.h +1 -1
- data/src/cxx_supportlib/Hooks.h +1 -1
- data/src/cxx_supportlib/LoggingKit/Assert.h +130 -0
- data/src/cxx_supportlib/LoggingKit/Config.h +97 -0
- data/src/cxx_supportlib/LoggingKit/Context.h +94 -0
- data/src/cxx_supportlib/LoggingKit/Forward.h +95 -0
- data/src/cxx_supportlib/LoggingKit/Implementation.cpp +695 -0
- data/src/cxx_supportlib/LoggingKit/Logging.h +204 -0
- data/src/cxx_supportlib/LoggingKit/LoggingKit.h +33 -0
- data/src/cxx_supportlib/LveLoggingDecorator.h +1 -1
- data/src/cxx_supportlib/MemoryKit/mbuf.cpp +1 -1
- data/src/cxx_supportlib/RandomGenerator.h +1 -1
- data/src/cxx_supportlib/SafeLibev.h +1 -1
- data/src/cxx_supportlib/ServerKit/AcceptLoadBalancer.h +1 -1
- data/src/cxx_supportlib/ServerKit/Channel.h +1 -1
- data/src/cxx_supportlib/ServerKit/FileBufferedChannel.h +1 -1
- data/src/cxx_supportlib/ServerKit/FileBufferedFdSinkChannel.h +1 -1
- data/src/cxx_supportlib/ServerKit/HttpChunkedBodyParser.h +1 -1
- data/src/cxx_supportlib/ServerKit/HttpHeaderParser.h +1 -1
- data/src/cxx_supportlib/ServerKit/HttpServer.h +48 -15
- data/src/cxx_supportlib/ServerKit/Server.h +79 -52
- data/src/cxx_supportlib/StaticString.h +12 -0
- data/src/cxx_supportlib/Utils/Curl.h +16 -0
- data/src/cxx_supportlib/Utils/FastStringStream.h +6 -1
- data/src/cxx_supportlib/Utils/ScopeGuard.h +1 -1
- data/src/cxx_supportlib/Utils/StrIntUtils.cpp +2 -19
- data/src/cxx_supportlib/WatchdogLauncher.h +3 -2
- data/src/ruby_supportlib/phusion_passenger.rb +3 -3
- data/src/ruby_supportlib/phusion_passenger/common_library.rb +12 -12
- data/src/ruby_supportlib/phusion_passenger/constants.rb +6 -3
- data/src/ruby_supportlib/phusion_passenger/standalone/start_command.rb +1 -0
- data/src/ruby_supportlib/phusion_passenger/standalone/stop_command.rb +1 -0
- metadata +14 -4
- data/src/cxx_supportlib/Logging.cpp +0 -295
- data/src/cxx_supportlib/Logging.h +0 -385
@@ -35,7 +35,7 @@
|
|
35
35
|
#include <jsoncpp/json.h>
|
36
36
|
|
37
37
|
#include <Exceptions.h>
|
38
|
-
#include <
|
38
|
+
#include <LoggingKit/LoggingKit.h>
|
39
39
|
#include <ConfigKit/Common.h>
|
40
40
|
#include <ConfigKit/DummyTranslator.h>
|
41
41
|
#include <ConfigKit/Utils.h>
|
@@ -59,16 +59,19 @@ public:
|
|
59
59
|
Type type;
|
60
60
|
Flags flags;
|
61
61
|
ValueGetter defaultValueGetter;
|
62
|
+
ValueFilter inspectFilter;
|
62
63
|
|
63
64
|
Entry()
|
64
65
|
: type(UNKNOWN_TYPE),
|
65
66
|
flags(OPTIONAL)
|
66
67
|
{ }
|
67
68
|
|
68
|
-
Entry(Type _type, Flags _flags, const ValueGetter &_defaultValueGetter
|
69
|
+
Entry(Type _type, Flags _flags, const ValueGetter &_defaultValueGetter,
|
70
|
+
const ValueFilter &_inspectFilter)
|
69
71
|
: type(_type),
|
70
72
|
flags(_flags),
|
71
|
-
defaultValueGetter(_defaultValueGetter)
|
73
|
+
defaultValueGetter(_defaultValueGetter),
|
74
|
+
inspectFilter(_inspectFilter)
|
72
75
|
{ }
|
73
76
|
|
74
77
|
Json::Value inspect() const {
|
@@ -85,18 +88,43 @@ public:
|
|
85
88
|
if (flags & READ_ONLY) {
|
86
89
|
doc["read_only"] = true;
|
87
90
|
}
|
91
|
+
if (flags & SECRET) {
|
92
|
+
doc["secret"] = true;
|
93
|
+
}
|
88
94
|
if (defaultValueGetter) {
|
89
|
-
|
95
|
+
if (flags & _DYNAMIC_DEFAULT_VALUE) {
|
96
|
+
doc["has_default_value"] = "dynamic";
|
97
|
+
} else {
|
98
|
+
doc["has_default_value"] = "static";
|
99
|
+
doc["default_value"] = Schema::getStaticDefaultValue(*this);
|
100
|
+
}
|
90
101
|
}
|
91
102
|
}
|
92
103
|
};
|
93
104
|
|
105
|
+
class EntryBuilder {
|
106
|
+
private:
|
107
|
+
Entry *entry;
|
108
|
+
|
109
|
+
public:
|
110
|
+
EntryBuilder(Entry &_entry)
|
111
|
+
: entry(&_entry)
|
112
|
+
{ }
|
113
|
+
|
114
|
+
EntryBuilder &setInspectFilter(const ValueFilter &filter) {
|
115
|
+
entry->inspectFilter = filter;
|
116
|
+
return *this;
|
117
|
+
}
|
118
|
+
};
|
119
|
+
|
94
120
|
typedef StringKeyTable<Entry>::ConstIterator ConstIterator;
|
95
121
|
typedef boost::function<void (const Store &store, vector<Error> &errors)> Validator;
|
122
|
+
typedef boost::function<Json::Value (const Json::Value &effectiveValues)> Normalizer;
|
96
123
|
|
97
124
|
private:
|
98
125
|
StringKeyTable<Entry> entries;
|
99
126
|
boost::container::vector<Validator> validators;
|
127
|
+
boost::container::vector<Normalizer> normalizers;
|
100
128
|
bool finalized;
|
101
129
|
|
102
130
|
static Json::Value returnJsonValue(const Store &store, Json::Value v) {
|
@@ -114,6 +142,13 @@ private:
|
|
114
142
|
const Schema *subschema, const Translator *translator,
|
115
143
|
const Validator &origValidator);
|
116
144
|
|
145
|
+
template<typename Translator>
|
146
|
+
static Json::Value normalizeSubSchema(const Json::Value &effectiveValues,
|
147
|
+
const Schema *mainSchema, const Schema *subschema,
|
148
|
+
const Translator *translator, const Normalizer &origNormalizer);
|
149
|
+
|
150
|
+
static Json::Value getStaticDefaultValue(const Schema::Entry &entry);
|
151
|
+
|
117
152
|
public:
|
118
153
|
Schema()
|
119
154
|
: finalized(false)
|
@@ -122,28 +157,29 @@ public:
|
|
122
157
|
/**
|
123
158
|
* Register a new schema entry, possibly with a static default value.
|
124
159
|
*/
|
125
|
-
|
160
|
+
EntryBuilder add(const HashedStaticString &key, Type type, unsigned int flags,
|
126
161
|
const Json::Value &defaultValue = Json::Value(Json::nullValue))
|
127
162
|
{
|
128
163
|
assert(!finalized);
|
129
164
|
if (defaultValue.isNull()) {
|
130
|
-
Entry entry(type, (Flags) flags, ValueGetter());
|
131
|
-
entries.insert(key, entry);
|
165
|
+
Entry entry(type, (Flags) flags, ValueGetter(), ValueFilter());
|
166
|
+
return EntryBuilder(entries.insert(key, entry)->value);
|
132
167
|
} else {
|
133
168
|
if (flags & REQUIRED) {
|
134
169
|
throw ArgumentException(
|
135
170
|
"A key cannot be required and have a default value at the same time");
|
136
171
|
}
|
137
172
|
Entry entry(type, (Flags) flags,
|
138
|
-
boost::bind(returnJsonValue, boost::placeholders::_1, defaultValue)
|
139
|
-
|
173
|
+
boost::bind(returnJsonValue, boost::placeholders::_1, defaultValue),
|
174
|
+
ValueFilter());
|
175
|
+
return EntryBuilder(entries.insert(key, entry)->value);
|
140
176
|
}
|
141
177
|
}
|
142
178
|
|
143
179
|
/**
|
144
180
|
* Register a new schema entry with a dynamic default value.
|
145
181
|
*/
|
146
|
-
|
182
|
+
EntryBuilder addWithDynamicDefault(const HashedStaticString &key, Type type, unsigned int flags,
|
147
183
|
const ValueGetter &defaultValueGetter)
|
148
184
|
{
|
149
185
|
if (flags & REQUIRED) {
|
@@ -151,8 +187,9 @@ public:
|
|
151
187
|
"A key cannot be required and have a default value at the same time");
|
152
188
|
}
|
153
189
|
assert(!finalized);
|
154
|
-
Entry entry(type, (Flags) (flags | _DYNAMIC_DEFAULT_VALUE), defaultValueGetter
|
155
|
-
|
190
|
+
Entry entry(type, (Flags) (flags | _DYNAMIC_DEFAULT_VALUE), defaultValueGetter,
|
191
|
+
ValueFilter());
|
192
|
+
return EntryBuilder(entries.insert(key, entry)->value);
|
156
193
|
}
|
157
194
|
|
158
195
|
void addSubSchema(const Schema &subschema) {
|
@@ -182,18 +219,25 @@ public:
|
|
182
219
|
}
|
183
220
|
|
184
221
|
Entry entry2(entry.type, (Flags) (entry.flags | _FROM_SUBSCHEMA),
|
185
|
-
valueGetter);
|
222
|
+
valueGetter, entry.inspectFilter);
|
186
223
|
entries.insert(translator.reverseTranslateOne(key), entry2);
|
187
224
|
it.next();
|
188
225
|
}
|
189
226
|
|
190
|
-
boost::container::vector<
|
227
|
+
boost::container::vector<Validator>::const_iterator v_it, v_end
|
191
228
|
= subschema.getValidators().end();
|
192
229
|
for (v_it = subschema.getValidators().begin(); v_it != v_end; v_it++) {
|
193
230
|
validators.push_back(boost::bind(validateSubSchema<Translator>,
|
194
231
|
boost::placeholders::_1, boost::placeholders::_2,
|
195
232
|
&subschema, &translator, *v_it));
|
196
233
|
}
|
234
|
+
|
235
|
+
boost::container::vector<Normalizer>::const_iterator n_it, n_end
|
236
|
+
= subschema.getNormalizers().end();
|
237
|
+
for (n_it = subschema.getNormalizers().begin(); n_it != n_end; n_it++) {
|
238
|
+
normalizers.push_back(boost::bind(normalizeSubSchema<Translator>,
|
239
|
+
boost::placeholders::_1, this, &subschema, &translator, *n_it));
|
240
|
+
}
|
197
241
|
}
|
198
242
|
|
199
243
|
void addValidator(const Validator &validator) {
|
@@ -201,11 +245,17 @@ public:
|
|
201
245
|
validators.push_back(validator);
|
202
246
|
}
|
203
247
|
|
248
|
+
void addNormalizer(const Normalizer &normalizer) {
|
249
|
+
assert(!finalized);
|
250
|
+
normalizers.push_back(normalizer);
|
251
|
+
}
|
252
|
+
|
204
253
|
void finalize() {
|
205
254
|
assert(!finalized);
|
206
255
|
entries.compact();
|
207
256
|
finalized = true;
|
208
257
|
validators.shrink_to_fit();
|
258
|
+
normalizers.shrink_to_fit();
|
209
259
|
}
|
210
260
|
|
211
261
|
bool get(const HashedStaticString &key, const Entry **entry) const {
|
@@ -241,7 +291,6 @@ public:
|
|
241
291
|
|
242
292
|
switch (entry->type) {
|
243
293
|
case STRING_TYPE:
|
244
|
-
case PASSWORD_TYPE:
|
245
294
|
if (value.isConvertibleTo(Json::stringValue)) {
|
246
295
|
return true;
|
247
296
|
} else {
|
@@ -302,6 +351,15 @@ public:
|
|
302
351
|
error = Error("'{{" + key + "}}' must be an array");
|
303
352
|
return false;
|
304
353
|
}
|
354
|
+
case OBJECT_TYPE:
|
355
|
+
if (value.isObject()) {
|
356
|
+
return true;
|
357
|
+
} else {
|
358
|
+
error = Error("'{{" + key + "}}' must be a JSON object");
|
359
|
+
return false;
|
360
|
+
}
|
361
|
+
case ANY_TYPE:
|
362
|
+
return true;
|
305
363
|
default:
|
306
364
|
P_BUG("Unknown type " + Passenger::toString((int) entry->type));
|
307
365
|
return false;
|
@@ -313,6 +371,11 @@ public:
|
|
313
371
|
return validators;
|
314
372
|
}
|
315
373
|
|
374
|
+
const boost::container::vector<Normalizer> &getNormalizers() const {
|
375
|
+
assert(finalized);
|
376
|
+
return normalizers;
|
377
|
+
}
|
378
|
+
|
316
379
|
ConstIterator getIterator() const {
|
317
380
|
assert(finalized);
|
318
381
|
return ConstIterator(entries);
|
@@ -28,12 +28,24 @@
|
|
28
28
|
|
29
29
|
#include <string>
|
30
30
|
#include <vector>
|
31
|
+
#include <cassert>
|
32
|
+
// for std::swap()
|
33
|
+
#if __cplusplus >= 201103L
|
34
|
+
#include <utility>
|
35
|
+
#else
|
36
|
+
#include <algorithm>
|
37
|
+
#endif
|
38
|
+
#include <boost/config.hpp>
|
39
|
+
|
40
|
+
#include <jsoncpp/json.h>
|
31
41
|
|
32
42
|
#include <ConfigKit/Common.h>
|
33
43
|
#include <ConfigKit/Schema.h>
|
34
44
|
#include <ConfigKit/Utils.h>
|
35
|
-
#include <
|
45
|
+
#include <LoggingKit/Assert.h>
|
46
|
+
#include <Exceptions.h>
|
36
47
|
#include <DataStructures/StringKeyTable.h>
|
48
|
+
#include <Utils/StrIntUtils.h>
|
37
49
|
|
38
50
|
namespace Passenger {
|
39
51
|
namespace ConfigKit {
|
@@ -87,7 +99,7 @@ private:
|
|
87
99
|
}
|
88
100
|
};
|
89
101
|
|
90
|
-
const Schema
|
102
|
+
const Schema *schema;
|
91
103
|
StringKeyTable<Entry> entries;
|
92
104
|
bool updatedOnce;
|
93
105
|
|
@@ -101,8 +113,8 @@ private:
|
|
101
113
|
}
|
102
114
|
}
|
103
115
|
|
104
|
-
static Json::Value
|
105
|
-
if (entry.schemaEntry->
|
116
|
+
static Json::Value maybeFilterSecret(const Entry &entry, const Json::Value &value) {
|
117
|
+
if (entry.schemaEntry->flags & SECRET) {
|
106
118
|
if (value.isNull()) {
|
107
119
|
return Json::nullValue;
|
108
120
|
} else {
|
@@ -113,12 +125,24 @@ private:
|
|
113
125
|
}
|
114
126
|
}
|
115
127
|
|
128
|
+
void initialize() {
|
129
|
+
Schema::ConstIterator it = schema->getIterator();
|
130
|
+
|
131
|
+
while (*it != NULL) {
|
132
|
+
Entry entry(it.getValue());
|
133
|
+
entries.insert(it.getKey(), entry);
|
134
|
+
it.next();
|
135
|
+
}
|
136
|
+
|
137
|
+
entries.compact();
|
138
|
+
}
|
139
|
+
|
116
140
|
bool isWritable(const Entry &entry) const {
|
117
141
|
return !(entry.schemaEntry->flags & READ_ONLY) || !updatedOnce;
|
118
142
|
}
|
119
143
|
|
120
144
|
void applyCustomValidators(const Json::Value &updates, vector<Error> &errors) const {
|
121
|
-
Store tempStore(schema);
|
145
|
+
Store tempStore(*schema);
|
122
146
|
StringKeyTable<Entry>::Iterator it(tempStore.entries);
|
123
147
|
|
124
148
|
while (*it != NULL) {
|
@@ -133,31 +157,157 @@ private:
|
|
133
157
|
}
|
134
158
|
|
135
159
|
boost::container::vector<Schema::Validator>::const_iterator v_it, v_end
|
136
|
-
= schema
|
137
|
-
for (v_it = schema
|
160
|
+
= schema->getValidators().end();
|
161
|
+
for (v_it = schema->getValidators().begin(); v_it != v_end; v_it++) {
|
138
162
|
const Schema::Validator &validator = *v_it;
|
139
163
|
validator(tempStore, errors);
|
140
164
|
}
|
141
165
|
}
|
142
166
|
|
167
|
+
void applyNormalizers(Json::Value &doc) const {
|
168
|
+
boost::container::vector<Schema::Normalizer>::const_iterator n_it, n_end;
|
169
|
+
|
170
|
+
n_it = schema->getNormalizers().begin();
|
171
|
+
n_end = schema->getNormalizers().end();
|
172
|
+
for (; n_it != n_end; n_it++) {
|
173
|
+
const Schema::Normalizer &normalizer = *n_it;
|
174
|
+
Json::Value effectiveValues(Json::objectValue);
|
175
|
+
Json::Value::iterator it, end = doc.end();
|
176
|
+
|
177
|
+
for (it = doc.begin(); it != end; it++) {
|
178
|
+
string name = it.name();
|
179
|
+
effectiveValues[name] = doc[name]["effective_value"];
|
180
|
+
}
|
181
|
+
|
182
|
+
Json::Value updates = normalizer(effectiveValues);
|
183
|
+
if (OXT_UNLIKELY(!updates.isNull() && !updates.isObject())) {
|
184
|
+
P_BUG("ConfigKit normalizers may only return null or object values");
|
185
|
+
}
|
186
|
+
if (updates.isNull() || updates.empty()) {
|
187
|
+
continue;
|
188
|
+
}
|
189
|
+
|
190
|
+
end = updates.end();
|
191
|
+
for (it = updates.begin(); it != end; it++) {
|
192
|
+
string name = it.name();
|
193
|
+
if (doc.isMember(name)) {
|
194
|
+
Json::Value &subdoc = doc[name];
|
195
|
+
subdoc["user_value"] = *it;
|
196
|
+
subdoc["effective_value"] = *it;
|
197
|
+
} else {
|
198
|
+
P_BUG("A ConfigKit normalizer returned a key that is not part of the schema: "
|
199
|
+
<< name);
|
200
|
+
}
|
201
|
+
}
|
202
|
+
}
|
203
|
+
}
|
204
|
+
|
205
|
+
void applyInspectFilters(Json::Value &doc) const {
|
206
|
+
StringKeyTable<Entry>::ConstIterator it(entries);
|
207
|
+
while (*it != NULL) {
|
208
|
+
const Entry &entry = it.getValue();
|
209
|
+
if (entry.schemaEntry->inspectFilter == NULL) {
|
210
|
+
it.next();
|
211
|
+
continue;
|
212
|
+
}
|
213
|
+
|
214
|
+
const HashedStaticString &key = it.getKey();
|
215
|
+
Json::Value &subdoc = doc[key];
|
216
|
+
|
217
|
+
Json::Value &userValue = subdoc["user_value"];
|
218
|
+
userValue = entry.schemaEntry->inspectFilter(userValue);
|
219
|
+
|
220
|
+
if (subdoc.isMember("default_value")) {
|
221
|
+
Json::Value &defaultValue = subdoc["default_value"];
|
222
|
+
defaultValue = entry.schemaEntry->inspectFilter(defaultValue);
|
223
|
+
}
|
224
|
+
|
225
|
+
Json::Value &effectiveValue = subdoc["effective_value"];
|
226
|
+
effectiveValue = entry.schemaEntry->inspectFilter(effectiveValue);
|
227
|
+
|
228
|
+
it.next();
|
229
|
+
}
|
230
|
+
}
|
231
|
+
|
232
|
+
void doFilterSecrets(Json::Value &doc) const {
|
233
|
+
StringKeyTable<Entry>::ConstIterator it(entries);
|
234
|
+
while (*it != NULL) {
|
235
|
+
const HashedStaticString &key = it.getKey();
|
236
|
+
const Entry &entry = it.getValue();
|
237
|
+
Json::Value &subdoc = doc[key];
|
238
|
+
|
239
|
+
Json::Value &userValue = subdoc["user_value"];
|
240
|
+
userValue = maybeFilterSecret(entry, userValue);
|
241
|
+
|
242
|
+
if (subdoc.isMember("default_value")) {
|
243
|
+
Json::Value &defaultValue = subdoc["default_value"];
|
244
|
+
defaultValue = maybeFilterSecret(entry, defaultValue);
|
245
|
+
}
|
246
|
+
|
247
|
+
Json::Value &effectiveValue = subdoc["effective_value"];
|
248
|
+
effectiveValue = maybeFilterSecret(entry, effectiveValue);
|
249
|
+
|
250
|
+
it.next();
|
251
|
+
}
|
252
|
+
}
|
253
|
+
|
143
254
|
public:
|
255
|
+
Store()
|
256
|
+
: schema(NULL),
|
257
|
+
entries(0, 0),
|
258
|
+
updatedOnce(false)
|
259
|
+
{ }
|
260
|
+
|
144
261
|
Store(const Schema &_schema)
|
145
|
-
: schema(_schema),
|
262
|
+
: schema(&_schema),
|
146
263
|
updatedOnce(false)
|
147
264
|
{
|
148
|
-
|
265
|
+
initialize();
|
266
|
+
}
|
149
267
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
268
|
+
Store(const Schema &_schema, const Json::Value &initialValues)
|
269
|
+
: schema(&_schema),
|
270
|
+
updatedOnce(false)
|
271
|
+
{
|
272
|
+
vector<Error> errors;
|
273
|
+
initialize();
|
274
|
+
if (!update(initialValues, errors)) {
|
275
|
+
throw ArgumentException("Invalid initial configuration: "
|
276
|
+
+ toString(errors));
|
154
277
|
}
|
278
|
+
}
|
155
279
|
|
156
|
-
|
280
|
+
template<typename Translator>
|
281
|
+
Store(const Schema &_schema, const Json::Value &initialValues,
|
282
|
+
const Translator &translator)
|
283
|
+
: schema(&_schema),
|
284
|
+
updatedOnce(false)
|
285
|
+
{
|
286
|
+
vector<Error> errors;
|
287
|
+
initialize();
|
288
|
+
if (!update(translator.translate(initialValues), errors)) {
|
289
|
+
errors = translator.reverseTranslate(errors);
|
290
|
+
throw ArgumentException("Invalid initial configuration: "
|
291
|
+
+ toString(errors));
|
292
|
+
}
|
293
|
+
}
|
294
|
+
|
295
|
+
Store(const Store &other, const Json::Value &updates, vector<Error> &errors)
|
296
|
+
: schema(other.schema),
|
297
|
+
updatedOnce(false)
|
298
|
+
{
|
299
|
+
initialize();
|
300
|
+
if (update(other.inspectUserValues(), errors)) {
|
301
|
+
update(updates, errors);
|
302
|
+
}
|
157
303
|
}
|
158
304
|
|
159
305
|
const Schema &getSchema() const {
|
160
|
-
return schema;
|
306
|
+
return *schema;
|
307
|
+
}
|
308
|
+
|
309
|
+
bool hasBeenUpdatedAtLeastOnce() const {
|
310
|
+
return updatedOnce;
|
161
311
|
}
|
162
312
|
|
163
313
|
/**
|
@@ -188,17 +338,22 @@ public:
|
|
188
338
|
* and whether it passes validation, without actually updating the
|
189
339
|
* stored configuration.
|
190
340
|
*
|
191
|
-
* You can use the `forceApplyUpdatePreview` method to apply the result, but
|
192
|
-
* be sure to do that only if validation passes.
|
193
|
-
*
|
194
341
|
* If validation fails then any validation errors will be added to `errors`.
|
195
342
|
*
|
196
343
|
* Any keys in `updates` that are not registered are omitted from the result.
|
197
344
|
* Any keys not in `updates` do not affect existing values stored in the store.
|
198
345
|
*
|
199
|
-
* The format returned by this method is the same as that of `
|
346
|
+
* The format returned by this method is the same as that of `inspect()`,
|
347
|
+
* with the following exceptions:
|
348
|
+
*
|
349
|
+
* - If `filterSecrets` is set to false, values of fields
|
350
|
+
* marked with the `SECRET` flag are not filtered.
|
351
|
+
* - If `shouldApplyInspectFilters` is set to false, values of fields
|
352
|
+
* are not passed through inspect filters.
|
200
353
|
*/
|
201
|
-
Json::Value previewUpdate(const Json::Value &updates, vector<Error> &errors
|
354
|
+
Json::Value previewUpdate(const Json::Value &updates, vector<Error> &errors,
|
355
|
+
bool filterSecrets = true, bool shouldApplyInspectFilters = true) const
|
356
|
+
{
|
202
357
|
if (!updates.isNull() && !updates.isObject()) {
|
203
358
|
errors.push_back(Error("The JSON document must be an object"));
|
204
359
|
return inspect();
|
@@ -206,6 +361,7 @@ public:
|
|
206
361
|
|
207
362
|
Json::Value result(Json::objectValue);
|
208
363
|
StringKeyTable<Entry>::ConstIterator it(entries);
|
364
|
+
vector<Error> tmpErrors;
|
209
365
|
Error error;
|
210
366
|
|
211
367
|
while (*it != NULL) {
|
@@ -213,6 +369,8 @@ public:
|
|
213
369
|
const Entry &entry = it.getValue();
|
214
370
|
Json::Value subdoc(Json::objectValue);
|
215
371
|
|
372
|
+
entry.schemaEntry->inspect(subdoc);
|
373
|
+
|
216
374
|
if (isWritable(entry) && updates.isMember(key)) {
|
217
375
|
subdoc["user_value"] = updates[key];
|
218
376
|
} else {
|
@@ -226,41 +384,33 @@ public:
|
|
226
384
|
subdoc["effective_value"] =
|
227
385
|
getEffectiveValue(subdoc["user_value"],
|
228
386
|
subdoc["default_value"]);
|
229
|
-
if (!schema
|
230
|
-
|
387
|
+
if (!schema->validateValue(it.getKey(), effectiveValue, error)) {
|
388
|
+
tmpErrors.push_back(error);
|
231
389
|
}
|
232
390
|
|
233
|
-
entry.schemaEntry->inspect(subdoc);
|
234
|
-
|
235
391
|
result[it.getKey()] = subdoc;
|
236
392
|
it.next();
|
237
393
|
}
|
238
394
|
|
239
|
-
if (!schema
|
240
|
-
applyCustomValidators(updates,
|
395
|
+
if (!schema->getValidators().empty()) {
|
396
|
+
applyCustomValidators(updates, tmpErrors);
|
241
397
|
}
|
242
398
|
|
243
|
-
|
244
|
-
|
399
|
+
if (tmpErrors.empty()) {
|
400
|
+
applyNormalizers(result);
|
401
|
+
}
|
245
402
|
|
246
|
-
|
247
|
-
|
248
|
-
* validation. Be sure to only call this if you've verified that
|
249
|
-
* `updatePreview()` passes validation, otherwise you will end up
|
250
|
-
* with invalid data in the store.
|
251
|
-
*/
|
252
|
-
void forceApplyUpdatePreview(const Json::Value &preview) {
|
253
|
-
StringKeyTable<Entry>::Iterator it(entries);
|
254
|
-
while (*it != NULL) {
|
255
|
-
Entry &entry = it.getValue();
|
256
|
-
const Json::Value &subdoc =
|
257
|
-
const_cast<const Json::Value &>(preview)[it.getKey()];
|
258
|
-
if (isWritable(entry)) {
|
259
|
-
entry.userValue = subdoc["user_value"];
|
260
|
-
}
|
261
|
-
it.next();
|
403
|
+
if (shouldApplyInspectFilters) {
|
404
|
+
applyInspectFilters(result);
|
262
405
|
}
|
263
|
-
|
406
|
+
|
407
|
+
if (filterSecrets) {
|
408
|
+
doFilterSecrets(result);
|
409
|
+
}
|
410
|
+
|
411
|
+
errors.insert(errors.end(), tmpErrors.begin(), tmpErrors.end());
|
412
|
+
|
413
|
+
return result;
|
264
414
|
}
|
265
415
|
|
266
416
|
/**
|
@@ -273,9 +423,19 @@ public:
|
|
273
423
|
* Any keys not in `updates` do not affect existing values stored in the store.
|
274
424
|
*/
|
275
425
|
bool update(const Json::Value &updates, vector<Error> &errors) {
|
276
|
-
Json::Value preview = previewUpdate(updates, errors);
|
426
|
+
Json::Value preview = previewUpdate(updates, errors, false, false);
|
277
427
|
if (errors.empty()) {
|
278
|
-
|
428
|
+
StringKeyTable<Entry>::Iterator it(entries);
|
429
|
+
while (*it != NULL) {
|
430
|
+
Entry &entry = it.getValue();
|
431
|
+
if (isWritable(entry)) {
|
432
|
+
const Json::Value &subdoc =
|
433
|
+
const_cast<const Json::Value &>(preview)[it.getKey()];
|
434
|
+
entry.userValue = subdoc["user_value"];
|
435
|
+
}
|
436
|
+
it.next();
|
437
|
+
}
|
438
|
+
updatedOnce = true;
|
279
439
|
return true;
|
280
440
|
} else {
|
281
441
|
return false;
|
@@ -292,7 +452,7 @@ public:
|
|
292
452
|
while (*it != NULL) {
|
293
453
|
const HashedStaticString &subSchemaKey = it.getKey();
|
294
454
|
Entry &subSchemaEntry = it.getValue();
|
295
|
-
const
|
455
|
+
const string mainSchemaKey = translator.reverseTranslateOne(
|
296
456
|
subSchemaKey);
|
297
457
|
const Entry *mainSchemaEntry;
|
298
458
|
|
@@ -306,6 +466,12 @@ public:
|
|
306
466
|
return result;
|
307
467
|
}
|
308
468
|
|
469
|
+
void swap(Store &other) BOOST_NOEXCEPT_OR_NOTHROW {
|
470
|
+
std::swap(schema, other.schema);
|
471
|
+
entries.swap(other.entries);
|
472
|
+
std::swap(updatedOnce, other.updatedOnce);
|
473
|
+
}
|
474
|
+
|
309
475
|
/**
|
310
476
|
* Inspects the current store's configuration keys and values in a format
|
311
477
|
* that displays user-supplied and effective values, as well as
|
@@ -320,17 +486,20 @@ public:
|
|
320
486
|
const Entry &entry = it.getValue();
|
321
487
|
Json::Value subdoc(Json::objectValue);
|
322
488
|
|
323
|
-
subdoc["user_value"] = maybeFilterPassword(entry, entry.userValue);
|
324
|
-
if (entry.schemaEntry->defaultValueGetter) {
|
325
|
-
subdoc["default_value"] = maybeFilterPassword(entry, entry.getDefaultValue(*this));
|
326
|
-
}
|
327
|
-
subdoc["effective_value"] = maybeFilterPassword(entry, entry.getEffectiveValue(*this));
|
328
489
|
entry.schemaEntry->inspect(subdoc);
|
490
|
+
subdoc["user_value"] = entry.userValue;
|
491
|
+
subdoc["effective_value"] = entry.getEffectiveValue(*this);
|
492
|
+
if (entry.schemaEntry->defaultValueGetter && entry.schemaEntry->flags & _DYNAMIC_DEFAULT_VALUE) {
|
493
|
+
subdoc["default_value"] = entry.getDefaultValue(*this);
|
494
|
+
}
|
329
495
|
|
330
496
|
result[it.getKey()] = subdoc;
|
331
497
|
it.next();
|
332
498
|
}
|
333
499
|
|
500
|
+
applyInspectFilters(result);
|
501
|
+
doFilterSecrets(result);
|
502
|
+
|
334
503
|
return result;
|
335
504
|
}
|
336
505
|
|
@@ -339,6 +508,7 @@ public:
|
|
339
508
|
* values only. This is like `inspect()` but much less verbose.
|
340
509
|
* See the README's "Inspecting all data" section to learn more
|
341
510
|
* about the format.
|
511
|
+
* Note that values with the SECRET flag are not filtered.
|
342
512
|
*/
|
343
513
|
Json::Value inspectEffectiveValues() const {
|
344
514
|
Json::Value result(Json::objectValue);
|
@@ -352,6 +522,24 @@ public:
|
|
352
522
|
|
353
523
|
return result;
|
354
524
|
}
|
525
|
+
|
526
|
+
/**
|
527
|
+
* Inspects the current store's configuration keys and user
|
528
|
+
* values only. This is like `inspect()` but much less verbose.
|
529
|
+
* Note that values with the SECRET flag are not filtered.
|
530
|
+
*/
|
531
|
+
Json::Value inspectUserValues() const {
|
532
|
+
Json::Value result(Json::objectValue);
|
533
|
+
StringKeyTable<Entry>::ConstIterator it(entries);
|
534
|
+
|
535
|
+
while (*it != NULL) {
|
536
|
+
const Entry &entry = it.getValue();
|
537
|
+
result[it.getKey()] = entry.userValue;
|
538
|
+
it.next();
|
539
|
+
}
|
540
|
+
|
541
|
+
return result;
|
542
|
+
}
|
355
543
|
};
|
356
544
|
|
357
545
|
|
@@ -390,6 +578,37 @@ Schema::validateSubSchema(const Store &store, vector<Error> &errors,
|
|
390
578
|
}
|
391
579
|
}
|
392
580
|
|
581
|
+
template<typename Translator>
|
582
|
+
inline Json::Value
|
583
|
+
Schema::normalizeSubSchema(const Json::Value &effectiveValues,
|
584
|
+
const Schema *mainSchema, const Schema *subschema,
|
585
|
+
const Translator *translator, const Normalizer &origNormalizer)
|
586
|
+
{
|
587
|
+
Json::Value translatedEffectiveValues(Json::objectValue);
|
588
|
+
StringKeyTable<Entry>::ConstIterator it(subschema->entries);
|
589
|
+
|
590
|
+
while (*it != NULL) {
|
591
|
+
const HashedStaticString &subSchemaKey = it.getKey();
|
592
|
+
const string mainSchemaKey = translator->reverseTranslateOne(
|
593
|
+
subSchemaKey);
|
594
|
+
const Entry *mainSchemaEntry;
|
595
|
+
|
596
|
+
if (mainSchema->entries.lookup(mainSchemaKey, &mainSchemaEntry)) {
|
597
|
+
translatedEffectiveValues[subSchemaKey] = effectiveValues[mainSchemaKey];
|
598
|
+
}
|
599
|
+
|
600
|
+
it.next();
|
601
|
+
}
|
602
|
+
|
603
|
+
return translator->reverseTranslate(origNormalizer(translatedEffectiveValues));
|
604
|
+
}
|
605
|
+
|
606
|
+
inline Json::Value
|
607
|
+
Schema::getStaticDefaultValue(const Schema::Entry &entry) {
|
608
|
+
Store::Entry storeEntry(entry);
|
609
|
+
return Store::maybeFilterSecret(storeEntry, storeEntry.getDefaultValue(Store()));
|
610
|
+
}
|
611
|
+
|
393
612
|
|
394
613
|
} // namespace ConfigKit
|
395
614
|
} // namespace Passenger
|