@@ -82,6 +82,7 @@ class PathMatcher {
8282 // The info associated with each method. The path matcher nodes
8383 // will hold pointers to MethodData objects in this vector.
8484 std::vector<std::unique_ptr<MethodData>> methods_;
85+ bool fully_decode_reserved_expansion_;
8586
8687 private:
8788 friend class PathMatcherBuilder <Method>;
@@ -113,6 +114,16 @@ class PathMatcherBuilder {
113114 bool Register (const std::string& http_method, const std::string& path,
114115 const std::string& body_field_path, Method method);
115116
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+
116127 // Returns a unique_ptr to a thread safe PathMatcher that contains all
117128 // registered path-WrapperGraph pairs. Note the PathMatchBuilder instance
118129 // will be moved so cannot use after invoking Build().
@@ -133,6 +144,7 @@ class PathMatcherBuilder {
133144 std::unordered_set<std::string> custom_verbs_;
134145 typedef typename PathMatcher<Method>::MethodData MethodData;
135146 std::vector<std::unique_ptr<MethodData>> methods_;
147+ bool fully_decode_reserved_expansion_;
136148
137149 friend class PathMatcher <Method>;
138150};
@@ -260,7 +272,8 @@ std::string UrlUnescapeString(const std::string& part,
260272template <class VariableBinding >
261273void ExtractBindingsFromPath (const std::vector<HttpTemplate::Variable>& vars,
262274 const std::vector<std::string>& parts,
263- std::vector<VariableBinding>* bindings) {
275+ std::vector<VariableBinding>* bindings,
276+ const bool fully_decode_reserved_expansion) {
264277 for (const auto & var : vars) {
265278 // Determine the subpath bound to the variable based on the
266279 // [start_segment, end_segment) segment range of the variable.
@@ -281,7 +294,8 @@ void ExtractBindingsFromPath(const std::vector<HttpTemplate::Variable>& vars,
281294 // Joins parts with "/" to form a path string.
282295 for (size_t i = var.start_segment ; i < end_segment; ++i) {
283296 // 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);
285299 if (i < end_segment - 1 ) {
286300 binding.value += " /" ;
287301 }
@@ -389,7 +403,9 @@ template <class Method>
389403PathMatcher<Method>::PathMatcher(PathMatcherBuilder<Method>&& builder)
390404 : root_ptr_(std::move(builder.root_ptr_)),
391405 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_) {}
393409
394410// Lookup is a wrapper method for the recursive node Lookup. First, the wrapper
395411// splits the request path into slash-separated path parts. Next, the method
@@ -424,7 +440,8 @@ Method PathMatcher<Method>::Lookup(
424440 MethodData* method_data = reinterpret_cast <MethodData*>(lookup_result.data );
425441 if (variable_bindings != nullptr ) {
426442 variable_bindings->clear ();
427- ExtractBindingsFromPath (method_data->variables , parts, variable_bindings);
443+ ExtractBindingsFromPath (method_data->variables , parts, variable_bindings,
444+ fully_decode_reserved_expansion_);
428445 ExtractBindingsFromQueryParameters (
429446 query_params, method_data->system_query_parameter_names ,
430447 variable_bindings);
@@ -461,7 +478,8 @@ Method PathMatcher<Method>::Lookup(const std::string& http_method,
461478// Initializes the builder with a root Path Segment
462479template <class Method >
463480PathMatcherBuilder<Method>::PathMatcherBuilder()
464- : root_ptr_(new PathMatcherNode()) {}
481+ : root_ptr_(new PathMatcherNode()),
482+ fully_decode_reserved_expansion_ (false ) {}
465483
466484template <class Method >
467485PathMatcherPtr<Method> PathMatcherBuilder<Method>::Build() {
0 commit comments