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

            
3
#include <string>
4

            
5
#include "source/common/config/metadata.h"
6
#include "source/common/formatter/stream_info_formatter.h"
7
#include "source/common/formatter/substitution_formatter.h"
8
#include "source/common/http/utility.h"
9
#include "source/common/protobuf/utility.h"
10
#include "source/common/runtime/runtime_features.h"
11

            
12
namespace Envoy {
13
namespace Extensions {
14
namespace Formatter {
15

            
16
// Metadata formatter for route's metadata.
17
class RouteMetadataFormatter : public ::Envoy::Formatter::MetadataFormatter {
18
public:
19
  RouteMetadataFormatter(absl::string_view filter_namespace,
20
                         const std::vector<absl::string_view>& path,
21
                         absl::optional<size_t> max_length)
22
2
      : ::Envoy::Formatter::MetadataFormatter(filter_namespace, path, max_length,
23
2
                                              [](const StreamInfo::StreamInfo& stream_info)
24
2
                                                  -> const envoy::config::core::v3::Metadata* {
25
2
                                                auto route = stream_info.route();
26
2
                                                if (route == nullptr) {
27
1
                                                  return nullptr;
28
1
                                                }
29
1
                                                return &route->metadata();
30
2
                                              }) {}
31
};
32

            
33
// Metadata formatter for listener metadata.
34
class ListenerMetadataFormatter : public ::Envoy::Formatter::MetadataFormatter {
35
public:
36
  ListenerMetadataFormatter(absl::string_view filter_namespace,
37
                            const std::vector<absl::string_view>& path,
38
                            absl::optional<size_t> max_length)
39
4
      : ::Envoy::Formatter::MetadataFormatter(
40
4
            filter_namespace, path, max_length,
41
4
            [](const StreamInfo::StreamInfo& stream_info)
42
4
                -> const envoy::config::core::v3::Metadata* {
43
4
              const auto listener_info = stream_info.downstreamAddressProvider().listenerInfo();
44
4
              if (listener_info) {
45
3
                return &listener_info->metadata();
46
3
              }
47
1
              return nullptr;
48
4
            }) {}
49
};
50

            
51
// Metadata formatter for listener filter chain metadata.
52
class ListenerFilterChainMetadataFormatter : public ::Envoy::Formatter::MetadataFormatter {
53
public:
54
  ListenerFilterChainMetadataFormatter(absl::string_view filter_namespace,
55
                                       const std::vector<absl::string_view>& path,
56
                                       absl::optional<size_t> max_length)
57
2
      : ::Envoy::Formatter::MetadataFormatter(
58
2
            filter_namespace, path, max_length,
59
2
            [](const StreamInfo::StreamInfo& stream_info)
60
2
                -> const envoy::config::core::v3::Metadata* {
61
2
              const auto filter_chain_info =
62
2
                  stream_info.downstreamAddressProvider().filterChainInfo();
63
2
              if (filter_chain_info) {
64
1
                return &filter_chain_info->metadata();
65
1
              }
66
1
              return nullptr;
67
2
            }) {}
68
};
69

            
70
// Metadata formatter for virtual host metadata.
71
class VirtualHostMetadataFormatter : public ::Envoy::Formatter::MetadataFormatter {
72
public:
73
  VirtualHostMetadataFormatter(absl::string_view filter_namespace,
74
                               const std::vector<absl::string_view>& path,
75
                               absl::optional<size_t> max_length)
76
6
      : ::Envoy::Formatter::MetadataFormatter(filter_namespace, path, max_length,
77
6
                                              [](const StreamInfo::StreamInfo& stream_info)
78
6
                                                  -> const envoy::config::core::v3::Metadata* {
79
6
                                                const auto& vhost = stream_info.virtualHost();
80
6
                                                return vhost != nullptr ? &vhost->metadata()
81
6
                                                                        : nullptr;
82
6
                                              }) {}
83
};
84

            
85
// Map used to dispatch types of metadata to individual handlers which will
86
// access required metadata object.
87
using FormatterProviderFunc = std::function<::Envoy::Formatter::StreamInfoFormatterProviderPtr(
88
    absl::string_view filter_namespace, const std::vector<absl::string_view>& path,
89
    absl::optional<size_t> max_length)>;
90

            
91
using FormatterProviderFuncTable = absl::flat_hash_map<std::string, FormatterProviderFunc>;
92

            
93
40
const auto& formatterProviderFuncTable() {
94
40
  CONSTRUCT_ON_FIRST_USE(
95
40
      FormatterProviderFuncTable,
96
40
      {
97
40
          {"DYNAMIC",
98
40
           [](absl::string_view filter_namespace, const std::vector<absl::string_view>& path,
99
40
              absl::optional<size_t> max_length) {
100
40
             return std::make_unique<::Envoy::Formatter::DynamicMetadataFormatter>(
101
40
                 filter_namespace, path, max_length);
102
40
           }},
103
40
          {"CLUSTER",
104
40
           [](absl::string_view filter_namespace, const std::vector<absl::string_view>& path,
105
40
              absl::optional<size_t> max_length) {
106
40
             return std::make_unique<::Envoy::Formatter::ClusterMetadataFormatter>(
107
40
                 filter_namespace, path, max_length);
108
40
           }},
109
40
          {"ROUTE",
110
40
           [](absl::string_view filter_namespace, const std::vector<absl::string_view>& path,
111
40
              absl::optional<size_t> max_length) {
112
40
             return std::make_unique<RouteMetadataFormatter>(filter_namespace, path, max_length);
113
40
           }},
114
40
          {"UPSTREAM_HOST",
115
40
           [](absl::string_view filter_namespace, const std::vector<absl::string_view>& path,
116
40
              absl::optional<size_t> max_length) {
117
40
             return std::make_unique<::Envoy::Formatter::UpstreamHostMetadataFormatter>(
118
40
                 filter_namespace, path, max_length);
119
40
           }},
120
40
          {"LISTENER",
121
40
           [](absl::string_view filter_namespace, const std::vector<absl::string_view>& path,
122
40
              absl::optional<size_t> max_length) {
123
40
             return std::make_unique<ListenerMetadataFormatter>(filter_namespace, path, max_length);
124
40
           }},
125
40
          {"LISTENER_FILTER_CHAIN",
126
40
           [](absl::string_view filter_namespace, const std::vector<absl::string_view>& path,
127
40
              absl::optional<size_t> max_length) {
128
40
             return std::make_unique<ListenerFilterChainMetadataFormatter>(filter_namespace, path,
129
40
                                                                           max_length);
130
40
           }},
131
40
          {"VIRTUAL_HOST",
132
40
           [](absl::string_view filter_namespace, const std::vector<absl::string_view>& path,
133
40
              absl::optional<size_t> max_length) {
134
40
             return std::make_unique<VirtualHostMetadataFormatter>(filter_namespace, path,
135
40
                                                                   max_length);
136
40
           }},
137
40
      });
138
40
}
139

            
140
::Envoy::Formatter::FormatterProviderPtr
141
MetadataFormatterCommandParser::parse(absl::string_view command, absl::string_view subcommand,
142
304
                                      absl::optional<size_t> max_length) const {
143
304
  if (command == "METADATA") {
144
    // Extract type of metadata and keys.
145
20
    absl::string_view type, filter_namespace;
146
20
    std::vector<absl::string_view> path;
147

            
148
20
    ::Envoy::Formatter::SubstitutionFormatUtils::parseSubcommand(subcommand, ':', type,
149
20
                                                                 filter_namespace, path);
150

            
151
20
    auto provider = formatterProviderFuncTable().find(type);
152
20
    if (provider == formatterProviderFuncTable().end()) {
153
1
      throw EnvoyException(absl::StrCat(type, " is not supported type of metadata"));
154
1
    }
155

            
156
    // Return a pointer to formatter provider.
157
19
    return provider->second(filter_namespace, path, max_length);
158
20
  }
159
284
  return nullptr;
160
304
}
161

            
162
} // namespace Formatter
163
} // namespace Extensions
164
} // namespace Envoy