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