Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/source/extensions/upstreams/http/config.cc
Line
Count
Source (jump to first uncovered line)
1
#include "source/extensions/upstreams/http/config.h"
2
3
#include <chrono>
4
#include <memory>
5
#include <string>
6
#include <vector>
7
8
#include "envoy/config/cluster/v3/cluster.pb.h"
9
#include "envoy/config/core/v3/base.pb.h"
10
#include "envoy/extensions/http/header_validators/envoy_default/v3/header_validator.pb.h"
11
#include "envoy/http/header_validator_factory.h"
12
#include "envoy/upstream/upstream.h"
13
14
#include "source/common/config/utility.h"
15
#include "source/common/http/http1/settings.h"
16
#include "source/common/http/utility.h"
17
#include "source/common/protobuf/utility.h"
18
19
namespace Envoy {
20
namespace Extensions {
21
namespace Upstreams {
22
namespace Http {
23
namespace {
24
25
const envoy::config::core::v3::Http1ProtocolOptions&
26
2.24k
getHttpOptions(const envoy::extensions::upstreams::http::v3::HttpProtocolOptions& options) {
27
2.24k
  if (options.has_use_downstream_protocol_config()) {
28
0
    return options.use_downstream_protocol_config().http_protocol_options();
29
0
  }
30
2.24k
  if (options.has_auto_config()) {
31
0
    return options.auto_config().http_protocol_options();
32
0
  }
33
2.24k
  return options.explicit_http_config().http_protocol_options();
34
2.24k
}
35
36
const envoy::config::core::v3::Http2ProtocolOptions&
37
2.24k
getHttp2Options(const envoy::extensions::upstreams::http::v3::HttpProtocolOptions& options) {
38
2.24k
  if (options.has_use_downstream_protocol_config()) {
39
0
    return options.use_downstream_protocol_config().http2_protocol_options();
40
0
  }
41
2.24k
  if (options.has_auto_config()) {
42
0
    return options.auto_config().http2_protocol_options();
43
0
  }
44
2.24k
  return options.explicit_http_config().http2_protocol_options();
45
2.24k
}
46
47
const envoy::config::core::v3::Http3ProtocolOptions&
48
2.24k
getHttp3Options(const envoy::extensions::upstreams::http::v3::HttpProtocolOptions& options) {
49
2.24k
  if (options.has_use_downstream_protocol_config() &&
50
2.24k
      options.use_downstream_protocol_config().has_http3_protocol_options()) {
51
0
    return options.use_downstream_protocol_config().http3_protocol_options();
52
0
  }
53
2.24k
  if (options.has_auto_config()) {
54
0
    return options.auto_config().http3_protocol_options();
55
0
  }
56
2.24k
  return options.explicit_http_config().http3_protocol_options();
57
2.24k
}
58
59
2.24k
bool useHttp2(const envoy::extensions::upstreams::http::v3::HttpProtocolOptions& options) {
60
2.24k
  if (options.has_explicit_http_config() &&
61
2.24k
      options.explicit_http_config().has_http2_protocol_options()) {
62
2.24k
    return true;
63
2.24k
  } else if (options.has_use_downstream_protocol_config() &&
64
0
             options.use_downstream_protocol_config().has_http2_protocol_options()) {
65
0
    return true;
66
0
  } else if (options.has_auto_config()) {
67
0
    return true;
68
0
  }
69
0
  return false;
70
2.24k
}
71
72
2.24k
bool useHttp3(const envoy::extensions::upstreams::http::v3::HttpProtocolOptions& options) {
73
2.24k
  if (options.has_explicit_http_config() &&
74
2.24k
      options.explicit_http_config().has_http3_protocol_options()) {
75
0
    return true;
76
2.24k
  } else if (options.has_use_downstream_protocol_config() &&
77
2.24k
             options.use_downstream_protocol_config().has_http3_protocol_options()) {
78
0
    return true;
79
2.24k
  } else if (options.has_auto_config() && options.auto_config().has_http3_protocol_options()) {
80
0
    return true;
81
0
  }
82
2.24k
  return false;
83
2.24k
}
84
85
absl::optional<const envoy::config::core::v3::AlternateProtocolsCacheOptions>
86
getAlternateProtocolsCacheOptions(
87
    const envoy::extensions::upstreams::http::v3::HttpProtocolOptions& options,
88
2.24k
    Server::Configuration::ServerFactoryContext& server_context) {
89
2.24k
  if (options.has_auto_config() && options.auto_config().has_http3_protocol_options()) {
90
0
    if (!options.auto_config().has_alternate_protocols_cache_options()) {
91
0
      throwEnvoyExceptionOrPanic(
92
0
          fmt::format("alternate protocols cache must be configured when HTTP/3 "
93
0
                      "is enabled with auto_config"));
94
0
    }
95
0
    auto cache_options = options.auto_config().alternate_protocols_cache_options();
96
0
    if (cache_options.has_key_value_store_config() && server_context.options().concurrency() != 1) {
97
0
      throwEnvoyExceptionOrPanic(
98
0
          fmt::format("options has key value store but Envoy has concurrency = {} : {}",
99
0
                      server_context.options().concurrency(), cache_options.DebugString()));
100
0
    }
101
102
0
    return cache_options;
103
0
  }
104
2.24k
  return absl::nullopt;
105
2.24k
}
106
107
Envoy::Http::HeaderValidatorFactoryPtr createHeaderValidatorFactory(
108
    [[maybe_unused]] const envoy::extensions::upstreams::http::v3::HttpProtocolOptions& options,
109
2.24k
    [[maybe_unused]] Server::Configuration::ServerFactoryContext& server_context) {
110
111
2.24k
  Envoy::Http::HeaderValidatorFactoryPtr header_validator_factory;
112
#ifdef ENVOY_ENABLE_UHV
113
  if (!Runtime::runtimeFeatureEnabled(
114
          "envoy.reloadable_features.enable_universal_header_validator")) {
115
    // This will cause codecs to use legacy header validation and path normalization
116
    return nullptr;
117
  }
118
  ::envoy::config::core::v3::TypedExtensionConfig legacy_header_validator_config;
119
  if (!options.has_header_validation_config()) {
120
    // If header validator is not configured ensure that the defaults match Envoy's original
121
    // behavior.
122
    ::envoy::extensions::http::header_validators::envoy_default::v3::HeaderValidatorConfig
123
        uhv_config;
124
    uhv_config.mutable_http1_protocol_options()->set_allow_chunked_length(
125
        getHttpOptions(options).allow_chunked_length());
126
    legacy_header_validator_config.set_name("default_envoy_uhv_from_legacy_settings");
127
    legacy_header_validator_config.mutable_typed_config()->PackFrom(uhv_config);
128
  }
129
130
  const ::envoy::config::core::v3::TypedExtensionConfig& header_validator_config =
131
      options.has_header_validation_config() ? options.header_validation_config()
132
                                             : legacy_header_validator_config;
133
134
  auto* factory = Envoy::Config::Utility::getFactory<Envoy::Http::HeaderValidatorFactoryConfig>(
135
      header_validator_config);
136
  if (!factory) {
137
    throwEnvoyExceptionOrPanic(
138
        fmt::format("Header validator extension not found: '{}'", header_validator_config.name()));
139
  }
140
141
  header_validator_factory =
142
      factory->createFromProto(header_validator_config.typed_config(), server_context);
143
  if (!header_validator_factory) {
144
    throwEnvoyExceptionOrPanic(fmt::format("Header validator extension could not be created: '{}'",
145
                                           header_validator_config.name()));
146
  }
147
#else
148
2.24k
  if (options.has_header_validation_config()) {
149
0
    throwEnvoyExceptionOrPanic(
150
0
        fmt::format("This Envoy binary does not support header validator extensions: '{}'",
151
0
                    options.header_validation_config().name()));
152
0
  }
153
154
2.24k
  if (Runtime::runtimeFeatureEnabled(
155
2.24k
          "envoy.reloadable_features.enable_universal_header_validator")) {
156
0
    throwEnvoyExceptionOrPanic(
157
0
        "Header validator can not be enabled since this Envoy binary does not support it.");
158
0
  }
159
2.24k
#endif
160
2.24k
  return header_validator_factory;
161
2.24k
}
162
163
} // namespace
164
165
uint64_t ProtocolOptionsConfigImpl::parseFeatures(const envoy::config::cluster::v3::Cluster& config,
166
3.26k
                                                  const ProtocolOptionsConfigImpl& options) {
167
3.26k
  uint64_t features = 0;
168
169
3.26k
  if (options.use_http2_) {
170
2.24k
    features |= Upstream::ClusterInfo::Features::HTTP2;
171
2.24k
  }
172
3.26k
  if (options.use_http3_) {
173
0
    features |= Upstream::ClusterInfo::Features::HTTP3;
174
0
  }
175
3.26k
  if (options.use_downstream_protocol_) {
176
0
    features |= Upstream::ClusterInfo::Features::USE_DOWNSTREAM_PROTOCOL;
177
0
  }
178
3.26k
  if (options.use_alpn_) {
179
0
    features |= Upstream::ClusterInfo::Features::USE_ALPN;
180
0
  }
181
3.26k
  if (config.close_connections_on_host_health_failure()) {
182
0
    features |= Upstream::ClusterInfo::Features::CLOSE_CONNECTIONS_ON_HOST_HEALTH_FAILURE;
183
0
  }
184
3.26k
  return features;
185
3.26k
}
186
187
ProtocolOptionsConfigImpl::ProtocolOptionsConfigImpl(
188
    const envoy::extensions::upstreams::http::v3::HttpProtocolOptions& options,
189
    Server::Configuration::ServerFactoryContext& server_context)
190
    : http1_settings_(Envoy::Http::Http1::parseHttp1Settings(
191
          getHttpOptions(options), server_context.messageValidationVisitor())),
192
      http2_options_(Http2::Utility::initializeAndValidateOptions(getHttp2Options(options))),
193
      http3_options_(getHttp3Options(options)),
194
      common_http_protocol_options_(options.common_http_protocol_options()),
195
      upstream_http_protocol_options_(
196
          options.has_upstream_http_protocol_options()
197
              ? absl::make_optional<envoy::config::core::v3::UpstreamHttpProtocolOptions>(
198
                    options.upstream_http_protocol_options())
199
              : absl::nullopt),
200
      http_filters_(options.http_filters()),
201
      alternate_protocol_cache_options_(getAlternateProtocolsCacheOptions(options, server_context)),
202
      header_validator_factory_(createHeaderValidatorFactory(options, server_context)),
203
      use_downstream_protocol_(options.has_use_downstream_protocol_config()),
204
      use_http2_(useHttp2(options)), use_http3_(useHttp3(options)),
205
2.24k
      use_alpn_(options.has_auto_config()) {}
206
207
ProtocolOptionsConfigImpl::ProtocolOptionsConfigImpl(
208
    const envoy::config::core::v3::Http1ProtocolOptions& http1_settings,
209
    const envoy::config::core::v3::Http2ProtocolOptions& http2_options,
210
    const envoy::config::core::v3::HttpProtocolOptions& common_options,
211
    const absl::optional<envoy::config::core::v3::UpstreamHttpProtocolOptions> upstream_options,
212
    bool use_downstream_protocol, bool use_http2,
213
    ProtobufMessage::ValidationVisitor& validation_visitor)
214
    : http1_settings_(Envoy::Http::Http1::parseHttp1Settings(http1_settings, validation_visitor)),
215
      http2_options_(Http2::Utility::initializeAndValidateOptions(http2_options)),
216
      common_http_protocol_options_(common_options),
217
      upstream_http_protocol_options_(upstream_options),
218
1.02k
      use_downstream_protocol_(use_downstream_protocol), use_http2_(use_http2) {}
219
220
LEGACY_REGISTER_FACTORY(ProtocolOptionsConfigFactory, Server::Configuration::ProtocolOptionsFactory,
221
                        "envoy.upstreams.http.http_protocol_options");
222
} // namespace Http
223
} // namespace Upstreams
224
} // namespace Extensions
225
} // namespace Envoy