Coverage Report

Created: 2023-11-12 09:30

/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