LCOV - code coverage report
Current view: top level - source/extensions/path/uri_template_lib - uri_template.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 74 94 78.7 %
Date: 2024-01-05 06:35:25 Functions: 6 7 85.7 %

          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

Generated by: LCOV version 1.15