Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/source/extensions/filters/network/http_connection_manager/config.cc
Line
Count
Source (jump to first uncovered line)
1
#include "source/extensions/filters/network/http_connection_manager/config.h"
2
3
#include <chrono>
4
#include <memory>
5
#include <string>
6
#include <vector>
7
8
#include "envoy/config/core/v3/base.pb.h"
9
#include "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.h"
10
#include "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.validate.h"
11
#include "envoy/extensions/http/header_validators/envoy_default/v3/header_validator.pb.h"
12
#include "envoy/extensions/http/original_ip_detection/xff/v3/xff.pb.h"
13
#include "envoy/extensions/request_id/uuid/v3/uuid.pb.h"
14
#include "envoy/filesystem/filesystem.h"
15
#include "envoy/http/header_validator_factory.h"
16
#include "envoy/registry/registry.h"
17
#include "envoy/server/admin.h"
18
#include "envoy/tracing/tracer.h"
19
#include "envoy/type/tracing/v3/custom_tag.pb.h"
20
#include "envoy/type/v3/percent.pb.h"
21
22
#include "source/common/access_log/access_log_impl.h"
23
#include "source/common/common/fmt.h"
24
#include "source/common/config/utility.h"
25
#include "source/common/http/conn_manager_config.h"
26
#include "source/common/http/conn_manager_utility.h"
27
#include "source/common/http/default_server_string.h"
28
#include "source/common/http/http1/codec_impl.h"
29
#include "source/common/http/http1/settings.h"
30
#include "source/common/http/http2/codec_impl.h"
31
#include "source/common/http/request_id_extension_impl.h"
32
#include "source/common/http/utility.h"
33
#include "source/common/local_reply/local_reply.h"
34
#include "source/common/protobuf/utility.h"
35
#include "source/common/quic/server_connection_factory.h"
36
#include "source/common/router/rds_impl.h"
37
#include "source/common/router/scoped_rds.h"
38
#include "source/common/runtime/runtime_impl.h"
39
#include "source/common/tracing/custom_tag_impl.h"
40
#include "source/common/tracing/tracer_config_impl.h"
41
#include "source/common/tracing/tracer_manager_impl.h"
42
43
namespace Envoy {
44
namespace Extensions {
45
namespace NetworkFilters {
46
namespace HttpConnectionManager {
47
namespace {
48
49
using FilterFactoriesList = std::list<Http::FilterFactoryCb>;
50
using FilterFactoryMap = std::map<std::string, HttpConnectionManagerConfig::FilterConfig>;
51
52
HttpConnectionManagerConfig::UpgradeMap::const_iterator
53
findUpgradeBoolCaseInsensitive(const HttpConnectionManagerConfig::UpgradeMap& upgrade_map,
54
0
                               absl::string_view upgrade_type) {
55
0
  for (auto it = upgrade_map.begin(); it != upgrade_map.end(); ++it) {
56
0
    if (StringUtil::CaseInsensitiveCompare()(it->first, upgrade_type)) {
57
0
      return it;
58
0
    }
59
0
  }
60
0
  return upgrade_map.end();
61
0
}
62
63
FilterFactoryMap::const_iterator findUpgradeCaseInsensitive(const FilterFactoryMap& upgrade_map,
64
1.26k
                                                            absl::string_view upgrade_type) {
65
3.08k
  for (auto it = upgrade_map.begin(); it != upgrade_map.end(); ++it) {
66
1.91k
    if (StringUtil::CaseInsensitiveCompare()(it->first, upgrade_type)) {
67
92
      return it;
68
92
    }
69
1.91k
  }
70
1.16k
  return upgrade_map.end();
71
1.26k
}
72
73
std::unique_ptr<Http::InternalAddressConfig> createInternalAddressConfig(
74
    const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
75
6.61k
        config) {
76
6.61k
  if (config.has_internal_address_config()) {
77
766
    return std::make_unique<InternalAddressConfig>(config.internal_address_config());
78
766
  }
79
80
5.84k
  return std::make_unique<Http::DefaultInternalAddressConfig>();
81
6.61k
}
82
83
envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
84
    PathWithEscapedSlashesAction
85
2.71k
    getPathWithEscapedSlashesActionRuntimeOverride(Server::Configuration::FactoryContext& context) {
86
  // The default behavior is to leave escaped slashes unchanged.
87
2.71k
  uint64_t runtime_override = context.runtime().snapshot().getInteger(
88
2.71k
      "http_connection_manager.path_with_escaped_slashes_action", 0);
89
2.71k
  switch (runtime_override) {
90
2.71k
  default:
91
    // Also includes runtime override values of 0 and 1
92
2.71k
    return envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
93
2.71k
        KEEP_UNCHANGED;
94
0
  case 2:
95
0
    return envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
96
0
        REJECT_REQUEST;
97
0
  case 3:
98
0
    return envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
99
0
        UNESCAPE_AND_REDIRECT;
100
0
  case 4:
101
0
    return envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
102
0
        UNESCAPE_AND_FORWARD;
103
2.71k
  }
104
2.71k
}
105
106
envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
107
    PathWithEscapedSlashesAction
108
    getPathWithEscapedSlashesAction(const envoy::extensions::filters::network::
109
                                        http_connection_manager::v3::HttpConnectionManager& config,
110
6.24k
                                    Server::Configuration::FactoryContext& context) {
111
6.24k
  envoy::type::v3::FractionalPercent default_fraction;
112
6.24k
  default_fraction.set_numerator(100);
113
6.24k
  default_fraction.set_denominator(envoy::type::v3::FractionalPercent::HUNDRED);
114
6.24k
  if (context.runtime().snapshot().featureEnabled(
115
6.24k
          "http_connection_manager.path_with_escaped_slashes_action_enabled", default_fraction)) {
116
2.71k
    return config.path_with_escaped_slashes_action() ==
117
2.71k
                   envoy::extensions::filters::network::http_connection_manager::v3::
118
2.71k
                       HttpConnectionManager::IMPLEMENTATION_SPECIFIC_DEFAULT
119
2.71k
               ? getPathWithEscapedSlashesActionRuntimeOverride(context)
120
2.71k
               : config.path_with_escaped_slashes_action();
121
2.71k
  }
122
123
  // When action is disabled through runtime the behavior is to keep escaped slashes unchanged.
124
3.53k
  return envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
125
3.53k
      KEEP_UNCHANGED;
126
6.24k
}
127
128
Http::HeaderValidatorFactoryPtr
129
createHeaderValidatorFactory([[maybe_unused]] const envoy::extensions::filters::network::
130
                                 http_connection_manager::v3::HttpConnectionManager& config,
131
6.24k
                             [[maybe_unused]] Server::Configuration::FactoryContext& context) {
132
133
6.24k
  Http::HeaderValidatorFactoryPtr header_validator_factory;
134
#ifdef ENVOY_ENABLE_UHV
135
  if (!Runtime::runtimeFeatureEnabled(
136
          "envoy.reloadable_features.enable_universal_header_validator")) {
137
    // This will cause codecs to use legacy header validation and path normalization
138
    return nullptr;
139
  }
140
  ::envoy::config::core::v3::TypedExtensionConfig legacy_header_validator_config;
141
  if (!config.has_typed_header_validation_config()) {
142
    // If header validator is not configured ensure that the defaults match Envoy's original
143
    // behavior.
144
    ::envoy::extensions::http::header_validators::envoy_default::v3::HeaderValidatorConfig
145
        uhv_config;
146
    // By default legacy config had path normalization and merge slashes disabled.
147
    uhv_config.mutable_uri_path_normalization_options()->set_skip_path_normalization(
148
        !config.has_normalize_path() || !config.normalize_path().value());
149
    uhv_config.mutable_uri_path_normalization_options()->set_skip_merging_slashes(
150
        !config.merge_slashes());
151
    uhv_config.mutable_uri_path_normalization_options()->set_path_with_escaped_slashes_action(
152
        static_cast<
153
            ::envoy::extensions::http::header_validators::envoy_default::v3::HeaderValidatorConfig::
154
                UriPathNormalizationOptions::PathWithEscapedSlashesAction>(
155
            getPathWithEscapedSlashesAction(config, context)));
156
    uhv_config.mutable_http1_protocol_options()->set_allow_chunked_length(
157
        config.http_protocol_options().allow_chunked_length());
158
    uhv_config.set_headers_with_underscores_action(
159
        static_cast<::envoy::extensions::http::header_validators::envoy_default::v3::
160
                        HeaderValidatorConfig::HeadersWithUnderscoresAction>(
161
            config.common_http_protocol_options().headers_with_underscores_action()));
162
    uhv_config.set_strip_fragment_from_path(!Runtime::runtimeFeatureEnabled(
163
        "envoy.reloadable_features.http_reject_path_with_fragment"));
164
    legacy_header_validator_config.set_name("default_envoy_uhv_from_legacy_settings");
165
    legacy_header_validator_config.mutable_typed_config()->PackFrom(uhv_config);
166
  }
167
168
  const ::envoy::config::core::v3::TypedExtensionConfig& header_validator_config =
169
      config.has_typed_header_validation_config() ? config.typed_header_validation_config()
170
                                                  : legacy_header_validator_config;
171
172
  auto* factory = Envoy::Config::Utility::getFactory<Http::HeaderValidatorFactoryConfig>(
173
      header_validator_config);
174
  if (!factory) {
175
    throwEnvoyExceptionOrPanic(
176
        fmt::format("Header validator extension not found: '{}'", header_validator_config.name()));
177
  }
178
179
  header_validator_factory = factory->createFromProto(header_validator_config.typed_config(),
180
                                                      context.getServerFactoryContext());
181
  if (!header_validator_factory) {
182
    throwEnvoyExceptionOrPanic(fmt::format("Header validator extension could not be created: '{}'",
183
                                           header_validator_config.name()));
184
  }
185
#else
186
6.24k
  if (config.has_typed_header_validation_config()) {
187
7
    throwEnvoyExceptionOrPanic(
188
7
        fmt::format("This Envoy binary does not support header validator extensions.: '{}'",
189
7
                    config.typed_header_validation_config().name()));
190
7
  }
191
192
6.23k
  if (Runtime::runtimeFeatureEnabled(
193
6.23k
          "envoy.reloadable_features.enable_universal_header_validator")) {
194
0
    throwEnvoyExceptionOrPanic(
195
0
        "Header validator can not be enabled since this Envoy binary does not support it.");
196
0
  }
197
6.23k
#endif
198
6.23k
  return header_validator_factory;
199
6.23k
}
200
201
} // namespace
202
203
// Singleton registration via macro defined in envoy/singleton/manager.h
204
SINGLETON_MANAGER_REGISTRATION(date_provider);
205
SINGLETON_MANAGER_REGISTRATION(route_config_provider_manager);
206
SINGLETON_MANAGER_REGISTRATION(scoped_routes_config_provider_manager);
207
208
6.61k
Utility::Singletons Utility::createSingletons(Server::Configuration::FactoryContext& context) {
209
6.61k
  std::shared_ptr<Http::TlsCachingDateProviderImpl> date_provider =
210
6.61k
      context.singletonManager().getTyped<Http::TlsCachingDateProviderImpl>(
211
6.61k
          SINGLETON_MANAGER_REGISTERED_NAME(date_provider), [&context] {
212
5.35k
            return std::make_shared<Http::TlsCachingDateProviderImpl>(
213
5.35k
                context.mainThreadDispatcher(), context.threadLocal());
214
5.35k
          });
215
216
6.61k
  Router::RouteConfigProviderManagerSharedPtr route_config_provider_manager =
217
6.61k
      context.singletonManager().getTyped<Router::RouteConfigProviderManager>(
218
6.61k
          SINGLETON_MANAGER_REGISTERED_NAME(route_config_provider_manager), [&context] {
219
5.35k
            return std::make_shared<Router::RouteConfigProviderManagerImpl>(context.admin());
220
5.35k
          });
221
222
6.61k
  Router::ScopedRoutesConfigProviderManagerSharedPtr scoped_routes_config_provider_manager =
223
6.61k
      context.singletonManager().getTyped<Router::ScopedRoutesConfigProviderManager>(
224
6.61k
          SINGLETON_MANAGER_REGISTERED_NAME(scoped_routes_config_provider_manager),
225
6.61k
          [&context, route_config_provider_manager] {
226
5.35k
            return std::make_shared<Router::ScopedRoutesConfigProviderManager>(
227
5.35k
                context.admin(), *route_config_provider_manager);
228
5.35k
          });
229
230
6.61k
  auto tracer_manager = Tracing::TracerManagerImpl::singleton(context);
231
232
6.61k
  std::shared_ptr<Http::DownstreamFilterConfigProviderManager> filter_config_provider_manager =
233
6.61k
      Http::FilterChainUtility::createSingletonDownstreamFilterConfigProviderManager(
234
6.61k
          context.getServerFactoryContext());
235
236
6.61k
  return {date_provider, route_config_provider_manager, scoped_routes_config_provider_manager,
237
6.61k
          tracer_manager, filter_config_provider_manager};
238
6.61k
}
239
240
std::shared_ptr<HttpConnectionManagerConfig> Utility::createConfig(
241
    const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
242
        proto_config,
243
    Server::Configuration::FactoryContext& context, Http::DateProvider& date_provider,
244
    Router::RouteConfigProviderManager& route_config_provider_manager,
245
    Config::ConfigProviderManager& scoped_routes_config_provider_manager,
246
    Tracing::TracerManager& tracer_manager,
247
6.61k
    FilterConfigProviderManager& filter_config_provider_manager) {
248
6.61k
  return std::make_shared<HttpConnectionManagerConfig>(
249
6.61k
      proto_config, context, date_provider, route_config_provider_manager,
250
6.61k
      scoped_routes_config_provider_manager, tracer_manager, filter_config_provider_manager);
251
6.61k
}
252
253
Network::FilterFactoryCb
254
HttpConnectionManagerFilterConfigFactory::createFilterFactoryFromProtoTyped(
255
    const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
256
        proto_config,
257
6.61k
    Server::Configuration::FactoryContext& context) {
258
6.61k
  return createFilterFactoryFromProtoAndHopByHop(proto_config, context, true);
259
6.61k
}
260
261
Network::FilterFactoryCb
262
HttpConnectionManagerFilterConfigFactory::createFilterFactoryFromProtoAndHopByHop(
263
    const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
264
        proto_config,
265
6.61k
    Server::Configuration::FactoryContext& context, bool clear_hop_by_hop_headers) {
266
6.61k
  Utility::Singletons singletons = Utility::createSingletons(context);
267
268
6.61k
  auto filter_config = Utility::createConfig(
269
6.61k
      proto_config, context, *singletons.date_provider_, *singletons.route_config_provider_manager_,
270
6.61k
      *singletons.scoped_routes_config_provider_manager_, *singletons.tracer_manager_,
271
6.61k
      *singletons.filter_config_provider_manager_);
272
273
  // This lambda captures the shared_ptrs created above, thus preserving the
274
  // reference count.
275
  // Keep in mind the lambda capture list **doesn't** determine the destruction order, but it's fine
276
  // as these captured objects are also global singletons.
277
6.61k
  return [singletons, filter_config, &context,
278
6.61k
          clear_hop_by_hop_headers](Network::FilterManager& filter_manager) -> void {
279
4.97k
    auto hcm = std::make_shared<Http::ConnectionManagerImpl>(
280
4.97k
        *filter_config, context.drainDecision(), context.api().randomGenerator(),
281
4.97k
        context.httpContext(), context.runtime(), context.localInfo(), context.clusterManager(),
282
4.97k
        context.overloadManager(), context.mainThreadDispatcher().timeSource());
283
4.97k
    if (!clear_hop_by_hop_headers) {
284
0
      hcm->setClearHopByHopResponseHeaders(false);
285
0
    }
286
4.97k
    filter_manager.addReadFilter(std::move(hcm));
287
4.97k
  };
288
6.61k
}
289
290
Network::FilterFactoryCb
291
MobileHttpConnectionManagerFilterConfigFactory::createFilterFactoryFromProtoTyped(
292
    const envoy::extensions::filters::network::http_connection_manager::v3::
293
        EnvoyMobileHttpConnectionManager& mobile_config,
294
0
    Server::Configuration::FactoryContext& context) {
295
0
  return HttpConnectionManagerFilterConfigFactory::createFilterFactoryFromProtoAndHopByHop(
296
0
      mobile_config.config(), context, false);
297
0
}
298
299
/**
300
 * Static registration for the HTTP connection manager filter.
301
 */
302
LEGACY_REGISTER_FACTORY(HttpConnectionManagerFilterConfigFactory,
303
                        Server::Configuration::NamedNetworkFilterConfigFactory,
304
                        "envoy.http_connection_manager");
305
306
InternalAddressConfig::InternalAddressConfig(
307
    const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
308
        InternalAddressConfig& config)
309
766
    : unix_sockets_(config.unix_sockets()), cidr_ranges_(config.cidr_ranges()) {}
310
311
HttpConnectionManagerConfig::HttpConnectionManagerConfig(
312
    const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
313
        config,
314
    Server::Configuration::FactoryContext& context, Http::DateProvider& date_provider,
315
    Router::RouteConfigProviderManager& route_config_provider_manager,
316
    Config::ConfigProviderManager& scoped_routes_config_provider_manager,
317
    Tracing::TracerManager& tracer_manager,
318
    FilterConfigProviderManager& filter_config_provider_manager)
319
    : context_(context), stats_prefix_(fmt::format("http.{}.", config.stat_prefix())),
320
      stats_(Http::ConnectionManagerImpl::generateStats(stats_prefix_, context_.scope())),
321
      tracing_stats_(
322
          Http::ConnectionManagerImpl::generateTracingStats(stats_prefix_, context_.scope())),
323
      use_remote_address_(PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, use_remote_address, false)),
324
      internal_address_config_(createInternalAddressConfig(config)),
325
      xff_num_trusted_hops_(config.xff_num_trusted_hops()),
326
      skip_xff_append_(config.skip_xff_append()), via_(config.via()),
327
      route_config_provider_manager_(route_config_provider_manager),
328
      scoped_routes_config_provider_manager_(scoped_routes_config_provider_manager),
329
      filter_config_provider_manager_(filter_config_provider_manager),
330
      http3_options_(Http3::Utility::initializeAndValidateOptions(
331
          config.http3_protocol_options(), config.has_stream_error_on_invalid_http_message(),
332
          config.stream_error_on_invalid_http_message())),
333
      http2_options_(Http2::Utility::initializeAndValidateOptions(
334
          config.http2_protocol_options(), config.has_stream_error_on_invalid_http_message(),
335
          config.stream_error_on_invalid_http_message())),
336
      http1_settings_(Http::Http1::parseHttp1Settings(
337
          config.http_protocol_options(), context.messageValidationVisitor(),
338
          config.stream_error_on_invalid_http_message(),
339
          xff_num_trusted_hops_ == 0 && use_remote_address_)),
340
      max_request_headers_kb_(PROTOBUF_GET_WRAPPED_OR_DEFAULT(
341
          config, max_request_headers_kb,
342
          context.runtime().snapshot().getInteger(Http::MaxRequestHeadersSizeOverrideKey,
343
                                                  Http::DEFAULT_MAX_REQUEST_HEADERS_KB))),
344
      max_request_headers_count_(PROTOBUF_GET_WRAPPED_OR_DEFAULT(
345
          config.common_http_protocol_options(), max_headers_count,
346
          context.runtime().snapshot().getInteger(Http::MaxRequestHeadersCountOverrideKey,
347
                                                  Http::DEFAULT_MAX_HEADERS_COUNT))),
348
      idle_timeout_(PROTOBUF_GET_OPTIONAL_MS(config.common_http_protocol_options(), idle_timeout)),
349
      max_connection_duration_(
350
          PROTOBUF_GET_OPTIONAL_MS(config.common_http_protocol_options(), max_connection_duration)),
351
      max_stream_duration_(
352
          PROTOBUF_GET_OPTIONAL_MS(config.common_http_protocol_options(), max_stream_duration)),
353
      stream_idle_timeout_(
354
          PROTOBUF_GET_MS_OR_DEFAULT(config, stream_idle_timeout, StreamIdleTimeoutMs)),
355
      request_timeout_(PROTOBUF_GET_MS_OR_DEFAULT(config, request_timeout, RequestTimeoutMs)),
356
      request_headers_timeout_(
357
          PROTOBUF_GET_MS_OR_DEFAULT(config, request_headers_timeout, RequestHeaderTimeoutMs)),
358
      drain_timeout_(PROTOBUF_GET_MS_OR_DEFAULT(config, drain_timeout, 5000)),
359
      generate_request_id_(PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, generate_request_id, true)),
360
      preserve_external_request_id_(config.preserve_external_request_id()),
361
      always_set_request_id_in_response_(config.always_set_request_id_in_response()),
362
      date_provider_(date_provider),
363
      listener_stats_(Http::ConnectionManagerImpl::generateListenerStats(stats_prefix_,
364
                                                                         context_.listenerScope())),
365
      proxy_100_continue_(config.proxy_100_continue()),
366
      stream_error_on_invalid_http_messaging_(
367
          PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, stream_error_on_invalid_http_message, false)),
368
      delayed_close_timeout_(PROTOBUF_GET_MS_OR_DEFAULT(config, delayed_close_timeout, 1000)),
369
#ifdef ENVOY_NORMALIZE_PATH_BY_DEFAULT
370
      normalize_path_(PROTOBUF_GET_WRAPPED_OR_DEFAULT(
371
          config, normalize_path,
372
          // TODO(htuch): we should have a boolean variant of featureEnabled() here.
373
          context.runtime().snapshot().featureEnabled("http_connection_manager.normalize_path",
374
                                                      100))),
375
#else
376
      normalize_path_(PROTOBUF_GET_WRAPPED_OR_DEFAULT(
377
          config, normalize_path,
378
          // TODO(htuch): we should have a boolean variant of featureEnabled() here.
379
          context.runtime().snapshot().featureEnabled("http_connection_manager.normalize_path",
380
                                                      0))),
381
#endif
382
      merge_slashes_(config.merge_slashes()),
383
      headers_with_underscores_action_(
384
          config.common_http_protocol_options().headers_with_underscores_action()),
385
      local_reply_(LocalReply::Factory::create(config.local_reply_config(), context)),
386
      path_with_escaped_slashes_action_(getPathWithEscapedSlashesAction(config, context)),
387
      strip_trailing_host_dot_(config.strip_trailing_host_dot()),
388
      max_requests_per_connection_(PROTOBUF_GET_WRAPPED_OR_DEFAULT(
389
          config.common_http_protocol_options(), max_requests_per_connection, 0)),
390
      proxy_status_config_(config.has_proxy_status_config()
391
                               ? std::make_unique<HttpConnectionManagerProto::ProxyStatusConfig>(
392
                                     config.proxy_status_config())
393
                               : nullptr),
394
      header_validator_factory_(createHeaderValidatorFactory(config, context)),
395
      append_x_forwarded_port_(config.append_x_forwarded_port()),
396
      add_proxy_protocol_connection_state_(
397
6.61k
          PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, add_proxy_protocol_connection_state, true)) {
398
6.61k
  if (!idle_timeout_) {
399
5.88k
    idle_timeout_ = std::chrono::hours(1);
400
5.88k
  } else if (idle_timeout_.value().count() == 0) {
401
207
    idle_timeout_ = absl::nullopt;
402
207
  }
403
404
6.61k
  if (config.strip_any_host_port() && config.strip_matching_host_port()) {
405
15
    throwEnvoyExceptionOrPanic(fmt::format(
406
15
        "Error: Only one of `strip_matching_host_port` or `strip_any_host_port` can be set."));
407
15
  }
408
409
6.59k
  if (config.strip_any_host_port()) {
410
700
    strip_port_type_ = Http::StripPortType::Any;
411
5.89k
  } else if (config.strip_matching_host_port()) {
412
497
    strip_port_type_ = Http::StripPortType::MatchingHost;
413
5.40k
  } else {
414
5.40k
    strip_port_type_ = Http::StripPortType::None;
415
5.40k
  }
416
417
  // If we are provided a different request_id_extension implementation to use try and create a
418
  // new instance of it, otherwise use default one.
419
6.59k
  envoy::extensions::filters::network::http_connection_manager::v3::RequestIDExtension
420
6.59k
      final_rid_config = config.request_id_extension();
421
6.59k
  if (!final_rid_config.has_typed_config()) {
422
    // This creates a default version of the UUID extension which is a required extension in the
423
    // build.
424
6.14k
    final_rid_config.mutable_typed_config()->PackFrom(
425
6.14k
        envoy::extensions::request_id::uuid::v3::UuidRequestIdConfig());
426
6.14k
  }
427
6.59k
  auto extension_or_error = Http::RequestIDExtensionFactory::fromProto(final_rid_config, context_);
428
6.59k
  THROW_IF_STATUS_NOT_OK(extension_or_error, throw);
429
6.51k
  request_id_extension_ = extension_or_error.value();
430
431
  // Check if IP detection extensions were configured, otherwise fall back to XFF.
432
6.51k
  auto ip_detection_extensions = config.original_ip_detection_extensions();
433
6.51k
  if (ip_detection_extensions.empty()) {
434
6.11k
    envoy::extensions::http::original_ip_detection::xff::v3::XffConfig xff_config;
435
6.11k
    xff_config.set_xff_num_trusted_hops(xff_num_trusted_hops_);
436
437
6.11k
    auto* extension = ip_detection_extensions.Add();
438
6.11k
    extension->set_name("envoy.http.original_ip_detection.xff");
439
6.11k
    extension->mutable_typed_config()->PackFrom(xff_config);
440
6.11k
  } else {
441
400
    if (use_remote_address_) {
442
2
      throwEnvoyExceptionOrPanic(
443
2
          "Original IP detection extensions and use_remote_address may not be mixed");
444
2
    }
445
446
398
    if (xff_num_trusted_hops_ > 0) {
447
6
      throwEnvoyExceptionOrPanic(
448
6
          "Original IP detection extensions and xff_num_trusted_hops may not be mixed");
449
6
    }
450
398
  }
451
452
6.51k
  original_ip_detection_extensions_.reserve(ip_detection_extensions.size());
453
6.51k
  for (const auto& extension_config : ip_detection_extensions) {
454
6.13k
    auto* factory =
455
6.13k
        Envoy::Config::Utility::getFactory<Http::OriginalIPDetectionFactory>(extension_config);
456
6.13k
    if (!factory) {
457
18
      throwEnvoyExceptionOrPanic(
458
18
          fmt::format("Original IP detection extension not found: '{}'", extension_config.name()));
459
18
    }
460
461
6.11k
    auto extension = factory->createExtension(extension_config.typed_config(), context_);
462
6.11k
    if (!extension) {
463
0
      throwEnvoyExceptionOrPanic(fmt::format(
464
0
          "Original IP detection extension could not be created: '{}'", extension_config.name()));
465
0
    }
466
6.11k
    original_ip_detection_extensions_.push_back(extension);
467
6.11k
  }
468
469
6.49k
  const auto& header_mutation_extensions = config.early_header_mutation_extensions();
470
6.49k
  early_header_mutation_extensions_.reserve(header_mutation_extensions.size());
471
6.49k
  for (const auto& extension_config : header_mutation_extensions) {
472
13
    auto* factory =
473
13
        Envoy::Config::Utility::getFactory<Http::EarlyHeaderMutationFactory>(extension_config);
474
13
    if (!factory) {
475
13
      throwEnvoyExceptionOrPanic(
476
13
          fmt::format("Early header mutation extension not found: '{}'", extension_config.name()));
477
13
    }
478
479
0
    auto extension = factory->createExtension(extension_config.typed_config(), context_);
480
0
    if (!extension) {
481
0
      throwEnvoyExceptionOrPanic(fmt::format(
482
0
          "Early header mutation extension could not be created: '{}'", extension_config.name()));
483
0
    }
484
0
    early_header_mutation_extensions_.push_back(std::move(extension));
485
0
  }
486
487
  // If scoped RDS is enabled, avoid creating a route config provider. Route config providers
488
  // will be managed by the scoped routing logic instead.
489
6.47k
  switch (config.route_specifier_case()) {
490
231
  case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
491
231
      RouteSpecifierCase::kRds:
492
6.00k
  case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
493
6.00k
      RouteSpecifierCase::kRouteConfig:
494
6.00k
    route_config_provider_ = Router::RouteConfigProviderUtil::create(
495
6.00k
        config, context_.getServerFactoryContext(), context_.messageValidationVisitor(),
496
6.00k
        context_.initManager(), stats_prefix_, route_config_provider_manager_);
497
6.00k
    break;
498
101
  case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
499
101
      RouteSpecifierCase::kScopedRoutes:
500
101
    scoped_routes_config_provider_ = Router::ScopedRoutesConfigProviderUtil::create(
501
101
        config, context_.getServerFactoryContext(), context_.initManager(), stats_prefix_,
502
101
        scoped_routes_config_provider_manager_);
503
101
    scope_key_builder_ = Router::ScopedRoutesConfigProviderUtil::createScopeKeyBuilder(config);
504
101
    break;
505
0
  case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
506
0
      RouteSpecifierCase::ROUTE_SPECIFIER_NOT_SET:
507
0
    PANIC_DUE_TO_CORRUPT_ENUM;
508
6.47k
  }
509
510
5.42k
  switch (config.forward_client_cert_details()) {
511
0
    PANIC_ON_PROTO_ENUM_SENTINEL_VALUES;
512
4.63k
  case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
513
4.63k
      SANITIZE:
514
4.63k
    forward_client_cert_ = Http::ForwardClientCertType::Sanitize;
515
4.63k
    break;
516
544
  case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
517
544
      FORWARD_ONLY:
518
544
    forward_client_cert_ = Http::ForwardClientCertType::ForwardOnly;
519
544
    break;
520
92
  case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
521
92
      APPEND_FORWARD:
522
92
    forward_client_cert_ = Http::ForwardClientCertType::AppendForward;
523
92
    break;
524
77
  case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
525
77
      SANITIZE_SET:
526
77
    forward_client_cert_ = Http::ForwardClientCertType::SanitizeSet;
527
77
    break;
528
80
  case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
529
80
      ALWAYS_FORWARD_ONLY:
530
80
    forward_client_cert_ = Http::ForwardClientCertType::AlwaysForwardOnly;
531
80
    break;
532
5.42k
  }
533
534
5.42k
  const auto& set_current_client_cert_details = config.set_current_client_cert_details();
535
5.42k
  if (set_current_client_cert_details.cert()) {
536
234
    set_current_client_cert_details_.push_back(Http::ClientCertDetailsType::Cert);
537
234
  }
538
5.42k
  if (set_current_client_cert_details.chain()) {
539
193
    set_current_client_cert_details_.push_back(Http::ClientCertDetailsType::Chain);
540
193
  }
541
5.42k
  if (PROTOBUF_GET_WRAPPED_OR_DEFAULT(set_current_client_cert_details, subject, false)) {
542
215
    set_current_client_cert_details_.push_back(Http::ClientCertDetailsType::Subject);
543
215
  }
544
5.42k
  if (set_current_client_cert_details.uri()) {
545
158
    set_current_client_cert_details_.push_back(Http::ClientCertDetailsType::URI);
546
158
  }
547
5.42k
  if (set_current_client_cert_details.dns()) {
548
120
    set_current_client_cert_details_.push_back(Http::ClientCertDetailsType::DNS);
549
120
  }
550
551
5.42k
  if (config.has_add_user_agent() && config.add_user_agent().value()) {
552
251
    user_agent_ = context_.localInfo().clusterName();
553
251
  }
554
555
5.42k
  if (config.has_tracing()) {
556
876
    tracer_ = tracer_manager.getOrCreateTracer(getPerFilterTracerConfig(config));
557
876
    tracing_config_ = std::make_unique<Http::TracingConnectionManagerConfig>(context.direction(),
558
876
                                                                             config.tracing());
559
876
  }
560
561
5.42k
  for (const auto& access_log : config.access_log()) {
562
2.97k
    AccessLog::InstanceSharedPtr current_access_log =
563
2.97k
        AccessLog::AccessLogFactory::fromProto(access_log, context_);
564
2.97k
    access_logs_.push_back(current_access_log);
565
2.97k
  }
566
567
5.42k
  if (config.has_access_log_options()) {
568
309
    if (config.flush_access_log_on_new_request() /* deprecated */) {
569
27
      throwEnvoyExceptionOrPanic(
570
27
          "Only one of flush_access_log_on_new_request or access_log_options can be specified.");
571
27
    }
572
573
282
    if (config.has_access_log_flush_interval()) {
574
3
      throwEnvoyExceptionOrPanic(
575
3
          "Only one of access_log_flush_interval or access_log_options can be specified.");
576
3
    }
577
578
279
    flush_access_log_on_new_request_ =
579
279
        config.access_log_options().flush_access_log_on_new_request();
580
279
    flush_log_on_tunnel_successfully_established_ =
581
279
        config.access_log_options().flush_log_on_tunnel_successfully_established();
582
583
279
    if (config.access_log_options().has_access_log_flush_interval()) {
584
24
      access_log_flush_interval_ = std::chrono::milliseconds(DurationUtil::durationToMilliseconds(
585
24
          config.access_log_options().access_log_flush_interval()));
586
24
    }
587
5.11k
  } else {
588
5.11k
    flush_access_log_on_new_request_ = config.flush_access_log_on_new_request();
589
590
5.11k
    if (config.has_access_log_flush_interval()) {
591
198
      access_log_flush_interval_ = std::chrono::milliseconds(
592
198
          DurationUtil::durationToMilliseconds(config.access_log_flush_interval()));
593
198
    }
594
5.11k
  }
595
596
5.39k
  server_transformation_ = config.server_header_transformation();
597
598
5.39k
  if (!config.scheme_header_transformation().scheme_to_overwrite().empty()) {
599
1
    scheme_to_set_ = config.scheme_header_transformation().scheme_to_overwrite();
600
1
  }
601
602
5.39k
  if (!config.server_name().empty()) {
603
393
    server_name_ = config.server_name();
604
5.00k
  } else {
605
5.00k
    server_name_ = Http::DefaultServerString::get();
606
5.00k
  }
607
608
5.39k
  switch (config.codec_type()) {
609
0
    PANIC_ON_PROTO_ENUM_SENTINEL_VALUES;
610
1.88k
  case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
611
1.88k
      AUTO:
612
1.88k
    codec_type_ = CodecType::AUTO;
613
1.88k
    break;
614
1.26k
  case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
615
1.26k
      HTTP1:
616
1.26k
    codec_type_ = CodecType::HTTP1;
617
1.26k
    break;
618
1.72k
  case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
619
1.72k
      HTTP2:
620
1.72k
    codec_type_ = CodecType::HTTP2;
621
1.72k
    break;
622
144
  case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
623
144
      HTTP3:
624
144
#ifdef ENVOY_ENABLE_QUIC
625
144
    codec_type_ = CodecType::HTTP3;
626
144
    if (!context_.isQuicListener()) {
627
144
      throwEnvoyExceptionOrPanic("HTTP/3 codec configured on non-QUIC listener.");
628
144
    }
629
#else
630
    throwEnvoyExceptionOrPanic("HTTP3 configured but not enabled in the build.");
631
#endif
632
0
    break;
633
5.39k
  }
634
4.87k
  if (codec_type_ != CodecType::HTTP3 && context_.isQuicListener()) {
635
0
    throwEnvoyExceptionOrPanic("Non-HTTP/3 codec configured on QUIC listener.");
636
0
  }
637
638
4.87k
  Http::FilterChainHelper<Server::Configuration::FactoryContext,
639
4.87k
                          Server::Configuration::NamedHttpFilterConfigFactory>
640
4.87k
      helper(filter_config_provider_manager_, context_.getServerFactoryContext(),
641
4.87k
             context_.clusterManager(), context_, stats_prefix_);
642
4.87k
  THROW_IF_NOT_OK(helper.processFilters(config.http_filters(), "http", "http", filter_factories_));
643
644
4.83k
  for (const auto& upgrade_config : config.upgrade_configs()) {
645
1.26k
    const std::string& name = upgrade_config.upgrade_type();
646
1.26k
    const bool enabled = upgrade_config.has_enabled() ? upgrade_config.enabled().value() : true;
647
1.26k
    if (findUpgradeCaseInsensitive(upgrade_filter_factories_, name) !=
648
1.26k
        upgrade_filter_factories_.end()) {
649
92
      throwEnvoyExceptionOrPanic(
650
92
          fmt::format("Error: multiple upgrade configs with the same name: '{}'", name));
651
92
    }
652
1.16k
    if (!upgrade_config.filters().empty()) {
653
79
      std::unique_ptr<FilterFactoriesList> factories = std::make_unique<FilterFactoriesList>();
654
79
      Http::DependencyManager upgrade_dependency_manager;
655
79
      THROW_IF_NOT_OK(
656
79
          helper.processFilters(upgrade_config.filters(), name, "http upgrade", *factories));
657
      // TODO(auni53): Validate encode dependencies too.
658
74
      auto status = upgrade_dependency_manager.validDecodeDependencies();
659
74
      if (!status.ok()) {
660
0
        throwEnvoyExceptionOrPanic(std::string(status.message()));
661
0
      }
662
663
74
      upgrade_filter_factories_.emplace(
664
74
          std::make_pair(name, FilterConfig{std::move(factories), enabled}));
665
1.09k
    } else {
666
1.09k
      std::unique_ptr<FilterFactoriesList> factories(nullptr);
667
1.09k
      upgrade_filter_factories_.emplace(
668
1.09k
          std::make_pair(name, FilterConfig{std::move(factories), enabled}));
669
1.09k
    }
670
1.16k
  }
671
4.83k
}
672
673
Http::ServerConnectionPtr HttpConnectionManagerConfig::createCodec(
674
    Network::Connection& connection, const Buffer::Instance& data,
675
3.09k
    Http::ServerConnectionCallbacks& callbacks, Server::OverloadManager& overload_manager) {
676
3.09k
  switch (codec_type_) {
677
495
  case CodecType::HTTP1:
678
495
    return std::make_unique<Http::Http1::ServerConnectionImpl>(
679
495
        connection, Http::Http1::CodecStats::atomicGet(http1_codec_stats_, context_.scope()),
680
495
        callbacks, http1_settings_, maxRequestHeadersKb(), maxRequestHeadersCount(),
681
495
        headersWithUnderscoresAction(), overload_manager);
682
1.41k
  case CodecType::HTTP2:
683
1.41k
    return std::make_unique<Http::Http2::ServerConnectionImpl>(
684
1.41k
        connection, callbacks,
685
1.41k
        Http::Http2::CodecStats::atomicGet(http2_codec_stats_, context_.scope()),
686
1.41k
        context_.api().randomGenerator(), http2_options_, maxRequestHeadersKb(),
687
1.41k
        maxRequestHeadersCount(), headersWithUnderscoresAction(), overload_manager);
688
0
  case CodecType::HTTP3:
689
0
    return Config::Utility::getAndCheckFactoryByName<QuicHttpServerConnectionFactory>(
690
0
               "quic.http_server_connection.default")
691
0
        .createQuicHttpServerConnectionImpl(
692
0
            connection, callbacks,
693
0
            Http::Http3::CodecStats::atomicGet(http3_codec_stats_, context_.scope()),
694
0
            http3_options_, maxRequestHeadersKb(), maxRequestHeadersCount(),
695
0
            headersWithUnderscoresAction());
696
1.18k
  case CodecType::AUTO:
697
1.18k
    return Http::ConnectionManagerUtility::autoCreateCodec(
698
1.18k
        connection, data, callbacks, context_.scope(), context_.api().randomGenerator(),
699
1.18k
        http1_codec_stats_, http2_codec_stats_, http1_settings_, http2_options_,
700
1.18k
        maxRequestHeadersKb(), maxRequestHeadersCount(), headersWithUnderscoresAction(),
701
1.18k
        overload_manager);
702
3.09k
  }
703
0
  PANIC_DUE_TO_CORRUPT_ENUM;
704
0
}
705
706
bool HttpConnectionManagerConfig::createFilterChain(Http::FilterChainManager& manager, bool,
707
2.48k
                                                    const Http::FilterChainOptions& options) const {
708
2.48k
  Http::FilterChainUtility::createFilterChainForFactories(manager, options, filter_factories_);
709
2.48k
  return true;
710
2.48k
}
711
712
bool HttpConnectionManagerConfig::createUpgradeFilterChain(
713
    absl::string_view upgrade_type,
714
    const Http::FilterChainFactory::UpgradeMap* per_route_upgrade_map,
715
0
    Http::FilterChainManager& callbacks) const {
716
0
  bool route_enabled = false;
717
0
  if (per_route_upgrade_map) {
718
0
    auto route_it = findUpgradeBoolCaseInsensitive(*per_route_upgrade_map, upgrade_type);
719
0
    if (route_it != per_route_upgrade_map->end()) {
720
      // Upgrades explicitly not allowed on this route.
721
0
      if (route_it->second == false) {
722
0
        return false;
723
0
      }
724
      // Upgrades explicitly enabled on this route.
725
0
      route_enabled = true;
726
0
    }
727
0
  }
728
729
0
  auto it = findUpgradeCaseInsensitive(upgrade_filter_factories_, upgrade_type);
730
0
  if ((it == upgrade_filter_factories_.end() || !it->second.allow_upgrade) && !route_enabled) {
731
    // Either the HCM disables upgrades and the route-config does not override,
732
    // or neither is configured for this upgrade.
733
0
    return false;
734
0
  }
735
0
  const FilterFactoriesList* filters_to_use = &filter_factories_;
736
0
  if (it != upgrade_filter_factories_.end() && it->second.filter_factories != nullptr) {
737
0
    filters_to_use = it->second.filter_factories.get();
738
0
  }
739
740
0
  Http::FilterChainUtility::createFilterChainForFactories(
741
0
      callbacks, Http::EmptyFilterChainOptions{}, *filters_to_use);
742
0
  return true;
743
0
}
744
745
0
const Network::Address::Instance& HttpConnectionManagerConfig::localAddress() {
746
0
  return *context_.localInfo().address();
747
0
}
748
749
/**
750
 * Determines what tracing provider to use for a given
751
 * "envoy.filters.network.http_connection_manager" filter instance.
752
 */
753
const envoy::config::trace::v3::Tracing_Http* HttpConnectionManagerConfig::getPerFilterTracerConfig(
754
    const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
755
876
        config) {
756
  // Give precedence to tracing provider configuration defined as part of
757
  // "envoy.filters.network.http_connection_manager" filter config.
758
876
  if (config.tracing().has_provider()) {
759
31
    return &config.tracing().provider();
760
31
  }
761
  // Otherwise, for the sake of backwards compatibility, fall back to using tracing provider
762
  // configuration defined in the bootstrap config.
763
845
  if (context_.httpContext().defaultTracingConfig().has_http()) {
764
0
    return &context_.httpContext().defaultTracingConfig().http();
765
0
  }
766
845
  return nullptr;
767
845
}
768
769
#ifdef ENVOY_ENABLE_UHV
770
::Envoy::Http::HeaderValidatorStats&
771
HttpConnectionManagerConfig::getHeaderValidatorStats([[maybe_unused]] Http::Protocol protocol) {
772
  switch (protocol) {
773
  case Http::Protocol::Http10:
774
  case Http::Protocol::Http11:
775
    return Http::Http1::CodecStats::atomicGet(http1_codec_stats_, context_.scope());
776
  case Http::Protocol::Http2:
777
    return Http::Http2::CodecStats::atomicGet(http2_codec_stats_, context_.scope());
778
  case Http::Protocol::Http3:
779
    return Http::Http3::CodecStats::atomicGet(http3_codec_stats_, context_.scope());
780
  }
781
  PANIC_DUE_TO_CORRUPT_ENUM;
782
}
783
#endif
784
785
std::function<Http::ApiListenerPtr(Network::ReadFilterCallbacks&)>
786
HttpConnectionManagerFactory::createHttpConnectionManagerFactoryFromProto(
787
    const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
788
        proto_config,
789
0
    Server::Configuration::FactoryContext& context, bool clear_hop_by_hop_headers) {
790
0
  Utility::Singletons singletons = Utility::createSingletons(context);
791
792
0
  auto filter_config = Utility::createConfig(
793
0
      proto_config, context, *singletons.date_provider_, *singletons.route_config_provider_manager_,
794
0
      *singletons.scoped_routes_config_provider_manager_, *singletons.tracer_manager_,
795
0
      *singletons.filter_config_provider_manager_);
796
797
  // This lambda captures the shared_ptrs created above, thus preserving the
798
  // reference count.
799
  // Keep in mind the lambda capture list **doesn't** determine the destruction order, but it's fine
800
  // as these captured objects are also global singletons.
801
0
  return [singletons, filter_config, &context, clear_hop_by_hop_headers](
802
0
             Network::ReadFilterCallbacks& read_callbacks) -> Http::ApiListenerPtr {
803
0
    auto conn_manager = std::make_unique<Http::ConnectionManagerImpl>(
804
0
        *filter_config, context.drainDecision(), context.api().randomGenerator(),
805
0
        context.httpContext(), context.runtime(), context.localInfo(), context.clusterManager(),
806
0
        context.overloadManager(), context.mainThreadDispatcher().timeSource());
807
0
    if (!clear_hop_by_hop_headers) {
808
0
      conn_manager->setClearHopByHopResponseHeaders(false);
809
0
    }
810
811
    // This factory creates a new ConnectionManagerImpl in the absence of its usual environment as
812
    // an L4 filter, so this factory needs to take a few actions.
813
814
    // When a new connection is creating its filter chain it hydrates the factory with a filter
815
    // manager which provides the ConnectionManager with its "read_callbacks".
816
0
    conn_manager->initializeReadFilterCallbacks(read_callbacks);
817
818
    // When the connection first calls onData on the ConnectionManager, the ConnectionManager
819
    // creates a codec. Here we force create a codec as onData will not be called.
820
0
    Buffer::OwnedImpl dummy;
821
0
    conn_manager->createCodec(dummy);
822
823
0
    return conn_manager;
824
0
  };
825
0
}
826
827
} // namespace HttpConnectionManager
828
} // namespace NetworkFilters
829
} // namespace Extensions
830
} // namespace Envoy