1
#include "source/extensions/http/stateful_session/envelope/envelope.h"
2

            
3
#include "absl/container/inlined_vector.h"
4

            
5
namespace Envoy {
6
namespace Extensions {
7
namespace Http {
8
namespace StatefulSession {
9
namespace Envelope {
10

            
11
constexpr absl::string_view OriginUpstreamValuePartFlag = "UV:";
12

            
13
bool EnvelopeSessionStateFactory::SessionStateImpl::onUpdate(
14
6
    absl::string_view host_address, Envoy::Http::ResponseHeaderMap& headers) {
15

            
16
6
  const auto upstream_value_header = headers.get(factory_.name_);
17
6
  if (upstream_value_header.size() != 1) {
18
4
    ENVOY_LOG(trace, "Header {} not exist or occurs multiple times", factory_.name_);
19
4
    return false;
20
4
  }
21

            
22
  // For envelope, we always update the header with the new host address, so consider it changed.
23
2
  const bool host_changed =
24
2
      !upstream_address_.has_value() || host_address != upstream_address_.value();
25
2
  const std::string new_header =
26
2
      absl::StrCat(Envoy::Base64::encode(host_address), ";", OriginUpstreamValuePartFlag,
27
2
                   Envoy::Base64::encode(upstream_value_header[0]->value().getStringView()));
28
2
  headers.setReferenceKey(factory_.name_, new_header);
29
2
  return host_changed;
30
6
}
31

            
32
EnvelopeSessionStateFactory::EnvelopeSessionStateFactory(const EnvelopeSessionStateProto& config)
33
5
    : name_(config.header().name()) {}
34

            
35
absl::optional<std::string>
36
9
EnvelopeSessionStateFactory::parseAddress(Envoy::Http::RequestHeaderMap& headers) const {
37
9
  const auto hdr = headers.get(name_);
38
9
  if (hdr.empty()) {
39
2
    return absl::nullopt;
40
2
  }
41
7
  const absl::InlinedVector<absl::string_view, 2> parts =
42
7
      absl::StrSplit(hdr[0]->value().getStringView(), ';', absl::SkipEmpty());
43
7
  if (parts.empty()) {
44
1
    return absl::nullopt;
45
1
  }
46
6
  std::string upstream_host = Base64::decode(parts[0]);
47

            
48
6
  absl::string_view upstream_value;
49

            
50
  // parts[0] is the base64 encoded upstream address and should be skipped.
51
6
  const auto other_parts_view = absl::Span<const absl::string_view>(parts).subspan(1);
52
6
  for (absl::string_view part : other_parts_view) {
53
5
    if (absl::StartsWith(part, OriginUpstreamValuePartFlag)) {
54
5
      upstream_value = part.substr(OriginUpstreamValuePartFlag.size());
55
5
      break;
56
5
    }
57
5
  }
58

            
59
6
  const std::string decoded = Envoy::Base64::decode(upstream_value);
60
6
  if (decoded.empty()) {
61
    // Do nothing if the 'UV' part is not valid or if there is no UV part.
62
2
    ENVOY_LOG(info, "Header {} contains invalid 'UV' part or there is no 'UV' part", name_);
63
2
    return absl::nullopt;
64
2
  }
65
4
  headers.setReferenceKey(name_, decoded);
66

            
67
4
  return !upstream_host.empty() ? absl::make_optional(std::move(upstream_host)) : absl::nullopt;
68
6
}
69

            
70
} // namespace Envelope
71
} // namespace StatefulSession
72
} // namespace Http
73
} // namespace Extensions
74
} // namespace Envoy