1
#pragma once
2

            
3
#include <string>
4
#include <vector>
5

            
6
#include "envoy/http/protocol.h"
7
#include "envoy/stream_info/stream_info.h"
8

            
9
#include "absl/strings/str_format.h"
10
#include "absl/strings/str_replace.h"
11
#include "absl/strings/str_split.h"
12
#include "absl/types/optional.h"
13
#include "fmt/format.h"
14

            
15
namespace Envoy {
16
namespace Formatter {
17

            
18
class CommandSyntaxChecker {
19
public:
20
  using CommandSyntaxFlags = std::bitset<4>;
21
  static constexpr CommandSyntaxFlags COMMAND_ONLY = 0;
22
  static constexpr CommandSyntaxFlags PARAMS_REQUIRED = 1 << 0;
23
  static constexpr CommandSyntaxFlags PARAMS_OPTIONAL = 1 << 1;
24
  static constexpr CommandSyntaxFlags LENGTH_ALLOWED = 1 << 2;
25

            
26
  static absl::Status verifySyntax(CommandSyntaxChecker::CommandSyntaxFlags flags,
27
                                   absl::string_view command, absl::string_view subcommand,
28
                                   absl::optional<size_t> length);
29
};
30

            
31
/**
32
 * Context independent utility class for the formatter.
33
 */
34
class SubstitutionFormatUtils {
35
public:
36
  // Optional references are not supported, but this method has large performance
37
  // impact, so using reference_wrapper.
38
  static const absl::optional<std::reference_wrapper<const std::string>>
39
  protocolToString(const absl::optional<Http::Protocol>& protocol);
40
  static const std::string&
41
  protocolToStringOrDefault(const absl::optional<Http::Protocol>& protocol);
42
  static const absl::optional<std::string> getHostname();
43

            
44
  /**
45
   * Unspecified value for protobuf.
46
   */
47
  static const Protobuf::Value& unspecifiedValue();
48

            
49
  /**
50
   * Truncate a string to a maximum length. Do nothing if max_length is not set or
51
   * max_length is greater than the length of the string.
52
   * @return true if the string was truncated, false otherwise.
53
   */
54
  static bool truncate(std::string& str, absl::optional<size_t> max_length);
55

            
56
  /**
57
   * Truncate an input string view to a maximum length, and return the resulting string view. Do not
58
   * truncate if max_length is not set or max_length is greater than the length of the input string
59
   * view.
60
   */
61
  static absl::string_view truncateStringView(absl::string_view str,
62
                                              absl::optional<size_t> max_length);
63

            
64
  /**
65
   * Parse a header subcommand of the form: X?Y .
66
   * Will populate a main_header and an optional alternative header if specified.
67
   * See doc:
68
   * https://envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/access_log#format-rules
69
   */
70
  using HeaderPair = std::pair<absl::string_view, absl::string_view>;
71
  static absl::StatusOr<HeaderPair> parseSubcommandHeaders(absl::string_view subcommand);
72

            
73
  /**
74
   * Variadic function template to parse the subcommand and assign found tokens to sequence of
75
   * params. subcommand must be a sequence of tokens separated by the same separator, like:
76
   * header1:header2 or header1?header2?header3.
77
   * params must be a sequence of absl::string_view& with optional container storing
78
   * absl::string_view. Here are examples of params:
79
   *  - absl::string_view& token1
80
   *  - absl::string_view& token1, absl::string_view& token2
81
   *  - absl::string_view& token1, absl::string_view& token2, std::vector<absl::string_view>& others
82
   *
83
   * If command contains more tokens than number of passed params, unassigned tokens will be
84
   * ignored. If command contains less tokens than number of passed params, some params will be left
85
   * untouched.
86
   */
87
  template <typename... Tokens>
88
  static void parseSubcommand(absl::string_view subcommand, const char separator,
89
135194
                              Tokens&&... params) {
90
135194
    std::vector<absl::string_view> tokens = absl::StrSplit(subcommand, separator);
91
135194
    std::vector<absl::string_view>::iterator it = tokens.begin();
92
135194
    (
93
404831
        [&](auto& param) {
94
404831
          if (it != tokens.end()) {
95
            if constexpr (std::is_same_v<typename std::remove_reference<decltype(param)>::type,
96
155709
                                         absl::string_view>) {
97
              // Compile time handler for absl::string_view.
98
155709
              param = *it;
99
155709
              it++;
100
155709
            } else {
101
              // Compile time handler for container type. It will catch all remaining tokens and
102
              // move iterator to the end.
103
1014
              do {
104
1014
                param.push_back(*it);
105
1014
                it++;
106
1014
              } while (it != tokens.end());
107
701
            }
108
156410
          }
109
404831
        }(params),
110
135194
        ...);
111
135194
  }
112
};
113

            
114
} // namespace Formatter
115
} // namespace Envoy