@@ -82,6 +82,7 @@ class PathMatcher {
82
82
// The info associated with each method. The path matcher nodes
83
83
// will hold pointers to MethodData objects in this vector.
84
84
std::vector<std::unique_ptr<MethodData>> methods_;
85
+ bool fully_decode_reserved_expansion_;
85
86
86
87
private:
87
88
friend class PathMatcherBuilder <Method>;
@@ -113,6 +114,16 @@ class PathMatcherBuilder {
113
114
bool Register (const std::string& http_method, const std::string& path,
114
115
const std::string& body_field_path, Method method);
115
116
117
+ // When set to true, URL path parameters will be fully URI-decoded except in
118
+ // cases of single segment matches in reserved expansion, where "%2F" will be
119
+ // left encoded.
120
+ //
121
+ // The default behavior is to not decode RFC 6570 reserved characters in multi
122
+ // segment matches.
123
+ void SetFullyDecodeReservedExpansion (bool value) {
124
+ fully_decode_reserved_expansion_ = value;
125
+ }
126
+
116
127
// Returns a unique_ptr to a thread safe PathMatcher that contains all
117
128
// registered path-WrapperGraph pairs. Note the PathMatchBuilder instance
118
129
// will be moved so cannot use after invoking Build().
@@ -133,6 +144,7 @@ class PathMatcherBuilder {
133
144
std::unordered_set<std::string> custom_verbs_;
134
145
typedef typename PathMatcher<Method>::MethodData MethodData;
135
146
std::vector<std::unique_ptr<MethodData>> methods_;
147
+ bool fully_decode_reserved_expansion_;
136
148
137
149
friend class PathMatcher <Method>;
138
150
};
@@ -260,7 +272,8 @@ std::string UrlUnescapeString(const std::string& part,
260
272
template <class VariableBinding >
261
273
void ExtractBindingsFromPath (const std::vector<HttpTemplate::Variable>& vars,
262
274
const std::vector<std::string>& parts,
263
- std::vector<VariableBinding>* bindings) {
275
+ std::vector<VariableBinding>* bindings,
276
+ const bool fully_decode_reserved_expansion) {
264
277
for (const auto & var : vars) {
265
278
// Determine the subpath bound to the variable based on the
266
279
// [start_segment, end_segment) segment range of the variable.
@@ -281,7 +294,8 @@ void ExtractBindingsFromPath(const std::vector<HttpTemplate::Variable>& vars,
281
294
// Joins parts with "/" to form a path string.
282
295
for (size_t i = var.start_segment ; i < end_segment; ++i) {
283
296
// For multipart matches only unescape non-reserved characters.
284
- binding.value += UrlUnescapeString (parts[i], !is_multipart);
297
+ binding.value += UrlUnescapeString (
298
+ parts[i], fully_decode_reserved_expansion || !is_multipart);
285
299
if (i < end_segment - 1 ) {
286
300
binding.value += " /" ;
287
301
}
@@ -389,7 +403,9 @@ template <class Method>
389
403
PathMatcher<Method>::PathMatcher(PathMatcherBuilder<Method>&& builder)
390
404
: root_ptr_(std::move(builder.root_ptr_)),
391
405
custom_verbs_ (std::move(builder.custom_verbs_)),
392
- methods_(std::move(builder.methods_)) {}
406
+ methods_(std::move(builder.methods_)),
407
+ fully_decode_reserved_expansion_(
408
+ builder.fully_decode_reserved_expansion_) {}
393
409
394
410
// Lookup is a wrapper method for the recursive node Lookup. First, the wrapper
395
411
// splits the request path into slash-separated path parts. Next, the method
@@ -424,7 +440,8 @@ Method PathMatcher<Method>::Lookup(
424
440
MethodData* method_data = reinterpret_cast <MethodData*>(lookup_result.data );
425
441
if (variable_bindings != nullptr ) {
426
442
variable_bindings->clear ();
427
- ExtractBindingsFromPath (method_data->variables , parts, variable_bindings);
443
+ ExtractBindingsFromPath (method_data->variables , parts, variable_bindings,
444
+ fully_decode_reserved_expansion_);
428
445
ExtractBindingsFromQueryParameters (
429
446
query_params, method_data->system_query_parameter_names ,
430
447
variable_bindings);
@@ -461,7 +478,8 @@ Method PathMatcher<Method>::Lookup(const std::string& http_method,
461
478
// Initializes the builder with a root Path Segment
462
479
template <class Method >
463
480
PathMatcherBuilder<Method>::PathMatcherBuilder()
464
- : root_ptr_(new PathMatcherNode()) {}
481
+ : root_ptr_(new PathMatcherNode()),
482
+ fully_decode_reserved_expansion_ (false ) {}
465
483
466
484
template <class Method >
467
485
PathMatcherPtr<Method> PathMatcherBuilder<Method>::Build() {
0 commit comments