LCOV - code coverage report
Current view: top level - source/common/router - header_parser_utils.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 49 49 100.0 %
Date: 2024-01-05 06:35:25 Functions: 4 4 100.0 %

          Line data    Source code
       1             : #include <regex>
       2             : #include <string>
       3             : 
       4             : #include "source/common/common/assert.h"
       5             : #include "source/common/json/json_loader.h"
       6             : #include "source/common/router/header_parser.h"
       7             : 
       8             : #include "absl/strings/str_replace.h"
       9             : #include "re2/re2.h"
      10             : 
      11             : namespace Envoy {
      12             : namespace Router {
      13         501 : static const re2::RE2& getMetadataTranslatorPattern() {
      14         501 :   CONSTRUCT_ON_FIRST_USE(re2::RE2,
      15         501 :                          R"EOF(%(UPSTREAM|DYNAMIC)_METADATA\(\s*(\[(?:.|\r?\n)+?\]\s*)\)%)EOF");
      16         501 : }
      17             : 
      18             : // Related to issue 20389. Header formatters are parsed and processed by formatters defined in
      19             : // source/common/formatter/substitution_formatter.cc. For backwards compatibility UPSTREAM_METADATA
      20             : // and UPSTREAM_METADATA format must be changed. Those formatters used to take a JSON format like
      21             : // UPSTREAM_METADATA(["a", "b"]) and substitution formatters use UPSTREAM_METADATA(a:b) format.
      22             : // This translator translates UPSTREAM_METADATA and DYNAMIC_METADATA from JSON format to colon
      23             : // format.
      24             : // TODO(cpakulski): Eventually JSON format should be deprecated in favor of colon format.
      25         501 : std::string HeaderParser::translateMetadataFormat(const std::string& header_value) {
      26         501 :   const re2::RE2& re = getMetadataTranslatorPattern();
      27         501 :   ASSERT(re.ok());
      28         501 :   std::string new_header_value = header_value;
      29         501 :   absl::string_view matches[3];
      30         537 :   while (re.Match(new_header_value, 0, new_header_value.size(), re2::RE2::UNANCHORED, matches, 3)) {
      31          42 :     TRY_ASSERT_MAIN_THREAD {
      32          42 :       std::string new_format;
      33          42 :       Json::ObjectSharedPtr parsed_params = Json::Factory::loadFromString(std::string(matches[2]));
      34             : 
      35             :       // The given json string may be an invalid object or with an empty object array.
      36          42 :       if (parsed_params == nullptr || parsed_params->asObjectArray().empty()) {
      37             :         // return original value
      38           6 :         return header_value;
      39           6 :       }
      40          36 :       new_format = parsed_params->asObjectArray()[0]->asString();
      41          74 :       for (size_t i = 1; i < parsed_params->asObjectArray().size(); i++) {
      42          38 :         absl::StrAppend(&new_format, ":", parsed_params->asObjectArray()[i]->asString());
      43          38 :       }
      44             : 
      45          36 :       new_format = absl::StrCat("%", matches[1], "_METADATA(", new_format, ")%");
      46          36 :       ENVOY_LOG_MISC(warn,
      47          36 :                      "Header formatter: JSON format of {}_METADATA parameters has been obsoleted. "
      48          36 :                      "Use colon format: {}",
      49          36 :                      matches[1], new_format.c_str());
      50             : 
      51          36 :       int subs = absl::StrReplaceAll({{matches[0], new_format}}, &new_header_value);
      52          36 :       ASSERT(subs > 0);
      53          36 :     }
      54          42 :     END_TRY CATCH(Json::Exception & e, { return header_value; });
      55          36 :   }
      56             : 
      57         495 :   return new_header_value;
      58         501 : }
      59             : 
      60         501 : static const re2::RE2& getPerRequestTranslatorPattern() {
      61         501 :   CONSTRUCT_ON_FIRST_USE(re2::RE2, R"EOF(%PER_REQUEST_STATE\((.+?)\)%)EOF");
      62         501 : }
      63             : 
      64             : // Related to issue 20389.
      65             : // Header's formatter PER_REQUEST_STATE(key) is equivalent to substitution
      66             : // formatter FILTER_STATE(key:PLAIN). translatePerRequestState method
      67             : // translates between these 2 formats.
      68             : // TODO(cpakulski): eventually PER_REQUEST_STATE formatter should be deprecated in
      69             : // favor of FILTER_STATE.
      70         501 : std::string HeaderParser::translatePerRequestState(const std::string& header_value) {
      71         501 :   const re2::RE2& re = getPerRequestTranslatorPattern();
      72         501 :   ASSERT(re.ok());
      73         501 :   std::string new_header_value = header_value;
      74         501 :   absl::string_view matches[2];
      75         516 :   while (re.Match(new_header_value, 0, new_header_value.size(), re2::RE2::UNANCHORED, matches, 2)) {
      76          15 :     const std::string new_format = absl::StrCat("%FILTER_STATE(", matches[1], ":PLAIN)%");
      77             : 
      78          15 :     ENVOY_LOG_MISC(warn, "PER_REQUEST_STATE header formatter has been obsoleted. Use {}",
      79          15 :                    new_format.c_str());
      80          15 :     int subs = absl::StrReplaceAll({{matches[0], new_format}}, &new_header_value);
      81          15 :     ASSERT(subs > 0);
      82          15 :   }
      83         501 :   return new_header_value;
      84         501 : }
      85             : 
      86             : } // namespace Router
      87             : } // namespace Envoy

Generated by: LCOV version 1.15