Line data Source code
1 : #include "source/extensions/path/uri_template_lib/uri_template.h" 2 : 3 : #include <map> 4 : #include <string> 5 : #include <utility> 6 : #include <vector> 7 : 8 : #include "source/common/http/path_utility.h" 9 : #include "source/extensions/path/uri_template_lib/uri_template_internal.h" 10 : 11 : #include "absl/status/statusor.h" 12 : #include "absl/strings/escaping.h" 13 : #include "absl/strings/str_split.h" 14 : #include "absl/strings/string_view.h" 15 : #include "re2/re2.h" 16 : 17 : namespace Envoy { 18 : namespace Extensions { 19 : namespace UriTemplate { 20 : 21 : using Internal::ParsedPathPattern; 22 : 23 : #ifndef SWIG 24 : // Silence warnings about missing initializers for members of LazyRE2. 25 : #pragma GCC diagnostic ignored "-Wmissing-field-initializers" 26 : #endif 27 : 28 0 : std::ostream& operator<<(std::ostream& os, const ParsedSegment& parsed_segment) { 29 0 : os << "{kind = "; 30 0 : switch (parsed_segment.kind_) { 31 0 : case RewriteStringKind::Variable: 32 0 : os << "Variable"; 33 0 : break; 34 0 : case RewriteStringKind::Literal: 35 0 : os << "Literal"; 36 0 : break; 37 0 : } 38 0 : return os << ", value = \"" << absl::CEscape(parsed_segment.value_) << "\"}"; 39 0 : } 40 : 41 362 : absl::StatusOr<std::string> convertPathPatternSyntaxToRegex(absl::string_view path_pattern) { 42 362 : absl::StatusOr<ParsedPathPattern> status = Internal::parsePathPatternSyntax(path_pattern); 43 362 : if (!status.ok()) { 44 146 : return status.status(); 45 146 : } 46 216 : return Internal::toRegexPattern(*status); 47 362 : } 48 : 49 346 : absl::StatusOr<std::vector<ParsedSegment>> parseRewritePattern(absl::string_view path_pattern) { 50 346 : std::vector<ParsedSegment> result; 51 : 52 : // The pattern should start with a '/' and thus the first segment should 53 : // always be a literal. 54 346 : if (path_pattern.empty() || path_pattern[0] != '/') { 55 3 : return absl::InvalidArgumentError("Invalid rewrite variable placement"); 56 3 : } 57 : 58 : // Don't allow contiguous '/' patterns. 59 343 : static const LazyRE2 invalid_regex = {"^.*//.*$"}; 60 343 : if (RE2::FullMatch(path_pattern, *invalid_regex)) { 61 11 : return absl::InvalidArgumentError("Invalid rewrite literal"); 62 11 : } 63 : 64 834 : while (!path_pattern.empty()) { 65 724 : std::vector<absl::string_view> segments1 = 66 724 : absl::StrSplit(path_pattern, absl::MaxSplits('{', 1)); 67 724 : if (!segments1[0].empty()) { 68 720 : if (!Internal::isValidRewriteLiteral(segments1[0])) { 69 59 : return absl::InvalidArgumentError("Invalid rewrite literal pattern"); 70 59 : } 71 661 : result.emplace_back(segments1[0], RewriteStringKind::Literal); 72 661 : } 73 : 74 665 : if (segments1.size() < 2) { 75 : // No more variable replacement, done. 76 99 : break; 77 99 : } 78 : 79 566 : std::vector<absl::string_view> segments2 = 80 566 : absl::StrSplit(segments1[1], absl::MaxSplits('}', 1)); 81 566 : if (segments2.size() < 2) { 82 15 : return absl::InvalidArgumentError("Unmatched variable bracket"); 83 15 : } 84 551 : path_pattern = segments2[1]; 85 : 86 551 : if (!Internal::isValidVariableName(segments2[0])) { 87 49 : return absl::InvalidArgumentError("Invalid variable name"); 88 49 : } 89 502 : result.emplace_back(segments2[0], RewriteStringKind::Variable); 90 502 : } 91 209 : return result; 92 332 : } 93 : 94 : absl::StatusOr<RewriteSegments> parseRewritePattern(absl::string_view pattern, 95 44 : absl::string_view capture_regex) { 96 44 : RewriteSegments parsed_pattern; 97 44 : RE2 regex = RE2(capture_regex); 98 44 : if (!regex.ok()) { 99 0 : return absl::InternalError(regex.error()); 100 0 : } 101 : 102 44 : absl::StatusOr<std::vector<ParsedSegment>> status = parseRewritePattern(pattern); 103 44 : if (!status.ok()) { 104 0 : return status.status(); 105 0 : } 106 44 : std::vector<ParsedSegment> processed_pattern = *std::move(status); 107 : 108 44 : const std::map<std::string, int>& capture_index_map = regex.NamedCapturingGroups(); 109 : 110 168 : for (const auto& [str, kind] : processed_pattern) { 111 168 : switch (kind) { 112 84 : case RewriteStringKind::Literal: 113 84 : parsed_pattern.push_back(RewriteSegment(std::string(str))); 114 84 : break; 115 84 : case RewriteStringKind::Variable: 116 84 : auto it = capture_index_map.find(std::string(str)); 117 84 : if (it == capture_index_map.end()) { 118 0 : return absl::InvalidArgumentError("Nonexisting variable name"); 119 0 : } 120 84 : parsed_pattern.push_back(RewriteSegment(it->second)); 121 84 : break; 122 168 : } 123 168 : } 124 : 125 44 : return parsed_pattern; 126 44 : } 127 : 128 60 : absl::Status isValidMatchPattern(absl::string_view path_template_match) { 129 60 : return convertPathPatternSyntaxToRegex(path_template_match).status(); 130 60 : } 131 : 132 44 : absl::Status isValidRewritePattern(absl::string_view path_template_rewrite) { 133 44 : return parseRewritePattern(path_template_rewrite).status(); 134 44 : } 135 : 136 44 : absl::Status isValidSharedVariableSet(absl::string_view pattern, absl::string_view capture_regex) { 137 44 : absl::StatusOr<std::string> status = convertPathPatternSyntaxToRegex(capture_regex).value(); 138 44 : if (!status.ok()) { 139 0 : return status.status(); 140 0 : } 141 44 : return parseRewritePattern(pattern, *std::move(status)).status(); 142 44 : } 143 : 144 : } // namespace UriTemplate 145 : } // namespace Extensions 146 : } // namespace Envoy