/proc/self/cwd/source/extensions/path/uri_template_lib/uri_template.cc
Line | Count | Source (jump to first uncovered line) |
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/str_split.h" |
13 | | #include "absl/strings/string_view.h" |
14 | | #include "re2/re2.h" |
15 | | |
16 | | namespace Envoy { |
17 | | namespace Extensions { |
18 | | namespace UriTemplate { |
19 | | |
20 | | using Internal::ParsedPathPattern; |
21 | | |
22 | | #ifndef SWIG |
23 | | // Silence warnings about missing initializers for members of LazyRE2. |
24 | | #pragma GCC diagnostic ignored "-Wmissing-field-initializers" |
25 | | #endif |
26 | | |
27 | 3.67k | absl::StatusOr<std::string> convertPathPatternSyntaxToRegex(absl::string_view path_pattern) { |
28 | 3.67k | absl::StatusOr<ParsedPathPattern> status = Internal::parsePathPatternSyntax(path_pattern); |
29 | 3.67k | if (!status.ok()) { |
30 | 722 | return status.status(); |
31 | 722 | } |
32 | 2.95k | return Internal::toRegexPattern(*status); |
33 | 3.67k | } |
34 | | |
35 | 2.51k | absl::StatusOr<std::vector<ParsedSegment>> parseRewritePattern(absl::string_view path_pattern) { |
36 | 2.51k | std::vector<ParsedSegment> result; |
37 | | |
38 | | // The pattern should start with a '/' and thus the first segment should |
39 | | // always be a literal. |
40 | 2.51k | if (path_pattern.empty() || path_pattern[0] != '/') { |
41 | 38 | return absl::InvalidArgumentError("Invalid rewrite variable placement"); |
42 | 38 | } |
43 | | |
44 | | // Don't allow contiguous '/' patterns. |
45 | 2.47k | static const LazyRE2 invalid_regex = {"^.*//.*$"}; |
46 | 2.47k | if (RE2::FullMatch(path_pattern, *invalid_regex)) { |
47 | 108 | return absl::InvalidArgumentError("Invalid rewrite literal"); |
48 | 108 | } |
49 | | |
50 | 307k | while (!path_pattern.empty()) { |
51 | 307k | std::vector<absl::string_view> segments1 = |
52 | 307k | absl::StrSplit(path_pattern, absl::MaxSplits('{', 1)); |
53 | 307k | if (!segments1[0].empty()) { |
54 | 305k | if (!Internal::isValidRewriteLiteral(segments1[0])) { |
55 | 274 | return absl::InvalidArgumentError("Invalid rewrite literal pattern"); |
56 | 274 | } |
57 | 305k | result.emplace_back(segments1[0], RewriteStringKind::Literal); |
58 | 305k | } |
59 | | |
60 | 307k | if (segments1.size() < 2) { |
61 | | // No more variable replacement, done. |
62 | 1.47k | break; |
63 | 1.47k | } |
64 | | |
65 | 305k | std::vector<absl::string_view> segments2 = |
66 | 305k | absl::StrSplit(segments1[1], absl::MaxSplits('}', 1)); |
67 | 305k | if (segments2.size() < 2) { |
68 | 54 | return absl::InvalidArgumentError("Unmatched variable bracket"); |
69 | 54 | } |
70 | 305k | path_pattern = segments2[1]; |
71 | | |
72 | 305k | if (!Internal::isValidVariableName(segments2[0])) { |
73 | 196 | return absl::InvalidArgumentError("Invalid variable name"); |
74 | 196 | } |
75 | 305k | result.emplace_back(segments2[0], RewriteStringKind::Variable); |
76 | 305k | } |
77 | 1.84k | return result; |
78 | 2.36k | } |
79 | | |
80 | | absl::StatusOr<RewriteSegments> parseRewritePattern(absl::string_view pattern, |
81 | 760 | absl::string_view capture_regex) { |
82 | 760 | RewriteSegments parsed_pattern; |
83 | 760 | RE2 regex = RE2(capture_regex); |
84 | 760 | if (!regex.ok()) { |
85 | 0 | return absl::InternalError(regex.error()); |
86 | 0 | } |
87 | | |
88 | 760 | absl::StatusOr<std::vector<ParsedSegment>> status = parseRewritePattern(pattern); |
89 | 760 | if (!status.ok()) { |
90 | 0 | return status.status(); |
91 | 0 | } |
92 | 760 | std::vector<ParsedSegment> processed_pattern = *std::move(status); |
93 | | |
94 | 760 | const std::map<std::string, int>& capture_index_map = regex.NamedCapturingGroups(); |
95 | | |
96 | 6.40k | for (const auto& [str, kind] : processed_pattern) { |
97 | 6.40k | switch (kind) { |
98 | 3.36k | case RewriteStringKind::Literal: |
99 | 3.36k | parsed_pattern.push_back(RewriteSegment(std::string(str))); |
100 | 3.36k | break; |
101 | 3.04k | case RewriteStringKind::Variable: |
102 | 3.04k | auto it = capture_index_map.find(std::string(str)); |
103 | 3.04k | if (it == capture_index_map.end()) { |
104 | 39 | return absl::InvalidArgumentError("Nonexisting variable name"); |
105 | 39 | } |
106 | 3.00k | parsed_pattern.push_back(RewriteSegment(it->second)); |
107 | 3.00k | break; |
108 | 6.40k | } |
109 | 6.40k | } |
110 | | |
111 | 721 | return parsed_pattern; |
112 | 760 | } |
113 | | |
114 | 1.86k | absl::Status isValidMatchPattern(absl::string_view path_template_match) { |
115 | 1.86k | return convertPathPatternSyntaxToRegex(path_template_match).status(); |
116 | 1.86k | } |
117 | | |
118 | 810 | absl::Status isValidRewritePattern(absl::string_view path_template_rewrite) { |
119 | 810 | return parseRewritePattern(path_template_rewrite).status(); |
120 | 810 | } |
121 | | |
122 | 751 | absl::Status isValidSharedVariableSet(absl::string_view pattern, absl::string_view capture_regex) { |
123 | 751 | absl::StatusOr<std::string> status = convertPathPatternSyntaxToRegex(capture_regex).value(); |
124 | 751 | if (!status.ok()) { |
125 | 0 | return status.status(); |
126 | 0 | } |
127 | 751 | return parseRewritePattern(pattern, *std::move(status)).status(); |
128 | 751 | } |
129 | | |
130 | | } // namespace UriTemplate |
131 | | } // namespace Extensions |
132 | | } // namespace Envoy |