Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/source/common/http/header_mutation.cc
Line
Count
Source (jump to first uncovered line)
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
380
      : HeadersToAddEntry(header_value_option), header_name_(header_value_option.header().key()) {}
20
21
  void evaluateHeaders(Http::HeaderMap& headers, const Formatter::HttpFormatterContext& context,
22
348
                       const StreamInfo::StreamInfo& stream_info) const override {
23
348
    const std::string value = formatter_->formatWithContext(context, stream_info);
24
25
348
    if (!value.empty() || add_if_empty_) {
26
346
      switch (append_action_) {
27
0
        PANIC_ON_PROTO_ENUM_SENTINEL_VALUES;
28
117
      case HeaderValueOption::APPEND_IF_EXISTS_OR_ADD:
29
117
        headers.addReferenceKey(header_name_, value);
30
117
        return;
31
18
      case HeaderValueOption::ADD_IF_ABSENT: {
32
18
        auto header = headers.get(header_name_);
33
18
        if (!header.empty()) {
34
13
          return;
35
13
        }
36
5
        headers.addReferenceKey(header_name_, value);
37
5
        break;
38
18
      }
39
5
      case HeaderValueOption::OVERWRITE_IF_EXISTS:
40
5
        if (headers.get(header_name_).empty()) {
41
0
          return;
42
0
        }
43
5
        FALLTHRU;
44
211
      case HeaderValueOption::OVERWRITE_IF_EXISTS_OR_ADD:
45
211
        headers.setReferenceKey(header_name_, value);
46
211
        break;
47
346
      }
48
346
    }
49
348
  }
50
51
private:
52
  Envoy::Http::LowerCaseString header_name_;
53
};
54
55
class RemoveMutation : public HeaderEvaluator {
56
public:
57
332
  RemoveMutation(const std::string& header_name) : header_name_(header_name) {}
58
59
  void evaluateHeaders(Http::HeaderMap& headers, const Formatter::HttpFormatterContext&,
60
161
                       const StreamInfo::StreamInfo&) const override {
61
161
    headers.remove(header_name_);
62
161
  }
63
64
private:
65
  const Envoy::Http::LowerCaseString header_name_;
66
};
67
} // namespace
68
69
236
HeaderMutations::HeaderMutations(const ProtoHeaderMutatons& header_mutations) {
70
712
  for (const auto& mutation : header_mutations) {
71
712
    switch (mutation.action_case()) {
72
380
    case envoy::config::common::mutation_rules::v3::HeaderMutation::ActionCase::kAppend:
73
380
      header_mutations_.emplace_back(std::make_unique<AppendMutation>(mutation.append()));
74
380
      break;
75
332
    case envoy::config::common::mutation_rules::v3::HeaderMutation::ActionCase::kRemove:
76
332
      header_mutations_.emplace_back(std::make_unique<RemoveMutation>(mutation.remove()));
77
332
      break;
78
0
    default:
79
0
      PANIC_DUE_TO_PROTO_UNSET;
80
712
    }
81
712
  }
82
236
}
83
84
void HeaderMutations::evaluateHeaders(Http::HeaderMap& headers,
85
                                      const Formatter::HttpFormatterContext& context,
86
126
                                      const StreamInfo::StreamInfo& stream_info) const {
87
509
  for (const auto& mutation : header_mutations_) {
88
509
    mutation->evaluateHeaders(headers, context, stream_info);
89
509
  }
90
126
}
91
92
} // namespace Http
93
} // namespace Envoy