1
#include "source/extensions/path/rewrite/uri_template/uri_template_rewrite.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/match/uri_template/uri_template_match.h"
10
#include "source/extensions/path/uri_template_lib/uri_template_internal.h"
11

            
12
#include "absl/status/statusor.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
namespace Rewrite {
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
absl::Status
28
24
UriTemplateRewriter::isCompatiblePathMatcher(Router::PathMatcherSharedPtr path_matcher) const {
29
24
  if (path_matcher == nullptr || path_matcher->name() != Extensions::UriTemplate::Match::NAME) {
30
1
    return absl::InvalidArgumentError(fmt::format("unable to use {} extension without {} extension",
31
1
                                                  Extensions::UriTemplate::Rewrite::NAME,
32
1
                                                  Extensions::UriTemplate::Match::NAME));
33
1
  }
34

            
35
  // This is needed to match up variable values.
36
  // Validation between extensions as they share rewrite pattern variables.
37
23
  if (!isValidSharedVariableSet(rewrite_pattern_, path_matcher->uriTemplate()).ok()) {
38
2
    return absl::InvalidArgumentError(
39
2
        fmt::format("mismatch between variables in path_match_policy {} and path_rewrite_policy {}",
40
2
                    path_matcher->uriTemplate(), rewrite_pattern_));
41
2
  }
42

            
43
21
  return absl::OkStatus();
44
23
}
45

            
46
absl::StatusOr<std::string> UriTemplateRewriter::rewritePath(absl::string_view pattern,
47
29
                                                             absl::string_view matched_path) const {
48
29
  absl::StatusOr<std::string> regex_pattern = convertPathPatternSyntaxToRegex(matched_path);
49
29
  if (!regex_pattern.ok()) {
50
1
    return absl::InvalidArgumentError("Unable to parse matched_path");
51
1
  }
52
28
  std::string regex_pattern_str = *std::move(regex_pattern);
53

            
54
  // validated on construction of UriTemplateRewriter
55
28
  RewriteSegments rewrite_pattern_segments =
56
28
      parseRewritePattern(rewrite_pattern_, regex_pattern_str).value();
57

            
58
28
  RE2 regex = RE2(regex_pattern_str);
59
28
  if (!regex.ok()) {
60
    return absl::InternalError("Regex library failed");
61
  }
62

            
63
  // First capture is the whole matched regex pattern.
64
28
  int capture_num = regex.NumberOfCapturingGroups() + 1;
65
28
  std::vector<absl::string_view> captures(capture_num);
66
28
  if (!regex.Match(pattern, /*startpos=*/0,
67
28
                   /*endpos=*/pattern.size(), RE2::ANCHOR_BOTH, captures.data(), captures.size())) {
68
1
    return absl::InvalidArgumentError("Pattern not match");
69
1
  }
70

            
71
27
  std::string new_path;
72
99
  for (const RewriteSegment& segment : rewrite_pattern_segments) {
73
99
    auto* literal = absl::get_if<std::string>(&segment);
74
99
    auto* capture_index = absl::get_if<int>(&segment);
75
99
    if (literal != nullptr) {
76
51
      absl::StrAppend(&new_path, *literal);
77
51
    } else if (capture_index != nullptr) {
78
48
      absl::StrAppend(&new_path, captures[*capture_index]);
79
48
    }
80
99
  }
81

            
82
27
  return {new_path};
83
28
}
84

            
85
} // namespace Rewrite
86
} // namespace UriTemplate
87
} // namespace Extensions
88
} // namespace Envoy