Line data Source code
1 : #include "source/common/http/header_mutation.h" 2 : 3 : #include "source/common/router/header_parser.h" 4 : 5 : namespace Envoy { 6 : namespace Http { 7 : 8 : namespace { 9 : 10 : using HeaderAppendAction = envoy::config::core::v3::HeaderValueOption::HeaderAppendAction; 11 : using HeaderValueOption = envoy::config::core::v3::HeaderValueOption; 12 : 13 : // TODO(wbpcode): Inherit from Envoy::Router::HeadersToAddEntry to make sure the formatter 14 : // has the same behavior as the router's formatter. We should try to find a more clean way 15 : // to reuse the formatter after the router's formatter is completely removed. 16 : class AppendMutation : public HeaderEvaluator, public Envoy::Router::HeadersToAddEntry { 17 : public: 18 : AppendMutation(const HeaderValueOption& header_value_option) 19 0 : : HeadersToAddEntry(header_value_option), header_name_(header_value_option.header().key()) {} 20 : 21 : void evaluateHeaders(Http::HeaderMap& headers, const Formatter::HttpFormatterContext& context, 22 0 : const StreamInfo::StreamInfo& stream_info) const override { 23 0 : const std::string value = formatter_->formatWithContext(context, stream_info); 24 : 25 0 : if (!value.empty() || add_if_empty_) { 26 0 : switch (append_action_) { 27 0 : PANIC_ON_PROTO_ENUM_SENTINEL_VALUES; 28 0 : case HeaderValueOption::APPEND_IF_EXISTS_OR_ADD: 29 0 : headers.addReferenceKey(header_name_, value); 30 0 : return; 31 0 : case HeaderValueOption::ADD_IF_ABSENT: { 32 0 : auto header = headers.get(header_name_); 33 0 : if (!header.empty()) { 34 0 : return; 35 0 : } 36 0 : headers.addReferenceKey(header_name_, value); 37 0 : break; 38 0 : } 39 0 : case HeaderValueOption::OVERWRITE_IF_EXISTS: 40 0 : if (headers.get(header_name_).empty()) { 41 0 : return; 42 0 : } 43 0 : FALLTHRU; 44 0 : case HeaderValueOption::OVERWRITE_IF_EXISTS_OR_ADD: 45 0 : headers.setReferenceKey(header_name_, value); 46 0 : break; 47 0 : } 48 0 : } 49 0 : } 50 : 51 : private: 52 : Envoy::Http::LowerCaseString header_name_; 53 : }; 54 : 55 : class RemoveMutation : public HeaderEvaluator { 56 : public: 57 0 : RemoveMutation(const std::string& header_name) : header_name_(header_name) {} 58 : 59 : void evaluateHeaders(Http::HeaderMap& headers, const Formatter::HttpFormatterContext&, 60 0 : const StreamInfo::StreamInfo&) const override { 61 0 : headers.remove(header_name_); 62 0 : } 63 : 64 : private: 65 : const Envoy::Http::LowerCaseString header_name_; 66 : }; 67 : } // namespace 68 : 69 0 : HeaderMutations::HeaderMutations(const ProtoHeaderMutatons& header_mutations) { 70 0 : for (const auto& mutation : header_mutations) { 71 0 : switch (mutation.action_case()) { 72 0 : case envoy::config::common::mutation_rules::v3::HeaderMutation::ActionCase::kAppend: 73 0 : header_mutations_.emplace_back(std::make_unique<AppendMutation>(mutation.append())); 74 0 : break; 75 0 : case envoy::config::common::mutation_rules::v3::HeaderMutation::ActionCase::kRemove: 76 0 : header_mutations_.emplace_back(std::make_unique<RemoveMutation>(mutation.remove())); 77 0 : break; 78 0 : default: 79 0 : PANIC_DUE_TO_PROTO_UNSET; 80 0 : } 81 0 : } 82 0 : } 83 : 84 : void HeaderMutations::evaluateHeaders(Http::HeaderMap& headers, 85 : const Formatter::HttpFormatterContext& context, 86 0 : const StreamInfo::StreamInfo& stream_info) const { 87 0 : for (const auto& mutation : header_mutations_) { 88 0 : mutation->evaluateHeaders(headers, context, stream_info); 89 0 : } 90 0 : } 91 : 92 : } // namespace Http 93 : } // namespace Envoy