1
#include "source/extensions/formatter/req_without_query/req_without_query.h"
2

            
3
#include <string>
4

            
5
#include "source/common/http/utility.h"
6
#include "source/common/protobuf/utility.h"
7

            
8
namespace Envoy {
9
namespace Extensions {
10
namespace Formatter {
11

            
12
namespace {
13

            
14
8
void truncate(std::string& str, absl::optional<size_t> max_length) {
15
8
  if (!max_length) {
16
6
    return;
17
6
  }
18

            
19
2
  str = str.substr(0, max_length.value());
20
2
}
21

            
22
} // namespace
23

            
24
ReqWithoutQuery::ReqWithoutQuery(absl::string_view main_header,
25
                                 absl::string_view alternative_header,
26
                                 absl::optional<size_t> max_length)
27
11
    : main_header_(main_header), alternative_header_(alternative_header), max_length_(max_length) {}
28

            
29
absl::optional<std::string> ReqWithoutQuery::format(const Envoy::Formatter::Context& context,
30
6
                                                    const StreamInfo::StreamInfo&) const {
31
6
  const Http::HeaderEntry* header = findHeader(context.requestHeaders());
32
6
  if (!header) {
33
2
    return absl::nullopt;
34
2
  }
35

            
36
4
  std::string val = Http::Utility::stripQueryString(header->value());
37
4
  truncate(val, max_length_);
38

            
39
4
  return val;
40
6
}
41

            
42
Protobuf::Value ReqWithoutQuery::formatValue(const Envoy::Formatter::Context& context,
43
5
                                             const StreamInfo::StreamInfo&) const {
44
5
  const Http::HeaderEntry* header = findHeader(context.requestHeaders());
45
5
  if (!header) {
46
1
    return ValueUtil::nullValue();
47
1
  }
48

            
49
4
  std::string val = Http::Utility::stripQueryString(header->value());
50
4
  truncate(val, max_length_);
51
4
  return ValueUtil::stringValue(val);
52
5
}
53

            
54
11
const Http::HeaderEntry* ReqWithoutQuery::findHeader(OptRef<const Http::HeaderMap> headers) const {
55
11
  if (!headers.has_value()) {
56
1
    return nullptr;
57
1
  }
58
10
  const auto header = headers->get(main_header_);
59

            
60
10
  if (header.empty() && !alternative_header_.get().empty()) {
61
2
    const auto alternate_header = headers->get(alternative_header_);
62
    // TODO(https://github.com/envoyproxy/envoy/issues/13454): Potentially log all header values.
63
2
    return alternate_header.empty() ? nullptr : alternate_header[0];
64
2
  }
65

            
66
8
  return header.empty() ? nullptr : header[0];
67
10
}
68

            
69
::Envoy::Formatter::FormatterProviderPtr
70
ReqWithoutQueryCommandParser::parse(absl::string_view command, absl::string_view subcommand,
71
12
                                    absl::optional<size_t> max_length) const {
72
12
  if (command == "REQ_WITHOUT_QUERY") {
73
11
    auto status_or = Envoy::Formatter::SubstitutionFormatUtils::parseSubcommandHeaders(subcommand);
74
11
    THROW_IF_NOT_OK_REF(status_or.status());
75
11
    return std::make_unique<ReqWithoutQuery>(status_or.value().first, status_or.value().second,
76
11
                                             max_length);
77
11
  }
78
1
  return nullptr;
79
12
}
80

            
81
} // namespace Formatter
82
} // namespace Extensions
83
} // namespace Envoy