Coverage Report

Created: 2024-09-19 09:45

/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, absl::Status& creation_status)
19
      : HeadersToAddEntry(header_value_option, creation_status),
20
15
        header_name_(header_value_option.header().key()) {}
21
22
  void evaluateHeaders(Http::HeaderMap& headers, const Formatter::HttpFormatterContext& context,
23
15
                       const StreamInfo::StreamInfo& stream_info) const override {
24
15
    const std::string value = formatter_->formatWithContext(context, stream_info);
25
26
15
    if (!value.empty() || add_if_empty_) {
27
15
      switch (append_action_) {
28
0
        PANIC_ON_PROTO_ENUM_SENTINEL_VALUES;
29
4
      case HeaderValueOption::APPEND_IF_EXISTS_OR_ADD:
30
4
        headers.addReferenceKey(header_name_, value);
31
4
        return;
32
4
      case HeaderValueOption::ADD_IF_ABSENT: {
33
4
        auto header = headers.get(header_name_);
34
4
        if (!header.empty()) {
35
1
          return;
36
1
        }
37
3
        headers.addReferenceKey(header_name_, value);
38
3
        break;
39
4
      }
40
0
      case HeaderValueOption::OVERWRITE_IF_EXISTS:
41
0
        if (headers.get(header_name_).empty()) {
42
0
          return;
43
0
        }
44
0
        FALLTHRU;
45
7
      case HeaderValueOption::OVERWRITE_IF_EXISTS_OR_ADD:
46
7
        headers.setReferenceKey(header_name_, value);
47
7
        break;
48
15
      }
49
15
    }
50
15
  }
51
52
private:
53
  Envoy::Http::LowerCaseString header_name_;
54
};
55
56
class RemoveMutation : public HeaderEvaluator {
57
public:
58
6
  RemoveMutation(const std::string& header_name) : header_name_(header_name) {}
59
60
  void evaluateHeaders(Http::HeaderMap& headers, const Formatter::HttpFormatterContext&,
61
6
                       const StreamInfo::StreamInfo&) const override {
62
6
    headers.remove(header_name_);
63
6
  }
64
65
private:
66
  const Envoy::Http::LowerCaseString header_name_;
67
};
68
} // namespace
69
70
absl::StatusOr<std::unique_ptr<HeaderMutations>>
71
10
HeaderMutations::create(const ProtoHeaderMutatons& header_mutations) {
72
10
  absl::Status creation_status = absl::OkStatus();
73
10
  auto ret =
74
10
      std::unique_ptr<HeaderMutations>(new HeaderMutations(header_mutations, creation_status));
75
10
  RETURN_IF_NOT_OK(creation_status);
76
10
  return ret;
77
10
}
78
79
HeaderMutations::HeaderMutations(const ProtoHeaderMutatons& header_mutations,
80
10
                                 absl::Status& creation_status) {
81
21
  for (const auto& mutation : header_mutations) {
82
21
    switch (mutation.action_case()) {
83
15
    case envoy::config::common::mutation_rules::v3::HeaderMutation::ActionCase::kAppend:
84
15
      header_mutations_.emplace_back(
85
15
          std::make_unique<AppendMutation>(mutation.append(), creation_status));
86
15
      if (!creation_status.ok()) {
87
0
        return;
88
0
      }
89
15
      break;
90
15
    case envoy::config::common::mutation_rules::v3::HeaderMutation::ActionCase::kRemove:
91
6
      header_mutations_.emplace_back(std::make_unique<RemoveMutation>(mutation.remove()));
92
6
      break;
93
0
    default:
94
0
      PANIC_DUE_TO_PROTO_UNSET;
95
21
    }
96
21
  }
97
10
}
98
99
void HeaderMutations::evaluateHeaders(Http::HeaderMap& headers,
100
                                      const Formatter::HttpFormatterContext& context,
101
8
                                      const StreamInfo::StreamInfo& stream_info) const {
102
21
  for (const auto& mutation : header_mutations_) {
103
21
    mutation->evaluateHeaders(headers, context, stream_info);
104
21
  }
105
8
}
106
107
} // namespace Http
108
} // namespace Envoy