Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/source/extensions/path/uri_template_lib/uri_template_internal.cc
Line
Count
Source (jump to first uncovered line)
1
#include "source/extensions/path/uri_template_lib/uri_template_internal.h"
2
3
#include <optional>
4
#include <string>
5
#include <type_traits>
6
#include <variant>
7
#include <vector>
8
9
#include "absl/container/flat_hash_set.h"
10
#include "absl/flags/flag.h"
11
#include "absl/functional/function_ref.h"
12
#include "absl/status/status.h"
13
#include "absl/status/statusor.h"
14
#include "absl/strings/match.h"
15
#include "absl/strings/str_cat.h"
16
#include "absl/strings/str_join.h"
17
#include "absl/strings/str_replace.h"
18
#include "absl/strings/str_split.h"
19
#include "absl/strings/string_view.h"
20
#include "absl/types/variant.h"
21
#include "re2/re2.h"
22
23
namespace Envoy {
24
namespace Extensions {
25
namespace UriTemplate {
26
27
namespace Internal {
28
29
namespace {
30
31
#ifndef SWIG
32
// Silence warnings about missing initializers for members of LazyRE2.
33
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
34
#endif
35
36
constexpr unsigned long kPatternMatchingMaxVariablesPerPath = 5;
37
constexpr unsigned long kPatternMatchingMaxVariableNameLen = 16;
38
constexpr unsigned long kPatternMatchingMinVariableNameLen = 1;
39
40
// Valid pchar from https://datatracker.ietf.org/doc/html/rfc3986#appendix-A
41
constexpr absl::string_view kLiteral = "a-zA-Z0-9-._~" // Unreserved
42
                                       "%"             // pct-encoded
43
                                       "!$&'()+,;"     // sub-delims excluding *=
44
                                       ":@"
45
                                       "="; // user included "=" allowed
46
47
// Default operator used for the variable when none specified.
48
constexpr Operator kDefaultVariableOperator = Operator::PathGlob;
49
50
// Visitor for displaying debug info of a ParsedSegment/Variable.var_match.
51
struct ToStringVisitor {
52
  template <typename T> std::string operator()(const T& val) const;
53
};
54
55
// Formatter used to allow joining variants together with StrJoin.
56
struct ToStringFormatter {
57
0
  template <typename T> void operator()(std::string* out, const T& t) const {
58
0
    absl::StrAppend(out, absl::visit(ToStringVisitor(), t));
59
0
  }
Unexecuted instantiation: uri_template_internal.cc:void Envoy::Extensions::UriTemplate::Internal::(anonymous namespace)::ToStringFormatter::operator()<std::__1::variant<Envoy::Extensions::UriTemplate::Internal::Operator, std::__1::basic_string_view<char, std::__1::char_traits<char> > > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, std::__1::variant<Envoy::Extensions::UriTemplate::Internal::Operator, std::__1::basic_string_view<char, std::__1::char_traits<char> > > const&) const
Unexecuted instantiation: uri_template_internal.cc:void Envoy::Extensions::UriTemplate::Internal::(anonymous namespace)::ToStringFormatter::operator()<std::__1::variant<Envoy::Extensions::UriTemplate::Internal::Operator, Envoy::Extensions::UriTemplate::Internal::Variable, std::__1::basic_string_view<char, std::__1::char_traits<char> > > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, std::__1::variant<Envoy::Extensions::UriTemplate::Internal::Operator, Envoy::Extensions::UriTemplate::Internal::Variable, std::__1::basic_string_view<char, std::__1::char_traits<char> > > const&) const
60
};
61
62
// Visitor for converting a ParsedSegment variant to the regex.
63
struct ToRegexPatternVisitor {
64
1.24M
  template <typename T> std::string operator()(const T& val) const { return toRegexPattern(val); }
uri_template_internal.cc:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > Envoy::Extensions::UriTemplate::Internal::(anonymous namespace)::ToRegexPatternVisitor::operator()<Envoy::Extensions::UriTemplate::Internal::Operator>(Envoy::Extensions::UriTemplate::Internal::Operator const&) const
Line
Count
Source
64
930k
  template <typename T> std::string operator()(const T& val) const { return toRegexPattern(val); }
uri_template_internal.cc:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > Envoy::Extensions::UriTemplate::Internal::(anonymous namespace)::ToRegexPatternVisitor::operator()<std::__1::basic_string_view<char, std::__1::char_traits<char> > >(std::__1::basic_string_view<char, std::__1::char_traits<char> > const&) const
Line
Count
Source
64
313k
  template <typename T> std::string operator()(const T& val) const { return toRegexPattern(val); }
uri_template_internal.cc:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > Envoy::Extensions::UriTemplate::Internal::(anonymous namespace)::ToRegexPatternVisitor::operator()<Envoy::Extensions::UriTemplate::Internal::Variable>(Envoy::Extensions::UriTemplate::Internal::Variable const&) const
Line
Count
Source
64
3.71k
  template <typename T> std::string operator()(const T& val) const { return toRegexPattern(val); }
65
};
66
67
// Formatter used to allow joining variants together with StrJoin.
68
struct ToRegexPatternFormatter {
69
1.24M
  template <typename T> void operator()(std::string* out, const T& t) const {
70
1.24M
    absl::StrAppend(out, absl::visit(ToRegexPatternVisitor(), t));
71
1.24M
  }
uri_template_internal.cc:void Envoy::Extensions::UriTemplate::Internal::(anonymous namespace)::ToRegexPatternFormatter::operator()<std::__1::variant<Envoy::Extensions::UriTemplate::Internal::Operator, std::__1::basic_string_view<char, std::__1::char_traits<char> > > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, std::__1::variant<Envoy::Extensions::UriTemplate::Internal::Operator, std::__1::basic_string_view<char, std::__1::char_traits<char> > > const&) const
Line
Count
Source
69
133k
  template <typename T> void operator()(std::string* out, const T& t) const {
70
133k
    absl::StrAppend(out, absl::visit(ToRegexPatternVisitor(), t));
71
133k
  }
uri_template_internal.cc:void Envoy::Extensions::UriTemplate::Internal::(anonymous namespace)::ToRegexPatternFormatter::operator()<std::__1::variant<Envoy::Extensions::UriTemplate::Internal::Operator, Envoy::Extensions::UriTemplate::Internal::Variable, std::__1::basic_string_view<char, std::__1::char_traits<char> > > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, std::__1::variant<Envoy::Extensions::UriTemplate::Internal::Operator, Envoy::Extensions::UriTemplate::Internal::Variable, std::__1::basic_string_view<char, std::__1::char_traits<char> > > const&) const
Line
Count
Source
69
1.11M
  template <typename T> void operator()(std::string* out, const T& t) const {
70
1.11M
    absl::StrAppend(out, absl::visit(ToRegexPatternVisitor(), t));
71
1.11M
  }
72
};
73
74
0
std::string toString(const Literal val) { return std::string(val); }
75
76
0
std::string toString(const Operator val) {
77
0
  switch (val) {
78
0
  case Operator::PathGlob:
79
0
    return "*";
80
0
  case Operator::TextGlob:
81
0
    return "**";
82
0
  }
83
0
  return "";
84
0
}
85
86
0
std::string toString(const Variable val) {
87
0
  if (val.match_.empty()) {
88
0
    return absl::StrCat("{", val.name_, "}");
89
0
  }
90
91
0
  return absl::StrCat("{", val.name_, "=", absl::StrJoin(val.match_, "/", ToStringFormatter()),
92
0
                      "}");
93
0
}
94
95
0
template <typename T> std::string ToStringVisitor::operator()(const T& val) const {
96
0
  return toString(val);
97
0
}
Unexecuted instantiation: uri_template_internal.cc:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > Envoy::Extensions::UriTemplate::Internal::(anonymous namespace)::ToStringVisitor::operator()<Envoy::Extensions::UriTemplate::Internal::Operator>(Envoy::Extensions::UriTemplate::Internal::Operator const&) const
Unexecuted instantiation: uri_template_internal.cc:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > Envoy::Extensions::UriTemplate::Internal::(anonymous namespace)::ToStringVisitor::operator()<std::__1::basic_string_view<char, std::__1::char_traits<char> > >(std::__1::basic_string_view<char, std::__1::char_traits<char> > const&) const
Unexecuted instantiation: uri_template_internal.cc:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > Envoy::Extensions::UriTemplate::Internal::(anonymous namespace)::ToStringVisitor::operator()<Envoy::Extensions::UriTemplate::Internal::Variable>(Envoy::Extensions::UriTemplate::Internal::Variable const&) const
98
99
template <typename T>
100
absl::StatusOr<T>
101
alsoUpdatePattern(absl::FunctionRef<absl::StatusOr<ParsedResult<T>>(absl::string_view)> parse_func,
102
3.93M
                  absl::string_view* patt) {
103
104
3.93M
  absl::StatusOr<ParsedResult<T>> status = parse_func(*patt);
105
3.93M
  if (!status.ok()) {
106
419
    return status.status();
107
419
  }
108
3.93M
  ParsedResult<T> result = *std::move(status);
109
110
3.93M
  *patt = result.unparsed_pattern_;
111
3.93M
  return result.parsed_value_;
112
3.93M
}
uri_template_internal.cc:absl::StatusOr<Envoy::Extensions::UriTemplate::Internal::Operator> Envoy::Extensions::UriTemplate::Internal::(anonymous namespace)::alsoUpdatePattern<Envoy::Extensions::UriTemplate::Internal::Operator>(absl::FunctionRef<absl::StatusOr<Envoy::Extensions::UriTemplate::Internal::ParsedResult<Envoy::Extensions::UriTemplate::Internal::Operator> > (std::__1::basic_string_view<char, std::__1::char_traits<char> >)>, std::__1::basic_string_view<char, std::__1::char_traits<char> >*)
Line
Count
Source
102
3.49M
                  absl::string_view* patt) {
103
104
3.49M
  absl::StatusOr<ParsedResult<T>> status = parse_func(*patt);
105
3.49M
  if (!status.ok()) {
106
0
    return status.status();
107
0
  }
108
3.49M
  ParsedResult<T> result = *std::move(status);
109
110
3.49M
  *patt = result.unparsed_pattern_;
111
3.49M
  return result.parsed_value_;
112
3.49M
}
uri_template_internal.cc:absl::StatusOr<std::__1::basic_string_view<char, std::__1::char_traits<char> > > Envoy::Extensions::UriTemplate::Internal::(anonymous namespace)::alsoUpdatePattern<std::__1::basic_string_view<char, std::__1::char_traits<char> > >(absl::FunctionRef<absl::StatusOr<Envoy::Extensions::UriTemplate::Internal::ParsedResult<std::__1::basic_string_view<char, std::__1::char_traits<char> > > > (std::__1::basic_string_view<char, std::__1::char_traits<char> >)>, std::__1::basic_string_view<char, std::__1::char_traits<char> >*)
Line
Count
Source
102
417k
                  absl::string_view* patt) {
103
104
417k
  absl::StatusOr<ParsedResult<T>> status = parse_func(*patt);
105
417k
  if (!status.ok()) {
106
235
    return status.status();
107
235
  }
108
417k
  ParsedResult<T> result = *std::move(status);
109
110
417k
  *patt = result.unparsed_pattern_;
111
417k
  return result.parsed_value_;
112
417k
}
uri_template_internal.cc:absl::StatusOr<Envoy::Extensions::UriTemplate::Internal::Variable> Envoy::Extensions::UriTemplate::Internal::(anonymous namespace)::alsoUpdatePattern<Envoy::Extensions::UriTemplate::Internal::Variable>(absl::FunctionRef<absl::StatusOr<Envoy::Extensions::UriTemplate::Internal::ParsedResult<Envoy::Extensions::UriTemplate::Internal::Variable> > (std::__1::basic_string_view<char, std::__1::char_traits<char> >)>, std::__1::basic_string_view<char, std::__1::char_traits<char> >*)
Line
Count
Source
102
20.0k
                  absl::string_view* patt) {
103
104
20.0k
  absl::StatusOr<ParsedResult<T>> status = parse_func(*patt);
105
20.0k
  if (!status.ok()) {
106
184
    return status.status();
107
184
  }
108
19.8k
  ParsedResult<T> result = *std::move(status);
109
110
19.8k
  *patt = result.unparsed_pattern_;
111
19.8k
  return result.parsed_value_;
112
20.0k
}
113
114
} // namespace
115
116
0
std::string Variable::debugString() const { return toString(*this); }
117
118
0
std::string ParsedPathPattern::debugString() const {
119
0
  return absl::StrCat("/", absl::StrJoin(parsed_segments_, "/", ToStringFormatter()), suffix_);
120
0
}
121
122
417k
bool isValidLiteral(absl::string_view literal) {
123
417k
  static const std::string* kValidLiteralRegex =
124
417k
      new std::string(absl::StrCat("^[", kLiteral, "]+$"));
125
417k
  static const LazyRE2 literal_regex = {kValidLiteralRegex->data()};
126
417k
  return RE2::FullMatch(literal, *literal_regex);
127
417k
}
128
129
305k
bool isValidRewriteLiteral(absl::string_view literal) {
130
305k
  static const std::string* kValidLiteralRegex =
131
305k
      new std::string(absl::StrCat("^[", kLiteral, "/]+$"));
132
305k
  static const LazyRE2 literal_regex = {kValidLiteralRegex->data()};
133
305k
  return RE2::FullMatch(literal, *literal_regex);
134
305k
}
135
136
325k
bool isValidVariableName(absl::string_view variable) {
137
325k
  static const LazyRE2 variable_regex = {"^[a-zA-Z][a-zA-Z0-9_]*$"};
138
325k
  return RE2::FullMatch(variable, *variable_regex);
139
325k
}
140
141
417k
absl::StatusOr<ParsedResult<Literal>> parseLiteral(absl::string_view pattern) {
142
417k
  absl::string_view literal =
143
417k
      std::vector<absl::string_view>(absl::StrSplit(pattern, absl::MaxSplits('/', 1)))[0];
144
417k
  absl::string_view unparsed_pattern = pattern.substr(literal.size());
145
417k
  if (!isValidLiteral(literal)) {
146
235
    return absl::InvalidArgumentError("Invalid literal");
147
235
  }
148
417k
  return ParsedResult<Literal>(literal, unparsed_pattern);
149
417k
}
150
151
3.49M
absl::StatusOr<ParsedResult<Operator>> parseOperator(absl::string_view pattern) {
152
3.49M
  if (absl::StartsWith(pattern, "**")) {
153
1.23k
    return ParsedResult<Operator>(Operator::TextGlob, pattern.substr(2));
154
1.23k
  }
155
3.49M
  if (absl::StartsWith(pattern, "*")) {
156
3.49M
    return ParsedResult<Operator>(Operator::PathGlob, pattern.substr(1));
157
3.49M
  }
158
0
  return absl::InvalidArgumentError("Invalid Operator");
159
3.49M
}
160
161
20.0k
absl::StatusOr<ParsedResult<Variable>> parseVariable(absl::string_view pattern) {
162
  // Locate the variable pattern to parse.
163
20.0k
  if (pattern.size() < 2 || (pattern)[0] != '{') {
164
27
    return absl::InvalidArgumentError("Invalid variable");
165
27
  }
166
20.0k
  std::vector<absl::string_view> parts = absl::StrSplit(pattern.substr(1), absl::MaxSplits('}', 1));
167
20.0k
  if (parts.size() != 2) {
168
23
    return absl::InvalidArgumentError("Unmatched variable bracket");
169
23
  }
170
20.0k
  absl::string_view unparsed_pattern = parts[1];
171
172
  // Parse the actual variable pattern, starting with the variable name.
173
20.0k
  std::vector<absl::string_view> variable_parts = absl::StrSplit(parts[0], absl::MaxSplits('=', 1));
174
20.0k
  if (!isValidVariableName(variable_parts[0])) {
175
36
    return absl::InvalidArgumentError("Invalid variable name");
176
36
  }
177
19.9k
  Variable var = Variable(variable_parts[0], {});
178
179
  // Parse the variable match pattern (if any).
180
19.9k
  if (variable_parts.size() < 2) {
181
18.7k
    return ParsedResult<Variable>(var, unparsed_pattern);
182
18.7k
  }
183
1.24k
  absl::string_view pattern_item = variable_parts[1];
184
1.24k
  if (pattern_item.empty()) {
185
15
    return absl::InvalidArgumentError("Empty variable match");
186
15
  }
187
1.91M
  while (!pattern_item.empty()) {
188
1.91M
    absl::variant<Operator, Literal> match;
189
1.91M
    if (pattern_item[0] == '*') {
190
191
1.90M
      absl::StatusOr<Operator> status = alsoUpdatePattern<Operator>(parseOperator, &pattern_item);
192
1.90M
      if (!status.ok()) {
193
0
        return status.status();
194
0
      }
195
1.90M
      match = *std::move(status);
196
197
1.90M
    } else {
198
6.83k
      absl::StatusOr<Literal> status = alsoUpdatePattern<Literal>(parseLiteral, &pattern_item);
199
6.83k
      if (!status.ok()) {
200
46
        return status.status();
201
46
      }
202
6.78k
      match = *std::move(status);
203
6.78k
    }
204
1.91M
    var.match_.push_back(match);
205
1.91M
    if (!pattern_item.empty()) {
206
1.91M
      if (pattern_item[0] != '/' || pattern_item.size() == 1) {
207
37
        return absl::InvalidArgumentError("Invalid variable match");
208
37
      }
209
1.91M
      pattern_item = pattern_item.substr(1);
210
1.91M
    }
211
1.91M
  }
212
213
1.14k
  return ParsedResult<Variable>(var, unparsed_pattern);
214
1.22k
}
215
216
absl::StatusOr<absl::flat_hash_set<absl::string_view>>
217
3.14k
gatherCaptureNames(const struct ParsedPathPattern& pattern) {
218
3.14k
  absl::flat_hash_set<absl::string_view> captured_variables;
219
220
1.48M
  for (const ParsedSegment& segment : pattern.parsed_segments_) {
221
1.48M
    if (!absl::holds_alternative<Variable>(segment)) {
222
1.48M
      continue;
223
1.48M
    }
224
4.16k
    if (captured_variables.size() >= kPatternMatchingMaxVariablesPerPath) {
225
25
      return absl::InvalidArgumentError("Exceeded variable count limit");
226
25
    }
227
4.13k
    absl::string_view name = absl::get<Variable>(segment).name_;
228
229
4.13k
    if (name.size() < kPatternMatchingMinVariableNameLen ||
230
4.13k
        name.size() > kPatternMatchingMaxVariableNameLen) {
231
55
      return absl::InvalidArgumentError("Invalid variable name length");
232
55
    }
233
4.08k
    if (captured_variables.contains(name)) {
234
63
      return absl::InvalidArgumentError("Repeated variable name");
235
63
    }
236
4.02k
    captured_variables.emplace(name);
237
4.02k
  }
238
239
3.00k
  return captured_variables;
240
3.14k
}
241
242
3.00k
absl::Status validateNoOperatorAfterTextGlob(const struct ParsedPathPattern& pattern) {
243
3.00k
  bool seen_text_glob = false;
244
1.14M
  for (const ParsedSegment& segment : pattern.parsed_segments_) {
245
1.14M
    if (absl::holds_alternative<Operator>(segment)) {
246
829k
      if (seen_text_glob) {
247
25
        return absl::InvalidArgumentError("Glob after text glob.");
248
25
      }
249
829k
      seen_text_glob = (absl::get<Operator>(segment) == Operator::TextGlob);
250
829k
    } else if (absl::holds_alternative<Variable>(segment)) {
251
3.74k
      const Variable& var = absl::get<Variable>(segment);
252
3.74k
      if (var.match_.empty()) {
253
3.37k
        if (seen_text_glob) {
254
          // A variable with no explicit matcher is treated as a path glob.
255
7
          return absl::InvalidArgumentError("Implicit variable path glob after text glob.");
256
7
        }
257
3.37k
      } else {
258
289k
        for (const absl::variant<Operator, absl::string_view>& var_seg : var.match_) {
259
289k
          if (!absl::holds_alternative<Operator>(var_seg)) {
260
1.49k
            continue;
261
1.49k
          }
262
287k
          if (seen_text_glob) {
263
16
            return absl::InvalidArgumentError("Glob after text glob.");
264
16
          }
265
287k
          seen_text_glob = (absl::get<Operator>(var_seg) == Operator::TextGlob);
266
287k
        }
267
372
      }
268
3.74k
    }
269
1.14M
  }
270
2.95k
  return absl::OkStatus();
271
3.00k
}
272
273
3.67k
absl::StatusOr<ParsedPathPattern> parsePathPatternSyntax(absl::string_view path) {
274
3.67k
  struct ParsedPathPattern parsed_pattern;
275
276
3.67k
  static const LazyRE2 printable_regex = {"^/[[:graph:]]*$"};
277
3.67k
  if (!RE2::FullMatch(path, *printable_regex)) {
278
91
    return absl::InvalidArgumentError("Invalid pattern");
279
91
  }
280
281
  // Parse the leading '/'
282
3.58k
  path = path.substr(1);
283
284
  // Do the initial lexical parsing.
285
2.02M
  while (!path.empty()) {
286
2.01M
    ParsedSegment segment;
287
2.01M
    if (path[0] == '*') {
288
1.58M
      absl::StatusOr<Operator> status = alsoUpdatePattern<Operator>(parseOperator, &path);
289
1.58M
      if (!status.ok()) {
290
0
        return status.status();
291
0
      }
292
1.58M
      segment = *std::move(status);
293
1.58M
    } else if (path[0] == '{') {
294
20.0k
      absl::StatusOr<Variable> status = alsoUpdatePattern<Variable>(parseVariable, &path);
295
20.0k
      if (!status.ok()) {
296
184
        return status.status();
297
184
      }
298
19.8k
      segment = *std::move(status);
299
410k
    } else {
300
410k
      absl::StatusOr<Literal> status = alsoUpdatePattern<Literal>(parseLiteral, &path);
301
410k
      if (!status.ok()) {
302
91
        return status.status();
303
91
      }
304
409k
      segment = *std::move(status);
305
409k
    }
306
2.01M
    parsed_pattern.parsed_segments_.push_back(segment);
307
308
    // Deal with trailing '/' or suffix.
309
2.01M
    if (!path.empty()) {
310
2.01M
      if (path == "/") {
311
        // Single trailing '/' at the end, mark this with empty literal.
312
301
        parsed_pattern.parsed_segments_.emplace_back("");
313
301
        break;
314
2.01M
      } else if (path[0] == '/') {
315
        // Have '/' followed by more text, parse the '/'.
316
2.01M
        path = path.substr(1);
317
2.01M
      } else {
318
        // Not followed by '/', treat as suffix.
319
896
        absl::StatusOr<Literal> status = alsoUpdatePattern<Literal>(parseLiteral, &path);
320
896
        if (!status.ok()) {
321
98
          return status.status();
322
98
        }
323
798
        parsed_pattern.suffix_ = *std::move(status);
324
798
        if (!path.empty()) {
325
          // Suffix didn't parse whole remaining pattern ('/' in path).
326
67
          return absl::InvalidArgumentError("Prefix match not supported.");
327
67
        }
328
731
        break;
329
798
      }
330
2.01M
    }
331
2.01M
  }
332
3.14k
  absl::StatusOr<absl::flat_hash_set<absl::string_view>> status =
333
3.14k
      gatherCaptureNames(parsed_pattern);
334
3.14k
  if (!status.ok()) {
335
143
    return status.status();
336
143
  }
337
3.00k
  parsed_pattern.captured_variables_ = *std::move(status);
338
339
3.00k
  absl::Status validate_status = validateNoOperatorAfterTextGlob(parsed_pattern);
340
3.00k
  if (!validate_status.ok()) {
341
48
    return validate_status;
342
48
  }
343
344
2.95k
  return parsed_pattern;
345
3.00k
}
346
347
316k
std::string toRegexPattern(absl::string_view pattern) {
348
316k
  return absl::StrReplaceAll(
349
316k
      pattern, {{"$", "\\$"}, {"(", "\\("}, {")", "\\)"}, {"+", "\\+"}, {".", "\\."}});
350
316k
}
351
352
934k
std::string toRegexPattern(Operator pattern) {
353
934k
  static const std::string* kPathGlobRegex = new std::string(absl::StrCat("[", kLiteral, "]+"));
354
934k
  static const std::string* kTextGlobRegex = new std::string(absl::StrCat("[", kLiteral, "/]*"));
355
934k
  switch (pattern) {
356
934k
  case Operator::PathGlob: // "*"
357
934k
    return *kPathGlobRegex;
358
83
  case Operator::TextGlob: // "**"
359
83
    return *kTextGlobRegex;
360
934k
  }
361
0
  return "";
362
934k
}
363
364
3.71k
std::string toRegexPattern(const Variable& pattern) {
365
3.71k
  return absl::StrCat("(?P<", pattern.name_, ">",
366
3.71k
                      pattern.match_.empty()
367
3.71k
                          ? toRegexPattern(kDefaultVariableOperator)
368
3.71k
                          : absl::StrJoin(pattern.match_, "/", ToRegexPatternFormatter()),
369
3.71k
                      ")");
370
3.71k
}
371
372
2.95k
std::string toRegexPattern(const struct ParsedPathPattern& pattern) {
373
2.95k
  return absl::StrCat("/", absl::StrJoin(pattern.parsed_segments_, "/", ToRegexPatternFormatter()),
374
2.95k
                      toRegexPattern(pattern.suffix_));
375
2.95k
}
376
377
} // namespace Internal
378
} // namespace UriTemplate
379
} // namespace Extensions
380
} // namespace Envoy