diff --git a/.azure-pipelines/docker/save_cache.sh b/.azure-pipelines/docker/save_cache.sh index f51fa1006b7d..f80f28d9f56b 100755 --- a/.azure-pipelines/docker/save_cache.sh +++ b/.azure-pipelines/docker/save_cache.sh @@ -36,6 +36,7 @@ if [[ "$CACHE_BAZEL" == "true" ]]; then ./.azure-pipelines/docker/create_cache.sh \ "${BAZEL_CACHE_TARBALL}" \ "${ENVOY_DOCKER_BUILD_DIR}" \ + .cache \ bazel_root/install \ bazel_root/base/external \ repository_cache diff --git a/.azure-pipelines/pipelines.yml b/.azure-pipelines/pipelines.yml index 5c8e740463b1..6cb7ac6fff03 100644 --- a/.azure-pipelines/pipelines.yml +++ b/.azure-pipelines/pipelines.yml @@ -45,7 +45,7 @@ variables: ## Variable settings # Caches (tip: append a version suffix while testing caches) - name: cacheKeyVersion - value: v1 + value: v2 - name: cacheKeyBazel value: '.bazelversion | ./WORKSPACE | **/*.bzl, !mobile/**, !envoy-docs/**' - name: cacheKeyDocker diff --git a/.bazelrc b/.bazelrc index 689702e0224e..8167ab650f21 100644 --- a/.bazelrc +++ b/.bazelrc @@ -343,7 +343,7 @@ build:compile-time-options --@envoy//source/extensions/filters/http/kill_request # Docker sandbox # NOTE: Update this from https://github.com/envoyproxy/envoy-build-tools/blob/main/toolchains/rbe_toolchains_config.bzl#L8 -build:docker-sandbox --experimental_docker_image=envoyproxy/envoy-build-ubuntu:1f2f7ee78f894859de0fa7a415b0bedde1f6c560@sha256:6a6a64be3f4e3c4380531ad1624f9419d1fe99dde4e5eeb04e2d538a92f27205 +build:docker-sandbox --experimental_docker_image=envoyproxy/envoy-build-ubuntu:56f235b141079013e64912d676fe7da981368402@sha256:d44499c6fd28a8a6a75dc61668b8a9e7bc3d99db11f9a61e8ea1d1f39c20a236 build:docker-sandbox --spawn_strategy=docker build:docker-sandbox --strategy=Javac=docker build:docker-sandbox --strategy=Closure=docker diff --git a/.clang-tidy b/.clang-tidy index 02ac33e00da5..7e9d197c9921 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,85 +1,77 @@ -Checks: '-clang-analyzer-core.NonNullParamChecker, - -clang-analyzer-optin.cplusplus.UninitializedObject, - abseil-duration-*, - abseil-faster-strsplit-delimiter, - abseil-no-namespace, - abseil-redundant-strcat-calls, - abseil-str-cat-append, - abseil-string-find-startswith, - abseil-upgrade-duration-conversions, - bugprone-assert-side-effect, - bugprone-unused-raii, - bugprone-use-after-move, - clang-analyzer-core.DivideZero, - misc-unused-using-decls, - modernize-deprecated-headers, - modernize-loop-convert, - modernize-make-shared, - modernize-make-unique, - modernize-return-braced-init-list, - modernize-use-default-member-init, - modernize-use-equals-default, - modernize-use-nullptr, - modernize-use-override, - modernize-use-using, - performance-faster-string-find, - performance-for-range-copy, - performance-inefficient-algorithm, - performance-inefficient-vector-operation, - performance-noexcept-move-constructor, - performance-move-constructor-init, - performance-type-promotion-in-math-fn, - performance-unnecessary-copy-initialization, - readability-braces-around-statements, - readability-container-size-empty, - readability-identifier-naming, - readability-redundant-control-flow, - readability-redundant-member-init, - readability-redundant-smartptr-get, - readability-redundant-string-cstr' - -WarningsAsErrors: '*' +Checks: > + -clang-analyzer-core.NonNullParamChecker, + -clang-analyzer-optin.cplusplus.UninitializedObject, + abseil-duration-*, + abseil-faster-strsplit-delimiter, + abseil-no-namespace, + abseil-redundant-strcat-calls, + abseil-str-cat-append, + abseil-string-find-startswith, + abseil-upgrade-duration-conversions, + bugprone-assert-side-effect, + bugprone-unused-raii, + bugprone-use-after-move, + clang-analyzer-core.DivideZero, + misc-unused-using-decls, + modernize-deprecated-headers, + modernize-loop-convert, + modernize-make-shared, + modernize-make-unique, + modernize-return-braced-init-list, + modernize-use-default-member-init, + modernize-use-equals-default, + modernize-use-nullptr, + modernize-use-override, + modernize-use-using, + performance-faster-string-find, + performance-for-range-copy, + performance-inefficient-algorithm, + performance-inefficient-vector-operation, + performance-noexcept-move-constructor, + performance-move-constructor-init, + performance-type-promotion-in-math-fn, + performance-unnecessary-copy-initialization, + readability-braces-around-statements, + readability-container-size-empty, + readability-identifier-naming, + readability-redundant-control-flow, + readability-redundant-member-init, + readability-redundant-smartptr-get, + readability-redundant-string-cstr CheckOptions: - - key: bugprone-assert-side-effect.AssertMacros - value: 'ASSERT' - - - key: bugprone-dangling-handle.HandleClasses - value: 'std::basic_string_view;std::experimental::basic_string_view;absl::string_view' - - - key: modernize-use-auto.MinTypeNameLength - value: '10' - - - key: readability-identifier-naming.ClassCase - value: 'CamelCase' - - - key: readability-identifier-naming.EnumCase - value: 'CamelCase' - - - key: readability-identifier-naming.EnumConstantCase - value: 'CamelCase' - - # Ignore GoogleTest function macros. - - key: readability-identifier-naming.FunctionIgnoredRegexp - value: '(TEST|TEST_F|TEST_P|INSTANTIATE_TEST_SUITE_P|MOCK_METHOD|TYPED_TEST)' - - - key: readability-identifier-naming.ParameterCase - value: 'lower_case' - - - key: readability-identifier-naming.PrivateMemberCase - value: 'lower_case' - - - key: readability-identifier-naming.PrivateMemberSuffix - value: '_' - - - key: readability-identifier-naming.StructCase - value: 'CamelCase' - - - key: readability-identifier-naming.TypeAliasCase - value: 'CamelCase' +- key: cppcoreguidelines-unused-variable.IgnorePattern + value: "^_$" +- key: bugprone-assert-side-effect.AssertMacros + value: 'ASSERT' +- key: bugprone-dangling-handle.HandleClasses + value: 'std::basic_string_view;std::experimental::basic_string_view;absl::string_view' +- key: modernize-use-auto.MinTypeNameLength + value: '10' +- key: readability-identifier-naming.ClassCase + value: 'CamelCase' +- key: readability-identifier-naming.EnumCase + value: 'CamelCase' +- key: readability-identifier-naming.EnumConstantCase + value: 'CamelCase' +# Ignore GoogleTest function macros. +- key: readability-identifier-naming.FunctionIgnoredRegexp + value: '(TEST|TEST_F|TEST_P|INSTANTIATE_TEST_SUITE_P|MOCK_METHOD|TYPED_TEST)' +- key: readability-identifier-naming.ParameterCase + value: 'lower_case' +- key: readability-identifier-naming.PrivateMemberCase + value: 'lower_case' +- key: readability-identifier-naming.PrivateMemberSuffix + value: '_' +- key: readability-identifier-naming.StructCase + value: 'CamelCase' +- key: readability-identifier-naming.TypeAliasCase + value: 'CamelCase' +- key: readability-identifier-naming.UnionCase + value: 'CamelCase' +- key: readability-identifier-naming.FunctionCase + value: 'camelBack' - - key: readability-identifier-naming.UnionCase - value: 'CamelCase' +UseColor: true - - key: readability-identifier-naming.FunctionCase - value: 'camelBack' +WarningsAsErrors: '*' diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index b0f71d3a0cb0..ae03bdd50ba1 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM gcr.io/envoy-ci/envoy-build:1f2f7ee78f894859de0fa7a415b0bedde1f6c560@sha256:9db54410ba9f8216cac84391ebcfb18a297c2217690c7c77bb050f78f56bb629 +FROM gcr.io/envoy-ci/envoy-build:56f235b141079013e64912d676fe7da981368402@sha256:6e3e8bd34ba568befa3f9c2fd067a1d82c1e55f0f597bcc5fddebbb644930761 ARG USERNAME=vscode ARG USER_UID=501 diff --git a/.github/dependabot.yml b/.github/dependabot.yml index a9462ca3b88d..8bd034f5b4dc 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -238,6 +238,12 @@ updates: interval: daily time: "06:00" +- package-ecosystem: "gomod" + directory: "/contrib/golang/filters/http/test/test_data/buffer" + schedule: + interval: daily + time: "06:00" + - package-ecosystem: "gomod" directory: "/contrib/golang/filters/http/test/test_data/routeconfig" schedule: diff --git a/.github/workflows/_env.yml b/.github/workflows/_env.yml index 5f61270583ae..3ec7f4082c7a 100644 --- a/.github/workflows/_env.yml +++ b/.github/workflows/_env.yml @@ -12,13 +12,13 @@ on: default: envoyproxy/envoy-build-ubuntu build_image_sha: type: string - default: 6a6a64be3f4e3c4380531ad1624f9419d1fe99dde4e5eeb04e2d538a92f27205 + default: d44499c6fd28a8a6a75dc61668b8a9e7bc3d99db11f9a61e8ea1d1f39c20a236 build_image_mobile_sha: type: string - default: 2c9852c10f133f780a96286230b7e07582e1c99fe204943d4fa66567f8b850f6 + default: b3cfc59c2fd1a86a2b12d303324f33d7f7248458233f3be2959fab119b11fa6f build_image_tag: type: string - default: 1f2f7ee78f894859de0fa7a415b0bedde1f6c560 + default: 56f235b141079013e64912d676fe7da981368402 check_mobile_run: type: boolean diff --git a/.github/workflows/mobile-release.yml b/.github/workflows/mobile-release.yml index 74ef2ee64691..effa6cd4192c 100644 --- a/.github/workflows/mobile-release.yml +++ b/.github/workflows/mobile-release.yml @@ -29,7 +29,7 @@ jobs: contents: read packages: read name: android_release_artifacts - runs-on: ubuntu-22.04 + runs-on: ${{ needs.env.outputs.agent_ubuntu }} timeout-minutes: 120 container: image: ${{ needs.env.outputs.build_image_ubuntu_mobile }} diff --git a/.yamllint b/.yamllint index 78788302cc6e..8a9e75677566 100644 --- a/.yamllint +++ b/.yamllint @@ -18,3 +18,8 @@ rules: - "false" # https://github.com/adrienverge/yamllint/issues/430 - "on" + +yaml-files: +- .clang-format +- "*.yml" +- "*.yaml" diff --git a/api/envoy/extensions/filters/http/ext_authz/v3/ext_authz.proto b/api/envoy/extensions/filters/http/ext_authz/v3/ext_authz.proto index cd2d1f6f4e21..b090b54b9c0c 100644 --- a/api/envoy/extensions/filters/http/ext_authz/v3/ext_authz.proto +++ b/api/envoy/extensions/filters/http/ext_authz/v3/ext_authz.proto @@ -78,6 +78,7 @@ message ExtAuthz { // 3. At least one ``authorization response header`` is added to the client request, or is used for // altering another client request header. // + // It is an error to set this field when the filter is configured on an upstream filter chain. bool clear_route_cache = 6; // Sets the HTTP status that is returned to the client when the authorization server returns an error @@ -135,6 +136,8 @@ message ExtAuthz { // // When this field is true, Envoy will include the peer X.509 certificate, if available, in the // :ref:`certificate`. + // + // It is an error to set this field when the filter is configured on an upstream filter chain. bool include_peer_certificate = 10; // Optional additional prefix to use when emitting statistics. This allows to distinguish @@ -184,6 +187,8 @@ message ExtAuthz { // // When this field is true, Envoy will include the SNI name used for TLSClientHello, if available, in the // :ref:`tls_session`. + // + // It is an error to set this field when the filter is configured on an upstream filter chain. bool include_tls_session = 18; } diff --git a/api/envoy/extensions/transport_sockets/tls/v3/common.proto b/api/envoy/extensions/transport_sockets/tls/v3/common.proto index a6fd01335af6..0d653050f5a3 100644 --- a/api/envoy/extensions/transport_sockets/tls/v3/common.proto +++ b/api/envoy/extensions/transport_sockets/tls/v3/common.proto @@ -179,7 +179,6 @@ message PrivateKeyProvider { google.protobuf.Any typed_config = 3 [(udpa.annotations.sensitive) = true]; } - // [#not-implemented-hide:] // If the private key provider isn't available (eg. the required hardware capability doesn't existed), // Envoy will fallback to the BoringSSL default implementation when the `fallback` is true. // The default value is `false`. diff --git a/api/envoy/extensions/transport_sockets/tls/v3/tls.proto b/api/envoy/extensions/transport_sockets/tls/v3/tls.proto index ac3641ebd6f5..f94889cfad04 100644 --- a/api/envoy/extensions/transport_sockets/tls/v3/tls.proto +++ b/api/envoy/extensions/transport_sockets/tls/v3/tls.proto @@ -63,7 +63,7 @@ message UpstreamTlsContext { google.protobuf.BoolValue enforce_rsa_key_usage = 5; } -// [#next-free-field: 10] +// [#next-free-field: 11] message DownstreamTlsContext { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.auth.DownstreamTlsContext"; @@ -119,6 +119,10 @@ message DownstreamTlsContext { bool disable_stateless_session_resumption = 7; } + // If set to true, the TLS server will not maintain a session cache of TLS sessions. (This is + // relevant only for TLSv1.2 and earlier.) + bool disable_stateful_session_resumption = 10; + // If specified, ``session_timeout`` will change the maximum lifetime (in seconds) of the TLS session. // Currently this value is used as a hint for the `TLS session ticket lifetime (for TLSv1.2) `_. // Only seconds can be specified (fractional seconds are ignored). diff --git a/bazel/repository_locations.bzl b/bazel/repository_locations.bzl index cc9833231494..0302660b40ed 100644 --- a/bazel/repository_locations.bzl +++ b/bazel/repository_locations.bzl @@ -102,11 +102,11 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_name = "envoy-build-tools", project_desc = "Common build tools shared by the Envoy/UDPA ecosystem", project_url = "https://github.com/envoyproxy/envoy-build-tools", - version = "b3e8ecd0f256b648a19d0f2146a966c2a6a0c0e7", - sha256 = "40ae52a50987feeef25510a37108aad621f4ba0ea7420d898cefd239ee56b178", + version = "633f57439ba683c1370fb8b1025680f1ce678caf", + sha256 = "88e4b7d12429d488daff522b765f0f21a3204d2c4b262b4b9d67587230415454", strip_prefix = "envoy-build-tools-{version}", urls = ["https://github.com/envoyproxy/envoy-build-tools/archive/{version}.tar.gz"], - release_date = "2023-09-03", + release_date = "2023-09-15", use_category = ["build"], license = "Apache-2.0", license_url = "https://github.com/envoyproxy/envoy-build-tools/blob/{version}/LICENSE", diff --git a/changelogs/current.yaml b/changelogs/current.yaml index bad6052057ae..acc84a3ff1c5 100644 --- a/changelogs/current.yaml +++ b/changelogs/current.yaml @@ -238,6 +238,11 @@ new_features: change: | added :ref:`custom_sink ` type to enable writing tap data out to a custom sink extension. +- area: tls + change: | + added :ref:`disable_stateful_session_resumption + ` config option to + disable stateful TLS session resumption. - area: udp_proxy change: | added :ref:`session_filters ` config to @@ -255,6 +260,14 @@ new_features: change: | added :ref:`record_headers_received_time ` to control writing request and response headers received time in trace output. +- area: tls + change: | + added fallback :ref:`fallback + ` + to support private key provider to fallback to boringssl tls handshake. + If the private key provider isn't available (eg. the required hardware capability doesn't existed), + Envoy will fallback to the BoringSSL default implementation when the fallback is true. + The default value is false. - area: tcp change: | added the support to detect and send TCP RST for raw buffer socket based connections. This is currently supported on Linux only. diff --git a/configs/proxy_connect.yaml b/configs/proxy_connect.yaml index 68e544971326..502671d88640 100644 --- a/configs/proxy_connect.yaml +++ b/configs/proxy_connect.yaml @@ -1,4 +1,4 @@ -# This will proxy CONNECT requests from a downstream connecting on 127.0.0.1:10001 +# This will forward CONNECT requests from a downstream connecting on 127.0.0.1:10001 # to an upstream listening on 127.0.0.1:10002 admin: address: diff --git a/configs/proxy_connect_udp_http3_downstream.yaml b/configs/proxy_connect_udp_http3_downstream.yaml new file mode 100644 index 000000000000..89ce62f156d9 --- /dev/null +++ b/configs/proxy_connect_udp_http3_downstream.yaml @@ -0,0 +1,68 @@ +# This will forward CONNECT-UDP requests from a downstream connecting on 127.0.0.1:10001 to an +# upstream listening on 127.0.0.1:10002. +static_resources: + listeners: + - name: listener_0 + address: + socket_address: + protocol: UDP + address: 127.0.0.1 + port_value: 10001 + udp_listener_config: + quic_options: {} + downstream_socket_config: + prefer_gro: true + filter_chains: + - transport_socket: + name: envoy.transport_sockets.quic + typed_config: + '@type': type.googleapis.com/envoy.extensions.transport_sockets.quic.v3.QuicDownstreamTransport + downstream_tls_context: + common_tls_context: + tls_certificates: + - certificate_chain: + filename: certs/servercert.pem + private_key: + filename: certs/serverkey.pem + filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + codec_type: HTTP3 + stat_prefix: ingress_http + route_config: + name: local_route + virtual_hosts: + - name: local_service + domains: + - "*" + routes: + - match: + connect_matcher: + {} + route: + cluster: cluster_0 + http_filters: + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + http2_protocol_options: + allow_connect: true + upgrade_configs: + - upgrade_type: CONNECT-UDP + clusters: + - name: cluster_0 + typed_extension_protocol_options: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicit_http_config: + http2_protocol_options: {} + load_assignment: + cluster_name: cluster_0 + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: 127.0.0.1 + port_value: 10002 diff --git a/configs/terminate_http3_connect_udp.yaml b/configs/terminate_http3_connect_udp.yaml new file mode 100644 index 000000000000..675df041e843 --- /dev/null +++ b/configs/terminate_http3_connect_udp.yaml @@ -0,0 +1,70 @@ +# This configuration terminates a CONNECT-UDP request and sends UDP payloads directly over UDP to the target. +static_resources: + listeners: + - name: listener_0 + address: + socket_address: + protocol: UDP + address: 127.0.0.1 + port_value: 10001 + udp_listener_config: + quic_options: {} + downstream_socket_config: + prefer_gro: true + filter_chains: + - transport_socket: + name: envoy.transport_sockets.quic + typed_config: + '@type': type.googleapis.com/envoy.extensions.transport_sockets.quic.v3.QuicDownstreamTransport + downstream_tls_context: + common_tls_context: + tls_certificates: + - certificate_chain: + filename: certs/servercert.pem + private_key: + filename: certs/serverkey.pem + filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + codec_type: HTTP3 + stat_prefix: ingress_http + route_config: + name: local_route + virtual_hosts: + - name: local_service + domains: + - "*" + routes: + - match: + connect_matcher: + {} + route: + cluster: service_google + upgrade_configs: + - upgrade_type: CONNECT-UDP + connect_config: + {} + http_filters: + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + http2_protocol_options: + allow_connect: true + upgrade_configs: + - upgrade_type: CONNECT-UDP + clusters: + - name: service_google + type: LOGICAL_DNS + # Comment out the following line to test on v6 networks + dns_lookup_family: V4_ONLY + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: service_google + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: www.google.com + port_value: 443 diff --git a/contrib/cryptomb/private_key_providers/source/cryptomb_private_key_provider.cc b/contrib/cryptomb/private_key_providers/source/cryptomb_private_key_provider.cc index f94f37db6323..82d1bd4a5a5c 100644 --- a/contrib/cryptomb/private_key_providers/source/cryptomb_private_key_provider.cc +++ b/contrib/cryptomb/private_key_providers/source/cryptomb_private_key_provider.cc @@ -499,6 +499,8 @@ bool CryptoMbPrivateKeyMethodProvider::checkFips() { return false; } +bool CryptoMbPrivateKeyMethodProvider::isAvailable() { return initialized_; } + Ssl::BoringSslPrivateKeyMethodSharedPtr CryptoMbPrivateKeyMethodProvider::getBoringSslPrivateKeyMethod() { return method_; @@ -522,7 +524,8 @@ CryptoMbPrivateKeyMethodProvider::CryptoMbPrivateKeyMethodProvider( stats_(generateCryptoMbStats("cryptomb", factory_context.statsScope())) { if (!ipp->mbxIsCryptoMbApplicable(0)) { - throw EnvoyException("Multi-buffer CPU instructions not available."); + ENVOY_LOG(warn, "Multi-buffer CPU instructions not available."); + return; } std::chrono::milliseconds poll_delay = @@ -565,7 +568,8 @@ CryptoMbPrivateKeyMethodProvider::CryptoMbPrivateKeyMethodProvider( key_size = 4096; break; default: - throw EnvoyException("Only RSA keys of 1024, 2048, 3072, and 4096 bits are supported."); + ENVOY_LOG(warn, "Only RSA keys of 1024, 2048, 3072, and 4096 bits are supported."); + return; } // If longer keys are ever supported, remember to change the signature buffer to be larger. @@ -619,6 +623,8 @@ CryptoMbPrivateKeyMethodProvider::CryptoMbPrivateKeyMethodProvider( ENVOY_LOG(debug, "Created CryptoMb Queue for thread {}", d.name()); return std::make_shared(poll_delay, key_type, key_size, ipp, d, stats_); }); + + initialized_ = true; } namespace { diff --git a/contrib/cryptomb/private_key_providers/source/cryptomb_private_key_provider.h b/contrib/cryptomb/private_key_providers/source/cryptomb_private_key_provider.h index 90d3efac06a7..cbd7a42d5366 100644 --- a/contrib/cryptomb/private_key_providers/source/cryptomb_private_key_provider.h +++ b/contrib/cryptomb/private_key_providers/source/cryptomb_private_key_provider.h @@ -166,6 +166,7 @@ class CryptoMbPrivateKeyMethodProvider : public virtual Ssl::PrivateKeyMethodPro Event::Dispatcher& dispatcher) override; void unregisterPrivateKeyMethod(SSL* ssl) override; bool checkFips() override; + bool isAvailable() override; Ssl::BoringSslPrivateKeyMethodSharedPtr getBoringSslPrivateKeyMethod() override; static int connectionIndex(); @@ -191,6 +192,8 @@ class CryptoMbPrivateKeyMethodProvider : public virtual Ssl::PrivateKeyMethodPro ThreadLocal::TypedSlotPtr tls_; CryptoMbStats stats_; + + bool initialized_{}; }; } // namespace CryptoMb diff --git a/contrib/cryptomb/private_key_providers/test/config_test.cc b/contrib/cryptomb/private_key_providers/test/config_test.cc index 158936f49037..0ac6ce5ff3aa 100644 --- a/contrib/cryptomb/private_key_providers/test/config_test.cc +++ b/contrib/cryptomb/private_key_providers/test/config_test.cc @@ -74,6 +74,7 @@ TEST_F(CryptoMbConfigTest, CreateRsa1024) { Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml); EXPECT_NE(nullptr, provider); EXPECT_EQ(false, provider->checkFips()); + EXPECT_EQ(provider->isAvailable(), true); Ssl::BoringSslPrivateKeyMethodSharedPtr method = provider->getBoringSslPrivateKeyMethod(); EXPECT_NE(nullptr, method); @@ -96,7 +97,9 @@ TEST_F(CryptoMbConfigTest, CreateRsa2048) { private_key: { "filename": "{{ test_rundir }}/contrib/cryptomb/private_key_providers/test/test_data/rsa-2048.pem" } )EOF"; - EXPECT_NE(nullptr, createWithConfig(yaml)); + Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml); + EXPECT_NE(nullptr, provider); + EXPECT_EQ(provider->isAvailable(), true); } TEST_F(CryptoMbConfigTest, CreateRsa2048WithExponent3) { @@ -146,8 +149,9 @@ TEST_F(CryptoMbConfigTest, CreateRsa512) { private_key: { "filename": "{{ test_rundir }}/contrib/cryptomb/private_key_providers/test/test_data/rsa-512.pem" } )EOF"; - EXPECT_THROW_WITH_MESSAGE(createWithConfig(yaml), EnvoyException, - "Only RSA keys of 1024, 2048, 3072, and 4096 bits are supported."); + Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml); + EXPECT_NE(nullptr, provider); + EXPECT_EQ(provider->isAvailable(), false); } TEST_F(CryptoMbConfigTest, CreateEcdsaP256) { @@ -266,6 +270,7 @@ TEST_F(CryptoMbConfigTest, CreateOneMillisecondPollDelay) { Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml); EXPECT_NE(nullptr, provider); + EXPECT_EQ(provider->isAvailable(), true); CryptoMbPrivateKeyMethodProvider* cryptomb_provider = dynamic_cast(provider.get()); EXPECT_EQ(cryptomb_provider->getPollDelayForTest(), std::chrono::microseconds(1000)); @@ -282,6 +287,7 @@ TEST_F(CryptoMbConfigTest, CreateTwoMillisecondPollDelay) { Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml); EXPECT_NE(nullptr, provider); + EXPECT_EQ(provider->isAvailable(), true); CryptoMbPrivateKeyMethodProvider* cryptomb_provider = dynamic_cast(provider.get()); EXPECT_EQ(cryptomb_provider->getPollDelayForTest(), std::chrono::microseconds(2000)); @@ -309,8 +315,8 @@ TEST_F(CryptoMbConfigTest, CreateNotSupportedInstructionSet) { poll_delay: 0.02s )EOF"; - EXPECT_THROW_WITH_MESSAGE(createWithConfig(yaml, false), EnvoyException, - "Multi-buffer CPU instructions not available."); + Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml, false); + EXPECT_EQ(provider->isAvailable(), false); } } // namespace CryptoMb diff --git a/contrib/golang/common/go/api/api.h b/contrib/golang/common/go/api/api.h index 312916ad0528..71469e999f5f 100644 --- a/contrib/golang/common/go/api/api.h +++ b/contrib/golang/common/go/api/api.h @@ -62,6 +62,7 @@ CAPIStatus envoyGoFilterHttpSetHeaderHelper(void* r, void* key, void* value, hea CAPIStatus envoyGoFilterHttpRemoveHeader(void* r, void* key); CAPIStatus envoyGoFilterHttpGetBuffer(void* r, unsigned long long int buffer, void* value); +CAPIStatus envoyGoFilterHttpDrainBuffer(void* r, unsigned long long int buffer, uint64_t length); CAPIStatus envoyGoFilterHttpSetBufferHelper(void* r, unsigned long long int buffer, void* data, int length, bufferAction action); diff --git a/contrib/golang/common/go/api/capi.go b/contrib/golang/common/go/api/capi.go index 6bd99ea0294e..e97c4908fdd7 100644 --- a/contrib/golang/common/go/api/capi.go +++ b/contrib/golang/common/go/api/capi.go @@ -33,6 +33,7 @@ type HttpCAPI interface { HttpRemoveHeader(r unsafe.Pointer, key *string) HttpGetBuffer(r unsafe.Pointer, bufferPtr uint64, value *string, length uint64) + HttpDrainBuffer(r unsafe.Pointer, bufferPtr uint64, length uint64) HttpSetBufferHelper(r unsafe.Pointer, bufferPtr uint64, value string, action BufferAction) HttpCopyTrailers(r unsafe.Pointer, num uint64, bytes uint64) map[string][]string diff --git a/contrib/golang/common/go/api/type.go b/contrib/golang/common/go/api/type.go index 522f8166000a..9f9e4f869646 100644 --- a/contrib/golang/common/go/api/type.go +++ b/contrib/golang/common/go/api/type.go @@ -200,12 +200,6 @@ type DataBufferBase interface { // buffer becomes too large, Write will panic with ErrTooLarge. WriteUint64(p uint64) error - // Peek returns n bytes from buffer, without draining any buffered data. - // If n > readable buffer, nil will be returned. - // It can be used in codec to check first-n-bytes magic bytes - // Note: do not change content in return bytes, use write instead - Peek(n int) []byte - // Bytes returns all bytes from buffer, without draining any buffered data. // It can be used to get fixed-length content, such as headers, body. // Note: do not change content in return bytes, use write instead diff --git a/contrib/golang/filters/http/source/cgo.cc b/contrib/golang/filters/http/source/cgo.cc index e4035beed84f..4be18d0ba19f 100644 --- a/contrib/golang/filters/http/source/cgo.cc +++ b/contrib/golang/filters/http/source/cgo.cc @@ -158,6 +158,15 @@ CAPIStatus envoyGoFilterHttpGetBuffer(void* r, unsigned long long int buffer_ptr }); } +CAPIStatus envoyGoFilterHttpDrainBuffer(void* r, unsigned long long int buffer_ptr, + uint64_t length) { + return envoyGoFilterHandlerWrapper( + r, [buffer_ptr, length](std::shared_ptr& filter) -> CAPIStatus { + auto buffer = reinterpret_cast(buffer_ptr); + return filter->drainBuffer(buffer, length); + }); +} + CAPIStatus envoyGoFilterHttpSetBufferHelper(void* r, unsigned long long int buffer_ptr, void* data, int length, bufferAction action) { return envoyGoFilterHandlerWrapper( diff --git a/contrib/golang/filters/http/source/go/pkg/http/capi_impl.go b/contrib/golang/filters/http/source/go/pkg/http/capi_impl.go index 8cecb683c5e8..ec1d7d6f55ac 100644 --- a/contrib/golang/filters/http/source/go/pkg/http/capi_impl.go +++ b/contrib/golang/filters/http/source/go/pkg/http/capi_impl.go @@ -193,6 +193,11 @@ func (c *httpCApiImpl) HttpGetBuffer(r unsafe.Pointer, bufferPtr uint64, value * handleCApiStatus(res) } +func (c *httpCApiImpl) HttpDrainBuffer(r unsafe.Pointer, bufferPtr uint64, length uint64) { + res := C.envoyGoFilterHttpDrainBuffer(r, C.ulonglong(bufferPtr), C.uint64_t(length)) + handleCApiStatus(res) +} + func (c *httpCApiImpl) HttpSetBufferHelper(r unsafe.Pointer, bufferPtr uint64, value string, action api.BufferAction) { sHeader := (*reflect.StringHeader)(unsafe.Pointer(&value)) var act C.bufferAction diff --git a/contrib/golang/filters/http/source/go/pkg/http/type.go b/contrib/golang/filters/http/source/go/pkg/http/type.go index d433f579ddb6..e296e059cb77 100644 --- a/contrib/golang/filters/http/source/go/pkg/http/type.go +++ b/contrib/golang/filters/http/source/go/pkg/http/type.go @@ -369,10 +369,6 @@ func (b *httpBuffer) WriteUint64(p uint64) error { return err } -func (b *httpBuffer) Peek(n int) []byte { - panic("implement me") -} - func (b *httpBuffer) Bytes() []byte { if b.length == 0 { return nil @@ -382,7 +378,18 @@ func (b *httpBuffer) Bytes() []byte { } func (b *httpBuffer) Drain(offset int) { - panic("implement me") + if offset <= 0 || b.length == 0 { + return + } + + size := uint64(offset) + if size > b.length { + size = b.length + } + + cAPI.HttpDrainBuffer(unsafe.Pointer(b.request.req), b.envoyBufferInstance, size) + + b.length -= size } func (b *httpBuffer) Len() int { @@ -390,7 +397,7 @@ func (b *httpBuffer) Len() int { } func (b *httpBuffer) Reset() { - panic("implement me") + b.Drain(b.Len()) } func (b *httpBuffer) String() string { diff --git a/contrib/golang/filters/http/source/golang_filter.cc b/contrib/golang/filters/http/source/golang_filter.cc index 2e26e762fcdc..31f58f45560c 100644 --- a/contrib/golang/filters/http/source/golang_filter.cc +++ b/contrib/golang/filters/http/source/golang_filter.cc @@ -807,6 +807,27 @@ CAPIStatus Filter::copyBuffer(Buffer::Instance* buffer, char* data) { return CAPIStatus::CAPIOK; } +CAPIStatus Filter::drainBuffer(Buffer::Instance* buffer, uint64_t length) { + // lock until this function return since it may running in a Go thread. + Thread::LockGuard lock(mutex_); + if (has_destroyed_) { + ENVOY_LOG(debug, "golang filter has been destroyed"); + return CAPIStatus::CAPIFilterIsDestroy; + } + auto& state = getProcessorState(); + if (!state.isProcessingInGo()) { + ENVOY_LOG(debug, "golang filter is not processing Go"); + return CAPIStatus::CAPINotInGo; + } + if (!state.doDataList.checkExisting(buffer)) { + ENVOY_LOG(debug, "invoking cgo api at invalid phase: {}", __func__); + return CAPIStatus::CAPIInvalidPhase; + } + + buffer->drain(length); + return CAPIStatus::CAPIOK; +} + CAPIStatus Filter::setBufferHelper(Buffer::Instance* buffer, absl::string_view& value, bufferAction action) { // lock until this function return since it may running in a Go thread. diff --git a/contrib/golang/filters/http/source/golang_filter.h b/contrib/golang/filters/http/source/golang_filter.h index 7c40320d995d..1d2485e4aabf 100644 --- a/contrib/golang/filters/http/source/golang_filter.h +++ b/contrib/golang/filters/http/source/golang_filter.h @@ -225,6 +225,7 @@ class Filter : public Http::StreamFilter, CAPIStatus setHeader(absl::string_view key, absl::string_view value, headerAction act); CAPIStatus removeHeader(absl::string_view key); CAPIStatus copyBuffer(Buffer::Instance* buffer, char* data); + CAPIStatus drainBuffer(Buffer::Instance* buffer, uint64_t length); CAPIStatus setBufferHelper(Buffer::Instance* buffer, absl::string_view& value, bufferAction action); CAPIStatus copyTrailers(GoString* go_strs, char* go_buf); diff --git a/contrib/golang/filters/http/test/BUILD b/contrib/golang/filters/http/test/BUILD index 7c6519b150cd..eefe0c5c64d3 100644 --- a/contrib/golang/filters/http/test/BUILD +++ b/contrib/golang/filters/http/test/BUILD @@ -54,6 +54,7 @@ envoy_cc_test( data = [ "//contrib/golang/filters/http/test/test_data/access_log:filter.so", "//contrib/golang/filters/http/test/test_data/basic:filter.so", + "//contrib/golang/filters/http/test/test_data/buffer:filter.so", "//contrib/golang/filters/http/test/test_data/echo:filter.so", "//contrib/golang/filters/http/test/test_data/metric:filter.so", "//contrib/golang/filters/http/test/test_data/passthrough:filter.so", diff --git a/contrib/golang/filters/http/test/golang_integration_test.cc b/contrib/golang/filters/http/test/golang_integration_test.cc index 0606d9a995dd..efd8b3466715 100644 --- a/contrib/golang/filters/http/test/golang_integration_test.cc +++ b/contrib/golang/filters/http/test/golang_integration_test.cc @@ -662,9 +662,43 @@ name: golang cleanup(); } + void testBufferApi(std::string query) { + initializeBasicFilter(BUFFER, "test.com"); + + auto path = std::string("/test?") + query; + codec_client_ = makeHttpConnection(makeClientConnection(lookupPort("http"))); + Http::TestRequestHeaderMapImpl request_headers{ + {":method", "POST"}, + {":path", path}, + {":scheme", "http"}, + {":authority", "test.com"}, + }; + + auto encoder_decoder = codec_client_->startRequest(request_headers); + Http::RequestEncoder& request_encoder = encoder_decoder.first; + auto response = std::move(encoder_decoder.second); + std::string data = ""; + for (int i = 0; i < 10; i++) { + data += "12345"; + } + codec_client_->sendData(request_encoder, data, true); + + waitForNextUpstreamRequest(); + + Http::TestResponseHeaderMapImpl response_headers{{":status", "200"}}; + upstream_request_->encodeHeaders(response_headers, false); + Buffer::OwnedImpl response_data("goodbye"); + upstream_request_->encodeData(response_data, true); + + ASSERT_TRUE(response->waitForEndStream()); + EXPECT_EQ("200", response->headers().getStatusValue()); + cleanup(); + } + const std::string ECHO{"echo"}; const std::string BASIC{"basic"}; const std::string PASSTHROUGH{"passthrough"}; + const std::string BUFFER{"buffer"}; const std::string ROUTECONFIG{"routeconfig"}; const std::string PROPERTY{"property"}; const std::string ACCESSLOG{"access_log"}; @@ -754,6 +788,12 @@ TEST_P(GolangIntegrationTest, PluginNotFound) { cleanup(); } +TEST_P(GolangIntegrationTest, BufferDrain) { testBufferApi("Drain"); } + +TEST_P(GolangIntegrationTest, BufferReset) { testBufferApi("Reset"); } + +TEST_P(GolangIntegrationTest, BufferResetAfterDrain) { testBufferApi("ResetAfterDrain"); } + TEST_P(GolangIntegrationTest, Property) { initializePropertyConfig(PROPERTY, genSoPath(PROPERTY), PROPERTY); initialize(); @@ -857,6 +897,7 @@ TEST_P(GolangIntegrationTest, AccessLogDownstreamStart) { EXPECT_TRUE(response->complete()); EXPECT_EQ("r;r2", getHeader(upstream_request_->headers(), "referers")); + EXPECT_EQ("true", getHeader(upstream_request_->headers(), "canRunAsynclyForDownstreamStart")); cleanup(); } @@ -887,6 +928,7 @@ TEST_P(GolangIntegrationTest, AccessLogDownstreamPeriodic) { EXPECT_TRUE(response->complete()); EXPECT_EQ("r", getHeader(upstream_request_->headers(), "referers")); + EXPECT_EQ("true", getHeader(upstream_request_->headers(), "canRunAsynclyForDownstreamPeriodic")); cleanup(); } diff --git a/contrib/golang/filters/http/test/test_data/access_log/filter.go b/contrib/golang/filters/http/test/test_data/access_log/filter.go index 7d5fa51aa267..750e19215b87 100644 --- a/contrib/golang/filters/http/test/test_data/access_log/filter.go +++ b/contrib/golang/filters/http/test/test_data/access_log/filter.go @@ -17,6 +17,10 @@ var ( respSize string canRunAsyncly bool + canRunAsynclyForDownstreamStart bool + + canRunAsynclyForDownstreamPeriodic bool + referers = []string{} ) @@ -47,6 +51,8 @@ func (f *filter) DecodeHeaders(header api.RequestHeaderMap, endStream bool) api. header.Set("respCode", respCode) header.Set("respSize", respSize) header.Set("canRunAsyncly", strconv.FormatBool(canRunAsyncly)) + header.Set("canRunAsynclyForDownstreamStart", strconv.FormatBool(canRunAsynclyForDownstreamStart)) + header.Set("canRunAsynclyForDownstreamPeriodic", strconv.FormatBool(canRunAsynclyForDownstreamPeriodic)) header.Set("referers", strings.Join(referers, ";")) @@ -68,6 +74,13 @@ func (f *filter) OnLogDownstreamStart() { } referers = append(referers, referer) + + wg.Add(1) + go func() { + time.Sleep(1 * time.Millisecond) + canRunAsynclyForDownstreamStart = true + wg.Done() + }() } func (f *filter) OnLogDownstreamPeriodic() { @@ -78,6 +91,13 @@ func (f *filter) OnLogDownstreamPeriodic() { } referers = append(referers, referer) + + wg.Add(1) + go func() { + time.Sleep(1 * time.Millisecond) + canRunAsynclyForDownstreamPeriodic = true + wg.Done() + }() } func (f *filter) OnLog() { diff --git a/contrib/golang/filters/http/test/test_data/buffer/BUILD b/contrib/golang/filters/http/test/test_data/buffer/BUILD new file mode 100644 index 000000000000..c072c6e72f57 --- /dev/null +++ b/contrib/golang/filters/http/test/test_data/buffer/BUILD @@ -0,0 +1,23 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_binary") + +licenses(["notice"]) # Apache 2 + +go_binary( + name = "filter.so", + srcs = [ + "config.go", + "filter.go", + ], + out = "filter.so", + cgo = True, + importpath = "github.com/envoyproxy/envoy/contrib/golang/filters/http/test/test_data/buffer", + linkmode = "c-shared", + visibility = ["//visibility:public"], + deps = [ + "//contrib/golang/common/go/api", + "//contrib/golang/filters/http/source/go/pkg/http", + "@com_github_cncf_xds_go//xds/type/v3:type", + "@org_golang_google_protobuf//types/known/anypb", + "@org_golang_google_protobuf//types/known/structpb", + ], +) diff --git a/contrib/golang/filters/http/test/test_data/buffer/config.go b/contrib/golang/filters/http/test/test_data/buffer/config.go new file mode 100644 index 000000000000..cb88f346652b --- /dev/null +++ b/contrib/golang/filters/http/test/test_data/buffer/config.go @@ -0,0 +1,44 @@ +package main + +import ( + "google.golang.org/protobuf/types/known/anypb" + + "github.com/envoyproxy/envoy/contrib/golang/common/go/api" + "github.com/envoyproxy/envoy/contrib/golang/filters/http/source/go/pkg/http" +) + +const Name = "buffer" + +func init() { + http.RegisterHttpFilterConfigFactoryAndParser(Name, ConfigFactory, &parser{}) +} + +type config struct { +} + +type parser struct { +} + +func (p *parser) Parse(any *anypb.Any, callbacks api.ConfigCallbackHandler) (interface{}, error) { + conf := &config{} + return conf, nil +} + +func (p *parser) Merge(parent interface{}, child interface{}) interface{} { + return child +} + +func ConfigFactory(c interface{}) api.StreamFilterFactory { + conf, ok := c.(*config) + if !ok { + panic("unexpected config type") + } + return func(callbacks api.FilterCallbackHandler) api.StreamFilter { + return &filter{ + callbacks: callbacks, + config: conf, + } + } +} + +func main() {} diff --git a/contrib/golang/filters/http/test/test_data/buffer/filter.go b/contrib/golang/filters/http/test/test_data/buffer/filter.go new file mode 100644 index 000000000000..3af04cdf4d40 --- /dev/null +++ b/contrib/golang/filters/http/test/test_data/buffer/filter.go @@ -0,0 +1,87 @@ +package main + +import ( + "fmt" + + "github.com/envoyproxy/envoy/contrib/golang/common/go/api" +) + +type filter struct { + api.PassThroughStreamFilter + + callbacks api.FilterCallbackHandler + path string + config *config + + failed bool +} + +func testReset(b api.BufferInstance) { + b.Reset() + + bs := b.Bytes() + if len(bs) > 0 { + panic(fmt.Sprintf("unexpected data: %s", string(bs))) + } +} + +func testDrain(b api.BufferInstance) { + b.Drain(40) + bs := b.Bytes() + if string(bs) != "1234512345" { + panic(fmt.Sprintf("unexpected data: %s", string(bs))) + } + + b.Drain(5) + bs = b.Bytes() + if string(bs) != "12345" { + panic(fmt.Sprintf("unexpected data: %s", string(bs))) + } + + b.Drain(10) + bs = b.Bytes() + if string(bs) != "" { + panic(fmt.Sprintf("unexpected data: %s", string(bs))) + } + + // drain when all data are drained + b.Drain(10) + bs = b.Bytes() + if string(bs) != "" { + panic(fmt.Sprintf("unexpected data: %s", string(bs))) + } + + // bad offset + for _, n := range []int{-1, 0} { + b.Drain(n) + } +} + +func testResetAfterDrain(b api.BufferInstance) { + b.Drain(40) + b.Reset() + bs := b.Bytes() + if string(bs) != "" { + panic(fmt.Sprintf("unexpected data: %s", string(bs))) + } +} + +func (f *filter) DecodeData(buffer api.BufferInstance, endStream bool) api.StatusType { + if endStream { + return api.Continue + } + // run once + + query, _ := f.callbacks.GetProperty("request.query") + switch query { + case "Reset": + testReset(buffer) + case "ResetAfterDrain": + testResetAfterDrain(buffer) + case "Drain": + testDrain(buffer) + default: + panic(fmt.Sprintf("unknown case %s", query)) + } + return api.Continue +} diff --git a/contrib/golang/filters/http/test/test_data/buffer/go.mod b/contrib/golang/filters/http/test/test_data/buffer/go.mod new file mode 100644 index 000000000000..2110471b7b0f --- /dev/null +++ b/contrib/golang/filters/http/test/test_data/buffer/go.mod @@ -0,0 +1,10 @@ +module example.com/buffer + +go 1.18 + +require ( + github.com/envoyproxy/envoy v1.24.0 + google.golang.org/protobuf v1.31.0 +) + +replace github.com/envoyproxy/envoy => ../../../../../../../ diff --git a/contrib/qat/private_key_providers/source/qat.cc b/contrib/qat/private_key_providers/source/qat.cc index 7acb4cbdcdf2..595ad63fe1ad 100644 --- a/contrib/qat/private_key_providers/source/qat.cc +++ b/contrib/qat/private_key_providers/source/qat.cc @@ -17,7 +17,8 @@ QatManager::QatManager(LibQatCryptoSharedPtr libqat) { libqat_ = libqat; CpaStatus status = libqat_->icpSalUserStart("SSL"); if (status != CPA_STATUS_SUCCESS) { - throw EnvoyException("Failed to start QAT device."); + ENVOY_LOG(warn, "Failed to start QAT device."); + qat_is_supported_ = false; } } @@ -64,6 +65,8 @@ int QatManager::connectionIndex() { CONSTRUCT_ON_FIRST_USE(int, createIndex()); int QatManager::contextIndex() { CONSTRUCT_ON_FIRST_USE(int, createIndex()); } +bool QatManager::checkQatDevice() { return qat_is_supported_; } + QatHandle::~QatHandle() { if (polling_thread_ == nullptr) { return; diff --git a/contrib/qat/private_key_providers/source/qat.h b/contrib/qat/private_key_providers/source/qat.h index 617b39aedef6..038e75010888 100644 --- a/contrib/qat/private_key_providers/source/qat.h +++ b/contrib/qat/private_key_providers/source/qat.h @@ -93,8 +93,11 @@ class QatManager : public std::enable_shared_from_this, static int connectionIndex(); static int contextIndex(); + bool checkQatDevice(); + private: LibQatCryptoSharedPtr libqat_{}; + bool qat_is_supported_{true}; }; /** diff --git a/contrib/qat/private_key_providers/source/qat_private_key_provider.cc b/contrib/qat/private_key_providers/source/qat_private_key_provider.cc index 863637604157..b6a4b0b51658 100644 --- a/contrib/qat/private_key_providers/source/qat_private_key_provider.cc +++ b/contrib/qat/private_key_providers/source/qat_private_key_provider.cc @@ -310,6 +310,7 @@ QatPrivateKeyMethodProvider::getBoringSslPrivateKeyMethod() { } bool QatPrivateKeyMethodProvider::checkFips() { return false; } +bool QatPrivateKeyMethodProvider::isAvailable() { return initialized_; } QatPrivateKeyConnection::QatPrivateKeyConnection(Ssl::PrivateKeyConnectionCallbacks& cb, Event::Dispatcher& dispatcher, QatHandle& handle, @@ -355,6 +356,10 @@ QatPrivateKeyMethodProvider::QatPrivateKeyMethodProvider( ASSERT(manager_); + if (!manager_->checkQatDevice()) { + return; + } + std::chrono::milliseconds poll_delay = std::chrono::milliseconds(PROTOBUF_GET_MS_OR_DEFAULT(conf, poll_delay, 5)); @@ -370,13 +375,15 @@ QatPrivateKeyMethodProvider::QatPrivateKeyMethodProvider( if (EVP_PKEY_id(pkey.get()) != EVP_PKEY_RSA) { // TODO(ipuustin): add support also to ECDSA keys. - throw EnvoyException("Only RSA keys are supported."); + ENVOY_LOG(warn, "Only RSA keys are supported."); + return; } pkey_ = std::move(pkey); section_ = std::make_shared(libqat); if (!section_->startSection(api_, poll_delay)) { - throw EnvoyException("Failed to start QAT."); + ENVOY_LOG(warn, "Failed to start QAT."); + return; } method_ = std::make_shared(); @@ -384,6 +391,7 @@ QatPrivateKeyMethodProvider::QatPrivateKeyMethodProvider( method_->decrypt = privateKeyDecrypt; method_->complete = privateKeyComplete; + initialized_ = true; ENVOY_LOG(info, "initialized QAT private key provider"); } diff --git a/contrib/qat/private_key_providers/source/qat_private_key_provider.h b/contrib/qat/private_key_providers/source/qat_private_key_provider.h index bfaf4ac2d715..7636430233c9 100644 --- a/contrib/qat/private_key_providers/source/qat_private_key_provider.h +++ b/contrib/qat/private_key_providers/source/qat_private_key_provider.h @@ -47,6 +47,7 @@ class QatPrivateKeyMethodProvider : public virtual Ssl::PrivateKeyMethodProvider Event::Dispatcher& dispatcher) override; void unregisterPrivateKeyMethod(SSL* ssl) override; bool checkFips() override; + bool isAvailable() override; Ssl::BoringSslPrivateKeyMethodSharedPtr getBoringSslPrivateKeyMethod() override; private: @@ -56,6 +57,7 @@ class QatPrivateKeyMethodProvider : public virtual Ssl::PrivateKeyMethodProvider Api::Api& api_; bssl::UniquePtr pkey_; LibQatCryptoSharedPtr libqat_{}; + bool initialized_{}; }; } // namespace Qat diff --git a/contrib/qat/private_key_providers/test/config_test.cc b/contrib/qat/private_key_providers/test/config_test.cc index 518c9ba22d6a..9cbbafada6fe 100644 --- a/contrib/qat/private_key_providers/test/config_test.cc +++ b/contrib/qat/private_key_providers/test/config_test.cc @@ -87,6 +87,7 @@ TEST_F(QatConfigTest, CreateRsa1024) { Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml); EXPECT_NE(nullptr, provider); EXPECT_EQ(false, provider->checkFips()); + EXPECT_EQ(provider->isAvailable(), true); Ssl::BoringSslPrivateKeyMethodSharedPtr method = provider->getBoringSslPrivateKeyMethod(); EXPECT_NE(nullptr, method); } @@ -100,7 +101,9 @@ TEST_F(QatConfigTest, CreateRsa2048) { private_key: { "filename": "{{ test_rundir }}/contrib/qat/private_key_providers/test/test_data/rsa-2048.pem" } )EOF"; - EXPECT_NE(nullptr, createWithConfig(yaml)); + Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml); + EXPECT_NE(nullptr, provider); + EXPECT_EQ(provider->isAvailable(), true); } TEST_F(QatConfigTest, CreateRsa3072) { @@ -112,7 +115,9 @@ TEST_F(QatConfigTest, CreateRsa3072) { private_key: { "filename": "{{ test_rundir }}/contrib/qat/private_key_providers/test/test_data/rsa-3072.pem" } )EOF"; - EXPECT_NE(nullptr, createWithConfig(yaml)); + Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml); + EXPECT_NE(nullptr, provider); + EXPECT_EQ(provider->isAvailable(), true); } TEST_F(QatConfigTest, CreateRsa4096) { @@ -124,7 +129,9 @@ TEST_F(QatConfigTest, CreateRsa4096) { private_key: { "filename": "{{ test_rundir }}/contrib/qat/private_key_providers/test/test_data/rsa-4096.pem" } )EOF"; - EXPECT_NE(nullptr, createWithConfig(yaml)); + Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml); + EXPECT_NE(nullptr, provider); + EXPECT_EQ(provider->isAvailable(), true); } TEST_F(QatConfigTest, CreateEcdsaP256) { @@ -136,7 +143,9 @@ TEST_F(QatConfigTest, CreateEcdsaP256) { private_key: { "filename": "{{ test_rundir }}/contrib/qat/private_key_providers/test/test_data/ecdsa-p256.pem" } )EOF"; - EXPECT_THROW_WITH_MESSAGE(createWithConfig(yaml), EnvoyException, "Only RSA keys are supported."); + Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml); + EXPECT_NE(nullptr, provider); + EXPECT_EQ(provider->isAvailable(), false); } TEST_F(QatConfigTest, CreateMissingPrivateKeyFile) { diff --git a/contrib/qat/private_key_providers/test/ops_test.cc b/contrib/qat/private_key_providers/test/ops_test.cc index 68922f08bfef..3f61f68c6367 100644 --- a/contrib/qat/private_key_providers/test/ops_test.cc +++ b/contrib/qat/private_key_providers/test/ops_test.cc @@ -241,9 +241,9 @@ TEST_F(QatProviderRsaTest, TestQatDeviceInit) { // no device found libqat_->icpSalUserStart_return_value_ = CPA_STATUS_FAIL; - EXPECT_THROW_WITH_REGEX( - std::make_shared(conf, factory_context_, libqat_), - EnvoyException, "Failed to start QAT device."); + Ssl::PrivateKeyMethodProviderSharedPtr provider = + std::make_shared(conf, factory_context_, libqat_); + EXPECT_EQ(provider->isAvailable(), false); delete private_key; } diff --git a/docs/root/intro/arch_overview/http/upgrades.rst b/docs/root/intro/arch_overview/http/upgrades.rst index f32bfe9e919f..3e06357f9f93 100644 --- a/docs/root/intro/arch_overview/http/upgrades.rst +++ b/docs/root/intro/arch_overview/http/upgrades.rst @@ -62,7 +62,7 @@ a deployment of the form: In this case, if a client is for example using WebSocket, we want the Websocket to arrive at the upstream server functionally intact, which means it needs to traverse the HTTP/2+ hop. -This is accomplished for HTTP/2 via `Extended CONNECT (RFC8441) `_ support, +This is accomplished for HTTP/2 via `Extended CONNECT (RFC 8441) `_ support, turned on by setting :ref:`allow_connect ` to ``true`` at the second layer Envoy. @@ -137,6 +137,51 @@ will synthesize 200 response headers, and then forward the TCP data as the HTTP "upstream" TLS loopback connection to encrypt it, then have a TCP listener take the encrypted payload and send the ``CONNECT`` upstream. +``CONNECT-UDP`` support +^^^^^^^^^^^^^^^^^^^^^^^ +.. note:: + ``CONNECT-UDP`` is in an alpha status and may not be stable enough for use in production. + We recommend to use this feature with caution. + +``CONNECT-UDP`` (`RFC 9298 `_) allows HTTP clients +to create UDP tunnels through an HTTP proxy server. Unlike ``CONNECT``, which is limited to +tunneling TCP, ``CONNECT-UDP`` can be used to proxy UDP-based protocols such as HTTP/3. + +``CONNECT-UDP`` support is disabled by default in Envoy. Similar to ``CONNECT``, it can be enabled +through the :ref:`upgrade_configs ` +by setting the value to the special keyword ``CONNECT-UDP``. Like ``CONNECT``, ``CONNECT-UDP`` requests +are forwarded to the upstream by default. +:ref:`connect_config ` +must be set to terminate the requests and forward the payload as UDP datagrams to the target. + +Example Configuration +--------------------- + +The following example configuration makes Envoy forward ``CONNECT-UDP`` requests to the upstream. Note +that the :ref:`upgrade_configs ` +is set to ``CONNECT-UDP``. + +.. literalinclude:: /_configs/repo/proxy_connect_udp_http3_downstream.yaml + :language: yaml + :linenos: + :lines: 27-54 + :lineno-start: 27 + :emphasize-lines: 15-16, 25-26 + :caption: :download:`proxy_connect_udp_http3_downstream.yaml ` + +The following example configuration makes Envoy terminate ``CONNECT-UDP`` requests and send UDP payloads +to the target. As in this example, the +:ref:`connect_config ` +must be set to terminate ``CONNECT-UDP`` requests. + +.. literalinclude:: /_configs/repo/terminate_http3_connect_udp.yaml + :language: yaml + :linenos: + :lines: 26-57 + :lineno-start: 26 + :emphasize-lines: 15-16, 19-22, 29-30 + :caption: :download:`terminate_http3_connect_udp.yaml ` + .. _tunneling-tcp-over-http: Tunneling TCP over HTTP diff --git a/envoy/server/factory_context.h b/envoy/server/factory_context.h index e665289120d1..ad7a50216af5 100644 --- a/envoy/server/factory_context.h +++ b/envoy/server/factory_context.h @@ -153,6 +153,11 @@ class ServerFactoryContext : public virtual CommonFactoryContext { public: ~ServerFactoryContext() override = default; + /** + * @return the server-wide http context. + */ + virtual Http::Context& httpContext() PURE; + /** * @return the server-wide grpc context. */ diff --git a/envoy/ssl/context_config.h b/envoy/ssl/context_config.h index 68baffc37c7f..596c70df2fea 100644 --- a/envoy/ssl/context_config.h +++ b/envoy/ssl/context_config.h @@ -189,6 +189,11 @@ class ServerContextConfig : public virtual ContextConfig { */ virtual bool disableStatelessSessionResumption() const PURE; + /** + * @return True if stateful TLS session resumption is disabled, false otherwise. + */ + virtual bool disableStatefulSessionResumption() const PURE; + /** * @return True if we allow full scan certificates when there is no cert matching SNI during * downstream TLS handshake, false otherwise. diff --git a/envoy/ssl/private_key/private_key.h b/envoy/ssl/private_key/private_key.h index b1048a09c6f5..861df49516af 100644 --- a/envoy/ssl/private_key/private_key.h +++ b/envoy/ssl/private_key/private_key.h @@ -51,6 +51,12 @@ class PrivateKeyMethodProvider { */ virtual bool checkFips() PURE; + /** + * Check whether the private key method is available. + * @return true if the private key method is available, false if not. + */ + virtual bool isAvailable() PURE; + #ifdef OPENSSL_IS_BORINGSSL /** * Get the private key methods from the provider. diff --git a/examples/ext_authz/auth/grpc-service/go.mod b/examples/ext_authz/auth/grpc-service/go.mod index 284b942a03f2..813dc3437945 100644 --- a/examples/ext_authz/auth/grpc-service/go.mod +++ b/examples/ext_authz/auth/grpc-service/go.mod @@ -6,5 +6,5 @@ require ( github.com/envoyproxy/go-control-plane v0.11.1 github.com/golang/protobuf v1.5.3 google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 - google.golang.org/grpc v1.58.0 + google.golang.org/grpc v1.58.1 ) diff --git a/examples/ext_authz/auth/grpc-service/go.sum b/examples/ext_authz/auth/grpc-service/go.sum index 001fe49be5de..e6f05609bfb6 100644 --- a/examples/ext_authz/auth/grpc-service/go.sum +++ b/examples/ext_authz/auth/grpc-service/go.sum @@ -1656,8 +1656,8 @@ google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwS google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/grpc v1.58.0 h1:32JY8YpPMSR45K+c3o6b8VL73V+rR8k+DeMIr4vRH8o= -google.golang.org/grpc v1.58.0/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.58.1 h1:OL+Vz23DTtrrldqHK49FUOPHyY75rvFqJfXC84NYW58= +google.golang.org/grpc v1.58.1/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= diff --git a/examples/golang-http/simple/config.go b/examples/golang-http/simple/config.go index 97b2cc164cad..effd79cb87be 100644 --- a/examples/golang-http/simple/config.go +++ b/examples/golang-http/simple/config.go @@ -25,6 +25,8 @@ type config struct { type parser struct { } +// Parse the filter configuration. We can call the ConfigCallbackHandler to control the filter's +// behavior func (p *parser) Parse(any *anypb.Any, callbacks api.ConfigCallbackHandler) (interface{}, error) { configStruct := &xds.TypedStruct{} if err := any.UnmarshalTo(configStruct); err != nil { @@ -45,6 +47,7 @@ func (p *parser) Parse(any *anypb.Any, callbacks api.ConfigCallbackHandler) (int return conf, nil } +// Merge configuration from the inherited parent configuration func (p *parser) Merge(parent interface{}, child interface{}) interface{} { parentConfig := parent.(*config) childConfig := child.(*config) diff --git a/examples/golang-http/simple/filter.go b/examples/golang-http/simple/filter.go index f4fb83f006b9..5eeddae31306 100644 --- a/examples/golang-http/simple/filter.go +++ b/examples/golang-http/simple/filter.go @@ -9,6 +9,8 @@ import ( var UpdateUpstreamBody = "upstream response body updated by the simple plugin" +// The callbacks in the filter, like `DecodeHeaders`, can be implemented on demand. +// Because api.PassThroughStreamFilter provides a default implementation. type filter struct { api.PassThroughStreamFilter @@ -20,10 +22,12 @@ type filter struct { func (f *filter) sendLocalReplyInternal() api.StatusType { body := fmt.Sprintf("%s, path: %s\r\n", f.config.echoBody, f.path) f.callbacks.SendLocalReply(200, body, nil, 0, "") + // Remember to return LocalReply when the request is replied locally return api.LocalReply } // Callbacks which are called in request path +// The endStream is true if the request doesn't have body func (f *filter) DecodeHeaders(header api.RequestHeaderMap, endStream bool) api.StatusType { f.path, _ = header.Get(":path") api.LogDebugf("get path %s", f.path) @@ -32,60 +36,104 @@ func (f *filter) DecodeHeaders(header api.RequestHeaderMap, endStream bool) api. return f.sendLocalReplyInternal() } return api.Continue + /* + // If the code is time-consuming, to avoid blocking the Envoy, + // we need to run the code in a background goroutine + // and suspend & resume the filter + go func() { + defer f.callbacks.RecoverPanic() + // do time-consuming jobs + + // resume the filter + f.callbacks.Continue(status) + }() + + // suspend the filter + return api.Running + */ } -/* -The callbacks can be implemented on demand - +// DecodeData might be called multiple times during handling the request body. +// The endStream is true when handling the last piece of the body. func (f *filter) DecodeData(buffer api.BufferInstance, endStream bool) api.StatusType { + // support suspending & resuming the filter in a background goroutine return api.Continue } func (f *filter) DecodeTrailers(trailers api.RequestTrailerMap) api.StatusType { + // support suspending & resuming the filter in a background goroutine return api.Continue } -*/ +// Callbacks which are called in response path +// The endStream is true if the response doesn't have body func (f *filter) EncodeHeaders(header api.ResponseHeaderMap, endStream bool) api.StatusType { if f.path == "/update_upstream_response" { header.Set("Content-Length", strconv.Itoa(len(UpdateUpstreamBody))) } header.Set("Rsp-Header-From-Go", "bar-test") + // support suspending & resuming the filter in a background goroutine return api.Continue } -// Callbacks which are called in response path +// EncodeData might be called multiple times during handling the response body. +// The endStream is true when handling the last piece of the body. func (f *filter) EncodeData(buffer api.BufferInstance, endStream bool) api.StatusType { if f.path == "/update_upstream_response" { if endStream { buffer.SetString(UpdateUpstreamBody) } else { - // TODO implement buffer->Drain, buffer.SetString means buffer->Drain(buffer.Len()) - buffer.SetString("") + buffer.Reset() } } + // support suspending & resuming the filter in a background goroutine return api.Continue } -/* -The callbacks can be implemented on demand - func (f *filter) EncodeTrailers(trailers api.ResponseTrailerMap) api.StatusType { return api.Continue } +// OnLog is called when the HTTP stream is ended on HTTP Connection Manager filter. func (f *filter) OnLog() { - // Collect request info when it is ended + code, _ := f.callbacks.StreamInfo().ResponseCode() + respCode := strconv.Itoa(int(code)) + api.LogDebug(respCode) + + /* + // It's possible to kick off a goroutine here. + // But it's unsafe to access the f.callbacks because the FilterCallbackHandler + // may be already released when the goroutine is scheduled. + go func() { + defer func() { + if p := recover(); p != nil { + const size = 64 << 10 + buf := make([]byte, size) + buf = buf[:runtime.Stack(buf, false)] + fmt.Printf("http: panic serving: %v\n%s", p, buf) + } + }() + + // do time-consuming jobs + }() + */ } +// OnLogDownstreamStart is called when HTTP Connection Manager filter receives a new HTTP request +// (required the corresponding access log type is enabled) func (f *filter) OnLogDownstreamStart() { - // Collect request info when the request is started (required corresponding Envoy configuration) + // also support kicking off a goroutine here, like OnLog. } +// OnLogDownstreamPeriodic is called on any HTTP Connection Manager periodic log record +// (required the corresponding access log type is enabled) func (f *filter) OnLogDownstreamPeriodic() { - // Collect request info periodically (required corresponding Envoy configuration) + // also support kicking off a goroutine here, like OnLog. } func (f *filter) OnDestroy(reason api.DestroyReason) { + // One should not access f.callbacks here because the FilterCallbackHandler + // is released. But we can still access other Go fields in the filter f. + + // goroutine can be used everywhere. } -*/ diff --git a/examples/load-reporting-service/go.mod b/examples/load-reporting-service/go.mod index c8a249d4fc70..8dbb321ce1c7 100644 --- a/examples/load-reporting-service/go.mod +++ b/examples/load-reporting-service/go.mod @@ -5,5 +5,5 @@ go 1.13 require ( github.com/envoyproxy/go-control-plane v0.11.1 github.com/golang/protobuf v1.5.3 - google.golang.org/grpc v1.58.0 + google.golang.org/grpc v1.58.1 ) diff --git a/examples/load-reporting-service/go.sum b/examples/load-reporting-service/go.sum index 001fe49be5de..e6f05609bfb6 100644 --- a/examples/load-reporting-service/go.sum +++ b/examples/load-reporting-service/go.sum @@ -1656,8 +1656,8 @@ google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwS google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/grpc v1.58.0 h1:32JY8YpPMSR45K+c3o6b8VL73V+rR8k+DeMIr4vRH8o= -google.golang.org/grpc v1.58.0/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.58.1 h1:OL+Vz23DTtrrldqHK49FUOPHyY75rvFqJfXC84NYW58= +google.golang.org/grpc v1.58.1/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= diff --git a/examples/mysql/Dockerfile-mysql b/examples/mysql/Dockerfile-mysql index ef07da28c81b..3c38055467fa 100644 --- a/examples/mysql/Dockerfile-mysql +++ b/examples/mysql/Dockerfile-mysql @@ -1 +1 @@ -FROM mysql:8.1.0@sha256:c0455ac041844b5e65cd08571387fa5b50ab2a6179557fd938298cab13acf0dd +FROM mysql:8.1.0@sha256:85ab57eb4a48ada2a341dcf7d96733ce2f370fffb8e8e216991b106e50fa6434 diff --git a/examples/shared/build/Dockerfile b/examples/shared/build/Dockerfile index 438aec3f5b99..b6199e72dc13 100644 --- a/examples/shared/build/Dockerfile +++ b/examples/shared/build/Dockerfile @@ -1,4 +1,4 @@ -FROM envoyproxy/envoy-build-ubuntu:1f2f7ee78f894859de0fa7a415b0bedde1f6c560@sha256:6a6a64be3f4e3c4380531ad1624f9419d1fe99dde4e5eeb04e2d538a92f27205 +FROM envoyproxy/envoy-build-ubuntu:56f235b141079013e64912d676fe7da981368402@sha256:d44499c6fd28a8a6a75dc61668b8a9e7bc3d99db11f9a61e8ea1d1f39c20a236 ENV DEBIAN_FRONTEND=noninteractive RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ --mount=type=cache,target=/var/lib/apt/lists,sharing=locked \ diff --git a/examples/shared/postgres/Dockerfile b/examples/shared/postgres/Dockerfile index c0be44672302..66e023ea11a9 100644 --- a/examples/shared/postgres/Dockerfile +++ b/examples/shared/postgres/Dockerfile @@ -1,3 +1,3 @@ -FROM postgres:latest@sha256:f2d194fecc644f4d71fb52ff191f17e3550247e2511affbecc2514269f84639a +FROM postgres:latest@sha256:bf0c7de8c8eadc8c86c631999b050e988a21c80530808f011bd864c899763e0f COPY docker-healthcheck.sh /usr/local/bin/ HEALTHCHECK CMD ["docker-healthcheck.sh"] diff --git a/mobile/STYLE.md b/mobile/STYLE.md index 108560a33525..9f11a05a8378 100644 --- a/mobile/STYLE.md +++ b/mobile/STYLE.md @@ -43,3 +43,16 @@ lowest applicable layer (core/bridge) of the library, and then declaring public values defined in terms of the enumeration, to be shared across bridge and platform code. See, for example: https://github.com/envoyproxy/envoy-mobile/blob/2a1b53427100d94878551b55bb564e9117f83fe6/library/common/types/c_types.h#L25 + +## Checking Format Problems + +``` +tools/check_format.sh +``` + +## Fixing Format Problems + +``` +tools/check_format.sh fix +``` + diff --git a/mobile/docs/publish.sh b/mobile/docs/publish.sh index 9c32ccc228b9..dc821274f934 100755 --- a/mobile/docs/publish.sh +++ b/mobile/docs/publish.sh @@ -10,7 +10,7 @@ set -e DOCS_DIR=generated/docs -CHECKOUT_DIR=../../envoy-mobile-docs +CHECKOUT_DIR=../envoy-mobile-docs BUILD_SHA="$(git rev-parse HEAD)" if [ "$GITHUB_REF_TYPE" == "tag" ] diff --git a/mobile/third_party/rbe_configs/config/BUILD b/mobile/third_party/rbe_configs/config/BUILD index 57c8c557cd40..35069fba0019 100644 --- a/mobile/third_party/rbe_configs/config/BUILD +++ b/mobile/third_party/rbe_configs/config/BUILD @@ -42,7 +42,7 @@ platform( "@bazel_tools//tools/cpp:clang", ], exec_properties = { - "container-image": "docker://envoyproxy/envoy-build-ubuntu:mobile-1f2f7ee78f894859de0fa7a415b0bedde1f6c560@sha256:2c9852c10f133f780a96286230b7e07582e1c99fe204943d4fa66567f8b850f6", + "container-image": "docker://envoyproxy/envoy-build-ubuntu:mobile-56f235b141079013e64912d676fe7da981368402@sha256:b3cfc59c2fd1a86a2b12d303324f33d7f7248458233f3be2959fab119b11fa6f", "OSFamily": "Linux", "Pool": "linux", }, @@ -57,7 +57,7 @@ platform( "@bazel_tools//tools/cpp:clang", ], exec_properties = { - "container-image": "docker://envoyproxy/envoy-build-ubuntu:mobile-1f2f7ee78f894859de0fa7a415b0bedde1f6c560@sha256:2c9852c10f133f780a96286230b7e07582e1c99fe204943d4fa66567f8b850f6", + "container-image": "docker://envoyproxy/envoy-build-ubuntu:mobile-56f235b141079013e64912d676fe7da981368402@sha256:b3cfc59c2fd1a86a2b12d303324f33d7f7248458233f3be2959fab119b11fa6f", "OSFamily": "Linux", "Pool": "linux", # Necessary to workaround https://github.com/google/sanitizers/issues/916, otherwise, dangling threads in the diff --git a/source/common/common/random_generator.cc b/source/common/common/random_generator.cc index 53e59c2ffb60..ba00e970f843 100644 --- a/source/common/common/random_generator.cc +++ b/source/common/common/random_generator.cc @@ -128,7 +128,7 @@ std::string RandomGeneratorImpl::uuid() { uuid[2 * i + 5] = hex[d & 0x0f]; } - return std::string(uuid, UUID_LENGTH); + return {uuid, UUID_LENGTH}; } } // namespace Random diff --git a/source/common/common/utility.cc b/source/common/common/utility.cc index 824558e391e3..3c425812fa4e 100644 --- a/source/common/common/utility.cc +++ b/source/common/common/utility.cc @@ -235,7 +235,8 @@ OutputBufferStream::OutputBufferStream(char* data, size_t size) int OutputBufferStream::bytesWritten() const { return pptr() - pbase(); } absl::string_view OutputBufferStream::contents() const { - return absl::string_view(pbase(), bytesWritten()); + const std::string::size_type written = bytesWritten(); + return {pbase(), written}; } ConstMemoryStreamBuffer::ConstMemoryStreamBuffer(const char* data, size_t size) { @@ -433,7 +434,7 @@ size_t StringUtil::strlcpy(char* dst, const char* src, size_t size) { } std::string StringUtil::subspan(absl::string_view source, size_t start, size_t end) { - return std::string(source.data() + start, end - start); + return {source.data() + start, end - start}; } std::string StringUtil::escape(const absl::string_view source) { diff --git a/source/common/event/scaled_range_timer_manager_impl.cc b/source/common/event/scaled_range_timer_manager_impl.cc index 81e4e91afd48..a7c72962d141 100644 --- a/source/common/event/scaled_range_timer_manager_impl.cc +++ b/source/common/event/scaled_range_timer_manager_impl.cc @@ -214,7 +214,7 @@ ScaledRangeTimerManagerImpl::activateTimer(std::chrono::milliseconds duration, resetQueueTimer(queue, dispatcher_.approximateMonotonicTime()); } - return ScalingTimerHandle(queue, --queue.range_timers_.end()); + return {queue, --queue.range_timers_.end()}; } void ScaledRangeTimerManagerImpl::removeTimer(ScalingTimerHandle handle) { diff --git a/source/common/http/conn_manager_impl.cc b/source/common/http/conn_manager_impl.cc index 5da6ce4da9e5..3071e7809cf6 100644 --- a/source/common/http/conn_manager_impl.cc +++ b/source/common/http/conn_manager_impl.cc @@ -1608,8 +1608,7 @@ void ConnectionManagerImpl::ActiveStream::requestRouteConfigUpdate( absl::optional ConnectionManagerImpl::ActiveStream::routeConfig() { if (connection_manager_.config_.routeConfigProvider() != nullptr) { - return absl::optional( - connection_manager_.config_.routeConfigProvider()->configCast()); + return {connection_manager_.config_.routeConfigProvider()->configCast()}; } return {}; } diff --git a/source/common/http/utility.cc b/source/common/http/utility.cc index 3168d7a9af88..bd9ce8323bd1 100644 --- a/source/common/http/utility.cc +++ b/source/common/http/utility.cc @@ -506,7 +506,7 @@ Utility::QueryParams Utility::parseQueryString(absl::string_view url) { Utility::QueryParamsMulti Utility::QueryParamsMulti::parseQueryString(absl::string_view url) { size_t start = url.find('?'); if (start == std::string::npos) { - return Utility::QueryParamsMulti(); + return {}; } start++; @@ -528,7 +528,7 @@ Utility::QueryParamsMulti Utility::QueryParamsMulti::parseAndDecodeQueryString(absl::string_view url) { size_t start = url.find('?'); if (start == std::string::npos) { - return Utility::QueryParamsMulti(); + return {}; } start++; @@ -622,8 +622,7 @@ absl::string_view Utility::findQueryStringStart(const HeaderString& path) { std::string Utility::stripQueryString(const HeaderString& path) { absl::string_view path_str = path.getStringView(); size_t query_offset = path_str.find('?'); - return std::string(path_str.data(), - query_offset != path_str.npos ? query_offset : path_str.size()); + return {path_str.data(), query_offset != path_str.npos ? query_offset : path_str.size()}; } std::string Utility::replaceQueryString(const HeaderString& path, diff --git a/source/common/network/BUILD b/source/common/network/BUILD index 63662c0128c9..a86c387ca714 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -78,8 +78,8 @@ envoy_cc_library( srcs = ["connection_impl_base.cc"], hdrs = ["connection_impl_base.h"], deps = [ + ":connection_socket_lib", ":filter_manager_lib", - ":listen_socket_lib", "//envoy/common:scope_tracker_interface", "//envoy/event:dispatcher_interface", "//source/common/common:assert_lib", @@ -117,7 +117,6 @@ envoy_cc_library( "//source/common/common:enum_to_int", "//source/common/common:minimal_logger_lib", "//source/common/event:libevent_lib", - "//source/common/network:listen_socket_lib", "//source/common/network:socket_option_factory_lib", "//source/common/runtime:runtime_features_lib", "//source/common/stream_info:stream_info_lib", @@ -281,11 +280,23 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "connection_socket_lib", + hdrs = ["connection_socket_impl.h"], + deps = [ + ":socket_lib", + ":utility_lib", + "//envoy/network:exception_interface", + "//source/common/common:assert_lib", + ], +) + envoy_cc_library( name = "listen_socket_lib", srcs = ["listen_socket_impl.cc"], hdrs = ["listen_socket_impl.h"], deps = [ + ":connection_socket_lib", ":socket_lib", ":utility_lib", "//envoy/network:exception_interface", diff --git a/source/common/network/address_impl.cc b/source/common/network/address_impl.cc index a00c5e121e2b..b165c2bcec9d 100644 --- a/source/common/network/address_impl.cc +++ b/source/common/network/address_impl.cc @@ -208,7 +208,8 @@ std::string Ipv4Instance::sockaddrToString(const sockaddr_in& addr) { *--start = '.'; } } - return std::string(start, str + BufferSize - start); + const std::string::size_type end = str + BufferSize - start; + return {start, end}; } absl::Status Ipv4Instance::validateProtocolSupported() { diff --git a/source/common/network/connection_impl.cc b/source/common/network/connection_impl.cc index 22b8a7c4055b..b6858939f517 100644 --- a/source/common/network/connection_impl.cc +++ b/source/common/network/connection_impl.cc @@ -18,7 +18,7 @@ #include "source/common/common/enum_to_int.h" #include "source/common/common/scope_tracker.h" #include "source/common/network/address_impl.h" -#include "source/common/network/listen_socket_impl.h" +#include "source/common/network/connection_socket_impl.h" #include "source/common/network/raw_buffer_socket.h" #include "source/common/network/socket_option_factory.h" #include "source/common/network/socket_option_impl.h" diff --git a/source/common/network/connection_socket_impl.h b/source/common/network/connection_socket_impl.h new file mode 100644 index 000000000000..51589d8ac4a3 --- /dev/null +++ b/source/common/network/connection_socket_impl.h @@ -0,0 +1,110 @@ +#pragma once + +#include +#include +#include + +#include "envoy/common/platform.h" +#include "envoy/network/connection.h" +#include "envoy/network/listen_socket.h" +#include "envoy/network/socket.h" +#include "envoy/network/socket_interface.h" + +#include "source/common/common/assert.h" +#include "source/common/common/dump_state_utils.h" +#include "source/common/network/socket_impl.h" +#include "source/common/network/socket_interface.h" + +namespace Envoy { +namespace Network { + +/** + * Wraps a unix socket. + */ +template struct NetworkSocketTrait {}; + +template <> struct NetworkSocketTrait { + static constexpr Socket::Type type = Socket::Type::Stream; +}; + +template <> struct NetworkSocketTrait { + static constexpr Socket::Type type = Socket::Type::Datagram; +}; + +class ConnectionSocketImpl : public SocketImpl, public ConnectionSocket { +public: + ConnectionSocketImpl(IoHandlePtr&& io_handle, + const Address::InstanceConstSharedPtr& local_address, + const Address::InstanceConstSharedPtr& remote_address) + : SocketImpl(std::move(io_handle), local_address, remote_address) {} + + ConnectionSocketImpl(Socket::Type type, const Address::InstanceConstSharedPtr& local_address, + const Address::InstanceConstSharedPtr& remote_address, + const SocketCreationOptions& options) + : SocketImpl(type, local_address, remote_address, options) { + connection_info_provider_->setLocalAddress(local_address); + } + + // Network::ConnectionSocket + void setDetectedTransportProtocol(absl::string_view protocol) override { + transport_protocol_ = std::string(protocol); + } + absl::string_view detectedTransportProtocol() const override { return transport_protocol_; } + + void setRequestedApplicationProtocols(const std::vector& protocols) override { + application_protocols_.clear(); + for (const auto& protocol : protocols) { + application_protocols_.emplace_back(protocol); + } + } + const std::vector& requestedApplicationProtocols() const override { + return application_protocols_; + } + + void setRequestedServerName(absl::string_view server_name) override { + // Always keep the server_name_ as lower case. + connectionInfoProvider().setRequestedServerName(absl::AsciiStrToLower(server_name)); + } + absl::string_view requestedServerName() const override { + return connectionInfoProvider().requestedServerName(); + } + + void setJA3Hash(absl::string_view ja3_hash) override { + connectionInfoProvider().setJA3Hash(ja3_hash); + } + absl::string_view ja3Hash() const override { return connectionInfoProvider().ja3Hash(); } + + absl::optional lastRoundTripTime() override { + return ioHandle().lastRoundTripTime(); + } + + absl::optional congestionWindowInBytes() const override { + return ioHandle().congestionWindowInBytes(); + } + + void dumpState(std::ostream& os, int indent_level) const override { + const char* spaces = spacesForLevel(indent_level); + os << spaces << "ListenSocketImpl " << this << DUMP_MEMBER(transport_protocol_) << "\n"; + DUMP_DETAILS(connection_info_provider_); + } + +protected: + std::string transport_protocol_; + std::vector application_protocols_; +}; + +// ConnectionSocket used with client connections. +class ClientSocketImpl : public ConnectionSocketImpl { +public: + ClientSocketImpl(const Address::InstanceConstSharedPtr& remote_address, + const OptionsSharedPtr& options) + : ConnectionSocketImpl(Network::ioHandleForAddr(Socket::Type::Stream, remote_address, {}), + nullptr, remote_address) { + if (options) { + addOptions(options); + } + } +}; + +} // namespace Network +} // namespace Envoy diff --git a/source/common/network/io_socket_handle_impl.cc b/source/common/network/io_socket_handle_impl.cc index 0838985e654b..0ccd658e7df8 100644 --- a/source/common/network/io_socket_handle_impl.cc +++ b/source/common/network/io_socket_handle_impl.cc @@ -62,7 +62,7 @@ Api::IoCallUint64Result IoSocketHandleImpl::close() { ASSERT(SOCKET_VALID(fd_)); const int rc = Api::OsSysCallsSingleton::get().close(fd_).return_value_; SET_SOCKET_INVALID(fd_); - return Api::IoCallUint64Result(rc, Api::IoErrorPtr(nullptr, IoSocketError::deleteIoError)); + return {static_cast(rc), Api::IoErrorPtr(nullptr, IoSocketError::deleteIoError)}; } bool IoSocketHandleImpl::isOpen() const { return SOCKET_VALID(fd_); } @@ -560,7 +560,8 @@ Address::InstanceConstSharedPtr IoSocketHandleImpl::peerAddress() { fmt::format("getpeername failed for '{}': {}", fd_, errorDetails(result.errno_))); } - if (ss_len >= (offsetof(sockaddr_storage, ss_family) + sizeof(ss.ss_family)) && + if (static_cast(ss_len) >= + (offsetof(sockaddr_storage, ss_family) + sizeof(ss.ss_family)) && ss.ss_family == AF_UNIX) { // For Unix domain sockets, can't find out the peer name, but it should match our own // name for the socket (i.e. the path should match, barring any namespace or other diff --git a/source/common/network/listen_socket_impl.h b/source/common/network/listen_socket_impl.h index 9fb220c47edd..a3c385ea1531 100644 --- a/source/common/network/listen_socket_impl.h +++ b/source/common/network/listen_socket_impl.h @@ -12,6 +12,7 @@ #include "source/common/common/assert.h" #include "source/common/common/dump_state_utils.h" +#include "source/common/network/connection_socket_impl.h" #include "source/common/network/socket_impl.h" #include "source/common/network/socket_interface.h" @@ -42,19 +43,6 @@ class ListenSocketImpl : public SocketImpl { bool isOpen() const override { return io_handle_ != nullptr && io_handle_->isOpen(); } }; -/** - * Wraps a unix socket. - */ -template struct NetworkSocketTrait {}; - -template <> struct NetworkSocketTrait { - static constexpr Socket::Type type = Socket::Type::Stream; -}; - -template <> struct NetworkSocketTrait { - static constexpr Socket::Type type = Socket::Type::Datagram; -}; - template class NetworkListenSocket : public ListenSocketImpl { public: NetworkListenSocket(const Address::InstanceConstSharedPtr& address, @@ -178,68 +166,6 @@ class InternalListenSocket : public ListenSocketImpl { } }; -class ConnectionSocketImpl : public SocketImpl, public ConnectionSocket { -public: - ConnectionSocketImpl(IoHandlePtr&& io_handle, - const Address::InstanceConstSharedPtr& local_address, - const Address::InstanceConstSharedPtr& remote_address) - : SocketImpl(std::move(io_handle), local_address, remote_address) {} - - ConnectionSocketImpl(Socket::Type type, const Address::InstanceConstSharedPtr& local_address, - const Address::InstanceConstSharedPtr& remote_address, - const SocketCreationOptions& options) - : SocketImpl(type, local_address, remote_address, options) { - connection_info_provider_->setLocalAddress(local_address); - } - - // Network::ConnectionSocket - void setDetectedTransportProtocol(absl::string_view protocol) override { - transport_protocol_ = std::string(protocol); - } - absl::string_view detectedTransportProtocol() const override { return transport_protocol_; } - - void setRequestedApplicationProtocols(const std::vector& protocols) override { - application_protocols_.clear(); - for (const auto& protocol : protocols) { - application_protocols_.emplace_back(protocol); - } - } - const std::vector& requestedApplicationProtocols() const override { - return application_protocols_; - } - - void setRequestedServerName(absl::string_view server_name) override { - // Always keep the server_name_ as lower case. - connectionInfoProvider().setRequestedServerName(absl::AsciiStrToLower(server_name)); - } - absl::string_view requestedServerName() const override { - return connectionInfoProvider().requestedServerName(); - } - - void setJA3Hash(absl::string_view ja3_hash) override { - connectionInfoProvider().setJA3Hash(ja3_hash); - } - absl::string_view ja3Hash() const override { return connectionInfoProvider().ja3Hash(); } - - absl::optional lastRoundTripTime() override { - return ioHandle().lastRoundTripTime(); - } - - absl::optional congestionWindowInBytes() const override { - return ioHandle().congestionWindowInBytes(); - } - - void dumpState(std::ostream& os, int indent_level) const override { - const char* spaces = spacesForLevel(indent_level); - os << spaces << "ListenSocketImpl " << this << DUMP_MEMBER(transport_protocol_) << "\n"; - DUMP_DETAILS(connection_info_provider_); - } - -protected: - std::string transport_protocol_; - std::vector application_protocols_; -}; - // ConnectionSocket used with server connections. class AcceptedSocketImpl : public ConnectionSocketImpl { public: @@ -262,18 +188,5 @@ class AcceptedSocketImpl : public ConnectionSocketImpl { static std::atomic global_accepted_socket_count_; }; -// ConnectionSocket used with client connections. -class ClientSocketImpl : public ConnectionSocketImpl { -public: - ClientSocketImpl(const Address::InstanceConstSharedPtr& remote_address, - const OptionsSharedPtr& options) - : ConnectionSocketImpl(Network::ioHandleForAddr(Socket::Type::Stream, remote_address, {}), - nullptr, remote_address) { - if (options) { - addOptions(options); - } - } -}; - } // namespace Network } // namespace Envoy diff --git a/source/common/quic/BUILD b/source/common/quic/BUILD index e1769f3919c4..b4aa1262cacf 100644 --- a/source/common/quic/BUILD +++ b/source/common/quic/BUILD @@ -336,7 +336,6 @@ envoy_cc_library( tags = ["nofips"], deps = [ "//envoy/network:connection_interface", - "//source/common/network:listen_socket_lib", ], ) @@ -349,6 +348,7 @@ envoy_cc_library( ":quic_io_handle_wrapper_lib", ":quic_network_connection_lib", "//source/common/network:generic_listener_filter_impl_base_lib", + "//source/common/network:listen_socket_lib", "//source/common/quic:envoy_quic_utils_lib", "@com_github_google_quiche//:quic_core_connection_lib", ], @@ -434,7 +434,7 @@ envoy_cc_library( "//source/common/http:header_map_lib", "//source/common/http:header_utility_lib", "//source/common/network:address_lib", - "//source/common/network:listen_socket_lib", + "//source/common/network:connection_socket_lib", "//source/common/network:socket_option_factory_lib", "//source/common/quic:quic_io_handle_wrapper_lib", "@com_github_google_quiche//:quic_core_config_lib", diff --git a/source/common/quic/envoy_quic_client_connection.cc b/source/common/quic/envoy_quic_client_connection.cc index 9fd5f64bbe48..8e2ba1aa49b2 100644 --- a/source/common/quic/envoy_quic_client_connection.cc +++ b/source/common/quic/envoy_quic_client_connection.cc @@ -4,7 +4,6 @@ #include "envoy/config/core/v3/base.pb.h" -#include "source/common/network/listen_socket_impl.h" #include "source/common/network/socket_option_factory.h" #include "source/common/network/udp_packet_writer_handler_impl.h" #include "source/common/quic/envoy_quic_utils.h" diff --git a/source/common/quic/envoy_quic_utils.h b/source/common/quic/envoy_quic_utils.h index e5fcc2532a7b..ae63d9a78297 100644 --- a/source/common/quic/envoy_quic_utils.h +++ b/source/common/quic/envoy_quic_utils.h @@ -8,7 +8,7 @@ #include "source/common/http/header_map_impl.h" #include "source/common/http/header_utility.h" #include "source/common/network/address_impl.h" -#include "source/common/network/listen_socket_impl.h" +#include "source/common/network/connection_socket_impl.h" #include "source/common/quic/quic_io_handle_wrapper.h" #include "openssl/ssl.h" diff --git a/source/common/quic/quic_filter_manager_connection_impl.cc b/source/common/quic/quic_filter_manager_connection_impl.cc index 2c9432d10ba9..a6731cd164fa 100644 --- a/source/common/quic/quic_filter_manager_connection_impl.cc +++ b/source/common/quic/quic_filter_manager_connection_impl.cc @@ -123,7 +123,7 @@ QuicFilterManagerConnectionImpl::socketOptions() const { } Ssl::ConnectionInfoConstSharedPtr QuicFilterManagerConnectionImpl::ssl() const { - return Ssl::ConnectionInfoConstSharedPtr(quic_ssl_info_); + return {quic_ssl_info_}; } void QuicFilterManagerConnectionImpl::rawWrite(Buffer::Instance& /*data*/, bool /*end_stream*/) { diff --git a/source/common/ssl/tls_certificate_config_impl.cc b/source/common/ssl/tls_certificate_config_impl.cc index 0d4c1dfb83bd..7e96344d7f9a 100644 --- a/source/common/ssl/tls_certificate_config_impl.cc +++ b/source/common/ssl/tls_certificate_config_impl.cc @@ -46,10 +46,6 @@ TlsCertificateConfigImpl::TlsCertificateConfigImpl( ocsp_staple_path_(Config::DataSource::getPath(config.ocsp_staple()) .value_or(ocsp_staple_.empty() ? EMPTY_STRING : INLINE_STRING)), private_key_method_(nullptr) { - if (config.has_private_key_provider() && config.has_private_key()) { - throw EnvoyException(fmt::format( - "Certificate configuration can't have both private_key and private_key_provider")); - } if (config.has_pkcs12()) { if (config.has_private_key()) { throw EnvoyException( @@ -69,20 +65,25 @@ TlsCertificateConfigImpl::TlsCertificateConfigImpl( factory_context.sslContextManager() .privateKeyMethodManager() .createPrivateKeyMethodProvider(config.private_key_provider(), factory_context); + if (private_key_method_ == nullptr || + (!private_key_method_->isAvailable() && !config.private_key_provider().fallback())) { + throw EnvoyException(fmt::format("Failed to load private key provider: {}", + config.private_key_provider().provider_name())); + } + + if (!private_key_method_->isAvailable()) { + private_key_method_ = nullptr; + } } if (certificate_chain_.empty()) { throw EnvoyException( fmt::format("Failed to load incomplete certificate from {}: certificate chain not set", certificate_chain_path_)); } + if (private_key_.empty() && private_key_method_ == nullptr) { - if (config.has_private_key_provider()) { - throw EnvoyException(fmt::format("Failed to load private key provider: {}", - config.private_key_provider().provider_name())); - } else { - throw EnvoyException( - fmt::format("Failed to load incomplete private key from path: {}", private_key_path_)); - } + throw EnvoyException( + fmt::format("Failed to load incomplete private key from path: {}", private_key_path_)); } } } diff --git a/source/common/stats/thread_local_store.cc b/source/common/stats/thread_local_store.cc index e51e847610c6..faa2e771d1aa 100644 --- a/source/common/stats/thread_local_store.cc +++ b/source/common/stats/thread_local_store.cc @@ -942,7 +942,7 @@ std::string ParentHistogramImpl::quantileSummary() const { } return absl::StrJoin(summary, " "); } else { - return std::string("No recorded values"); + return {"No recorded values"}; } } @@ -958,7 +958,7 @@ std::string ParentHistogramImpl::bucketSummary() const { } return absl::StrJoin(bucket_summary, " "); } else { - return std::string("No recorded values"); + return {"No recorded values"}; } } diff --git a/source/common/upstream/default_local_address_selector.cc b/source/common/upstream/default_local_address_selector.cc index 8108116e3bc4..1d66e50e2522 100644 --- a/source/common/upstream/default_local_address_selector.cc +++ b/source/common/upstream/default_local_address_selector.cc @@ -10,7 +10,7 @@ DefaultUpstreamLocalAddressSelector::DefaultUpstreamLocalAddressSelector( : upstream_local_addresses_(std::move(upstream_local_addresses)) { // If bind config is not provided, we insert at least one // ``UpstreamLocalAddress`` with null address. - ASSERT(upstream_local_addresses_.size() > 0); + ASSERT(!upstream_local_addresses_.empty()); } UpstreamLocalAddress DefaultUpstreamLocalAddressSelector::getUpstreamLocalAddressImpl( diff --git a/source/common/upstream/default_local_address_selector_factory.cc b/source/common/upstream/default_local_address_selector_factory.cc index 64db72d67c33..f10dd91b4451 100644 --- a/source/common/upstream/default_local_address_selector_factory.cc +++ b/source/common/upstream/default_local_address_selector_factory.cc @@ -12,7 +12,7 @@ constexpr absl::string_view kDefaultLocalAddressSelectorName = void validate(const std::vector<::Envoy::Upstream::UpstreamLocalAddress>& upstream_local_addresses, absl::optional cluster_name) { - if (upstream_local_addresses.size() == 0) { + if (upstream_local_addresses.empty()) { throw EnvoyException(fmt::format("{}'s upstream binding config has no valid source address.", !(cluster_name.has_value()) ? "Bootstrap" diff --git a/source/common/upstream/transport_socket_match_impl.cc b/source/common/upstream/transport_socket_match_impl.cc index 63df66e2c2c2..18d29f7d1d0c 100644 --- a/source/common/upstream/transport_socket_match_impl.cc +++ b/source/common/upstream/transport_socket_match_impl.cc @@ -42,10 +42,10 @@ TransportSocketMatcherImpl::resolve(const envoy::config::core::v3::Metadata* met if (Config::Metadata::metadataLabelMatch( match.label_set, metadata, Envoy::Config::MetadataFilters::get().ENVOY_TRANSPORT_SOCKET_MATCH, false)) { - return MatchData(*match.factory, match.stats, match.name); + return {*match.factory, match.stats, match.name}; } } - return MatchData(*default_match_.factory, default_match_.stats, default_match_.name); + return {*default_match_.factory, default_match_.stats, default_match_.name}; } } // namespace Upstream diff --git a/source/common/upstream/upstream_impl.cc b/source/common/upstream/upstream_impl.cc index 3b8a104fd008..a21ae634b57f 100644 --- a/source/common/upstream/upstream_impl.cc +++ b/source/common/upstream/upstream_impl.cc @@ -848,7 +848,7 @@ ClusterInfoImpl::generateStats(Stats::ScopeSharedPtr scope, ClusterRequestResponseSizeStats ClusterInfoImpl::generateRequestResponseSizeStats( Stats::Scope& scope, const ClusterRequestResponseSizeStatNames& stat_names) { - return ClusterRequestResponseSizeStats(stat_names, scope); + return {stat_names, scope}; } ClusterLoadReportStats diff --git a/source/extensions/clusters/eds/eds.cc b/source/extensions/clusters/eds/eds.cc index 21eccdf5b42e..c2d1c504e5df 100644 --- a/source/extensions/clusters/eds/eds.cc +++ b/source/extensions/clusters/eds/eds.cc @@ -282,7 +282,6 @@ void EdsClusterImpl::update( BatchUpdateHelper helper(*this, *used_load_assignment); priority_set_.batchHostUpdate(helper); - return; } absl::Status diff --git a/source/extensions/clusters/redis/BUILD b/source/extensions/clusters/redis/BUILD index 195c9d02e595..14e29e634903 100644 --- a/source/extensions/clusters/redis/BUILD +++ b/source/extensions/clusters/redis/BUILD @@ -11,19 +11,15 @@ envoy_extension_package() envoy_cc_library( name = "crc16_lib", - srcs = [ - "crc16.cc", - "crc16.h", - ], + srcs = ["crc16.cc"], + hdrs = ["crc16.h"], deps = ["@com_google_absl//absl/strings"], ) envoy_cc_library( name = "redis_cluster_lb", - srcs = [ - "redis_cluster_lb.cc", - "redis_cluster_lb.h", - ], + srcs = ["redis_cluster_lb.cc"], + hdrs = ["redis_cluster_lb.h"], deps = [ ":crc16_lib", "//envoy/upstream:thread_local_cluster_interface", @@ -38,10 +34,8 @@ envoy_cc_library( envoy_cc_extension( name = "redis_cluster", - srcs = [ - "redis_cluster.cc", - "redis_cluster.h", - ], + srcs = ["redis_cluster.cc"], + hdrs = ["redis_cluster.h"], deps = [ "redis_cluster_lb", "//envoy/api:api_interface", diff --git a/source/extensions/common/aws/region_provider_impl.cc b/source/extensions/common/aws/region_provider_impl.cc index 0914c46ced41..c2b94f019413 100644 --- a/source/extensions/common/aws/region_provider_impl.cc +++ b/source/extensions/common/aws/region_provider_impl.cc @@ -9,9 +9,7 @@ static const char AWS_REGION[] = "AWS_REGION"; StaticRegionProvider::StaticRegionProvider(const std::string& region) : region_(region) {} -absl::optional StaticRegionProvider::getRegion() { - return absl::optional(region_); -} +absl::optional StaticRegionProvider::getRegion() { return {region_}; } absl::optional EnvironmentRegionProvider::getRegion() { const auto region = std::getenv(AWS_REGION); @@ -19,7 +17,7 @@ absl::optional EnvironmentRegionProvider::getRegion() { return absl::nullopt; } ENVOY_LOG(debug, "Found environment region {}={}", AWS_REGION, region); - return absl::optional(region); + return {region}; } } // namespace Aws diff --git a/source/extensions/compression/zstd/common/BUILD b/source/extensions/compression/zstd/common/BUILD index 2da038649999..98b6a3abb62f 100644 --- a/source/extensions/compression/zstd/common/BUILD +++ b/source/extensions/compression/zstd/common/BUILD @@ -20,7 +20,7 @@ envoy_cc_library( envoy_cc_library( name = "zstd_dictionary_manager_lib", - srcs = ["dictionary_manager.h"], + hdrs = ["dictionary_manager.h"], external_deps = ["zstd"], deps = [ "//envoy/event:dispatcher_interface", diff --git a/source/extensions/config_subscription/grpc/watch_map.cc b/source/extensions/config_subscription/grpc/watch_map.cc index ea00f4e0d5af..50a9a2909719 100644 --- a/source/extensions/config_subscription/grpc/watch_map.cc +++ b/source/extensions/config_subscription/grpc/watch_map.cc @@ -77,7 +77,7 @@ WatchMap::updateWatchInterest(Watch* watch, eds_resources_cache_->removeResource(resource_name); } } - return AddedRemoved(std::move(added_resources), std::move(removed_resources)); + return {std::move(added_resources), std::move(removed_resources)}; } absl::flat_hash_set WatchMap::watchesInterestedIn(const std::string& resource_name) { @@ -287,8 +287,8 @@ void WatchMap::onConfigUpdate( for (const auto& resource : decoded_resources) { const envoy::config::endpoint::v3::ClusterLoadAssignment& cluster_load_assignment = dynamic_cast( - resource.get()->resource()); - eds_resources_cache_->setResource(resource.get()->name(), cluster_load_assignment); + resource->resource()); + eds_resources_cache_->setResource(resource->name(), cluster_load_assignment); } // No need to remove resources from the cache, as currently only non-collection // subscriptions are supported, and these resources are removed in the call diff --git a/source/extensions/extensions_metadata.yaml b/source/extensions/extensions_metadata.yaml index f63117e8aff8..096095d664bd 100644 --- a/source/extensions/extensions_metadata.yaml +++ b/source/extensions/extensions_metadata.yaml @@ -311,8 +311,10 @@ envoy.filters.http.dynamic_forward_proxy: envoy.filters.http.ext_authz: categories: - envoy.filters.http + - envoy.filters.http.upstream security_posture: robust_to_untrusted_downstream status: stable + status_upstream: alpha type_urls: - envoy.extensions.filters.http.ext_authz.v3.ExtAuthz - envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute diff --git a/source/extensions/filters/common/ext_authz/check_request_utils.cc b/source/extensions/filters/common/ext_authz/check_request_utils.cc index 6d65dc7d4a4d..88a4f0e96f29 100644 --- a/source/extensions/filters/common/ext_authz/check_request_utils.cc +++ b/source/extensions/filters/common/ext_authz/check_request_utils.cc @@ -203,15 +203,17 @@ void CheckRequestUtils::createHttpCheck( // *cb->connection(), callbacks->streamInfo() and callbacks->decodingBuffer() are not qualified as // const. auto* cb = const_cast(callbacks); - setAttrContextPeer(*attrs->mutable_source(), *cb->connection(), service, false, - include_peer_certificate); - setAttrContextPeer(*attrs->mutable_destination(), *cb->connection(), EMPTY_STRING, true, - include_peer_certificate); + if (cb->connection().has_value()) { + setAttrContextPeer(*attrs->mutable_source(), *cb->connection(), service, false, + include_peer_certificate); + setAttrContextPeer(*attrs->mutable_destination(), *cb->connection(), EMPTY_STRING, true, + include_peer_certificate); + } setAttrContextRequest(*attrs->mutable_request(), cb->streamId(), cb->streamInfo(), cb->decodingBuffer(), headers, max_request_bytes, pack_as_bytes, request_header_matchers); - if (include_tls_session) { + if (include_tls_session && cb->connection().has_value()) { if (cb->connection()->ssl() != nullptr) { attrs->mutable_tls_session(); if (!cb->connection()->ssl()->sni().empty()) { @@ -240,6 +242,7 @@ void CheckRequestUtils::createTcpCheck( include_peer_certificate); setAttrContextPeer(*attrs->mutable_destination(), cb->connection(), server_name, true, include_peer_certificate); + (*attrs->mutable_destination()->mutable_labels()) = destination_labels; } diff --git a/source/extensions/filters/http/cache/cache_headers_utils.cc b/source/extensions/filters/http/cache/cache_headers_utils.cc index 1e9b3b8b588b..a02632d7c5ac 100644 --- a/source/extensions/filters/http/cache/cache_headers_utils.cc +++ b/source/extensions/filters/http/cache/cache_headers_utils.cc @@ -288,7 +288,7 @@ VaryHeaderUtils::getVaryValues(const Http::ResponseHeaderMap& headers) { std::vector values = CacheHeadersUtils::parseCommaDelimitedHeader(vary_headers); - return absl::btree_set(values.begin(), values.end()); + return {values.begin(), values.end()}; } namespace { diff --git a/source/extensions/filters/http/common/factory_base.h b/source/extensions/filters/http/common/factory_base.h index c334e6135482..3c82ce8e67a1 100644 --- a/source/extensions/filters/http/common/factory_base.h +++ b/source/extensions/filters/http/common/factory_base.h @@ -105,11 +105,12 @@ class DualFactoryBase : public CommonFactoryBase, struct DualInfo { DualInfo(Server::Configuration::UpstreamFactoryContext& context) - : init_manager(context.initManager()), scope(context.scope()) {} + : init_manager(context.initManager()), scope(context.scope()), is_upstream_filter(true) {} DualInfo(Server::Configuration::FactoryContext& context) - : init_manager(context.initManager()), scope(context.scope()) {} + : init_manager(context.initManager()), scope(context.scope()), is_upstream_filter(false) {} Init::Manager& init_manager; Stats::Scope& scope; + bool is_upstream_filter; }; Envoy::Http::FilterFactoryCb diff --git a/source/extensions/filters/http/ext_authz/config.cc b/source/extensions/filters/http/ext_authz/config.cc index 2b6cca8265a6..ea1fcd8fe40f 100644 --- a/source/extensions/filters/http/ext_authz/config.cc +++ b/source/extensions/filters/http/ext_authz/config.cc @@ -9,6 +9,7 @@ #include "envoy/grpc/async_client_manager.h" #include "envoy/registry/registry.h" +#include "source/common/common/utility.h" #include "source/common/config/utility.h" #include "source/common/protobuf/utility.h" #include "source/extensions/filters/common/ext_authz/ext_authz_grpc_impl.h" @@ -20,12 +21,27 @@ namespace Extensions { namespace HttpFilters { namespace ExtAuthz { -Http::FilterFactoryCb ExtAuthzFilterConfig::createFilterFactoryFromProtoTyped( +Http::FilterFactoryCb ExtAuthzFilterFactory::createFilterFactoryFromProtoTyped( const envoy::extensions::filters::http::ext_authz::v3::ExtAuthz& proto_config, - const std::string& stats_prefix, Server::Configuration::FactoryContext& context) { - const auto filter_config = std::make_shared( - proto_config, context.scope(), context.runtime(), context.httpContext(), stats_prefix, - context.getServerFactoryContext().bootstrap()); + const std::string& stats_prefix, DualInfo dual_info, + Server::Configuration::ServerFactoryContext& context) { + if (dual_info.is_upstream_filter) { + if (proto_config.clear_route_cache()) { + ExceptionUtil::throwEnvoyException( + "clear_route_cache cannot be enabled on an upstream ext_authz filter."); + } + if (proto_config.include_peer_certificate()) { + ExceptionUtil::throwEnvoyException( + "include_peer_certificate cannot be enabled on an upstream ext_authz filter."); + } + if (proto_config.include_tls_session()) { + ExceptionUtil::throwEnvoyException( + "include_tls_session cannot be enabled on an upstream ext_auth filter."); + } + } + const auto filter_config = + std::make_shared(proto_config, dual_info.scope, context.runtime(), + context.httpContext(), stats_prefix, context.bootstrap()); // The callback is created in main thread and executed in worker thread, variables except factory // context must be captured by value into the callback. Http::FilterFactoryCb callback; @@ -51,11 +67,11 @@ Http::FilterFactoryCb ExtAuthzFilterConfig::createFilterFactoryFromProtoTyped( THROW_IF_NOT_OK(Config::Utility::checkTransportVersion(proto_config)); Envoy::Grpc::GrpcServiceConfigWithHashKey config_with_hash_key = Envoy::Grpc::GrpcServiceConfigWithHashKey(proto_config.grpc_service()); - callback = [&context, filter_config, timeout_ms, - config_with_hash_key](Http::FilterChainFactoryCallbacks& callbacks) { + callback = [&context, filter_config, timeout_ms, config_with_hash_key, + dual_info](Http::FilterChainFactoryCallbacks& callbacks) { auto client = std::make_unique( context.clusterManager().grpcAsyncClientManager().getOrCreateRawAsyncClientWithHashKey( - config_with_hash_key, context.scope(), true), + config_with_hash_key, dual_info.scope, true), std::chrono::milliseconds(timeout_ms)); callbacks.addStreamFilter(std::make_shared(filter_config, std::move(client))); }; @@ -65,7 +81,7 @@ Http::FilterFactoryCb ExtAuthzFilterConfig::createFilterFactoryFromProtoTyped( } Router::RouteSpecificFilterConfigConstSharedPtr -ExtAuthzFilterConfig::createRouteSpecificFilterConfigTyped( +ExtAuthzFilterFactory::createRouteSpecificFilterConfigTyped( const envoy::extensions::filters::http::ext_authz::v3::ExtAuthzPerRoute& proto_config, Server::Configuration::ServerFactoryContext&, ProtobufMessage::ValidationVisitor&) { return std::make_shared(proto_config); @@ -74,8 +90,10 @@ ExtAuthzFilterConfig::createRouteSpecificFilterConfigTyped( /** * Static registration for the external authorization filter. @see RegisterFactory. */ -LEGACY_REGISTER_FACTORY(ExtAuthzFilterConfig, Server::Configuration::NamedHttpFilterConfigFactory, +LEGACY_REGISTER_FACTORY(ExtAuthzFilterFactory, Server::Configuration::NamedHttpFilterConfigFactory, "envoy.ext_authz"); +LEGACY_REGISTER_FACTORY(UpstreamExtAuthzFilterFactory, + Server::Configuration::UpstreamHttpFilterConfigFactory, "envoy.ext_authz"); } // namespace ExtAuthz } // namespace HttpFilters diff --git a/source/extensions/filters/http/ext_authz/config.h b/source/extensions/filters/http/ext_authz/config.h index a5cddfb6a12c..4e2238d76364 100644 --- a/source/extensions/filters/http/ext_authz/config.h +++ b/source/extensions/filters/http/ext_authz/config.h @@ -14,18 +14,19 @@ namespace ExtAuthz { /** * Config registration for the external authorization filter. @see NamedHttpFilterConfigFactory. */ -class ExtAuthzFilterConfig - : public Common::FactoryBase< +class ExtAuthzFilterFactory + : public Common::DualFactoryBase< envoy::extensions::filters::http::ext_authz::v3::ExtAuthz, envoy::extensions::filters::http::ext_authz::v3::ExtAuthzPerRoute> { public: - ExtAuthzFilterConfig() : FactoryBase("envoy.filters.http.ext_authz") {} + ExtAuthzFilterFactory() : DualFactoryBase("envoy.filters.http.ext_authz") {} private: static constexpr uint64_t DefaultTimeout = 200; Http::FilterFactoryCb createFilterFactoryFromProtoTyped( const envoy::extensions::filters::http::ext_authz::v3::ExtAuthz& proto_config, - const std::string& stats_prefix, Server::Configuration::FactoryContext& context) override; + const std::string& stats_prefix, DualInfo dual_info, + Server::Configuration::ServerFactoryContext& context) override; Router::RouteSpecificFilterConfigConstSharedPtr createRouteSpecificFilterConfigTyped( const envoy::extensions::filters::http::ext_authz::v3::ExtAuthzPerRoute& proto_config, @@ -33,6 +34,8 @@ class ExtAuthzFilterConfig ProtobufMessage::ValidationVisitor& validator) override; }; +using UpstreamExtAuthzFilterFactory = ExtAuthzFilterFactory; + } // namespace ExtAuthz } // namespace HttpFilters } // namespace Extensions diff --git a/source/extensions/filters/http/ext_authz/ext_authz.cc b/source/extensions/filters/http/ext_authz/ext_authz.cc index 68f327e9774d..7fe02926efba 100644 --- a/source/extensions/filters/http/ext_authz/ext_authz.cc +++ b/source/extensions/filters/http/ext_authz/ext_authz.cc @@ -46,34 +46,41 @@ void Filter::initiateCall(const Http::RequestHeaderMap& headers) { // If metadata_context_namespaces is specified, pass matching filter metadata to the ext_authz // service. If metadata key is set in both the connection and request metadata then the value // will be the request metadata value. - const auto& connection_metadata = - decoder_callbacks_->connection()->streamInfo().dynamicMetadata().filter_metadata(); + const auto& connection = decoder_callbacks_->connection(); const auto& request_metadata = decoder_callbacks_->streamInfo().dynamicMetadata().filter_metadata(); for (const auto& context_key : config_->metadataContextNamespaces()) { if (const auto metadata_it = request_metadata.find(context_key); metadata_it != request_metadata.end()) { (*metadata_context.mutable_filter_metadata())[metadata_it->first] = metadata_it->second; - } else if (const auto metadata_it = connection_metadata.find(context_key); - metadata_it != connection_metadata.end()) { - (*metadata_context.mutable_filter_metadata())[metadata_it->first] = metadata_it->second; + } else if (connection.has_value()) { + const auto& connection_metadata = + connection->streamInfo().dynamicMetadata().filter_metadata(); + const auto metadata_it = + connection->streamInfo().dynamicMetadata().filter_metadata().find(context_key); + if (metadata_it != connection_metadata.end()) { + (*metadata_context.mutable_filter_metadata())[metadata_it->first] = metadata_it->second; + } } } // If typed_metadata_context_namespaces is specified, pass matching typed filter metadata to the // ext_authz service. If metadata key is set in both the connection and request metadata then // the value will be the request metadata value. - const auto& connection_typed_metadata = - decoder_callbacks_->connection()->streamInfo().dynamicMetadata().typed_filter_metadata(); const auto& request_typed_metadata = decoder_callbacks_->streamInfo().dynamicMetadata().typed_filter_metadata(); for (const auto& context_key : config_->typedMetadataContextNamespaces()) { if (const auto metadata_it = request_typed_metadata.find(context_key); metadata_it != request_typed_metadata.end()) { (*metadata_context.mutable_typed_filter_metadata())[metadata_it->first] = metadata_it->second; - } else if (const auto metadata_it = connection_typed_metadata.find(context_key); - metadata_it != connection_typed_metadata.end()) { - (*metadata_context.mutable_typed_filter_metadata())[metadata_it->first] = metadata_it->second; + } else if (connection.has_value()) { + const auto& connection_typed_metadata = + connection->streamInfo().dynamicMetadata().typed_filter_metadata(); + const auto metadata_it = connection_typed_metadata.find(context_key); + if (metadata_it != connection_typed_metadata.end()) { + (*metadata_context.mutable_typed_filter_metadata())[metadata_it->first] = + metadata_it->second; + } } } @@ -156,7 +163,6 @@ Http::FilterDataStatus Filter::decodeData(Buffer::Instance& data, bool end_strea return Http::FilterDataStatus::StopIterationAndBuffer; } } - return Http::FilterDataStatus::Continue; } @@ -254,12 +260,15 @@ void Filter::onComplete(Filters::Common::ExtAuthz::ResponsePtr&& response) { switch (response->status) { case CheckStatus::OK: { // Any changes to request headers or query parameters can affect how the request is going to be - // routed. If we are changing the headers we also need to clear the route - // cache. + // routed. If we are changing the headers we also need to clear the route cache. + // + // clearRouteCache() should only be true if decoder_callbacks_->downstreamCallbacks() is also + // true, i.e. the filter is a downstream filter. if (config_->clearRouteCache() && (!response->headers_to_set.empty() || !response->headers_to_append.empty() || !response->headers_to_remove.empty() || !response->query_parameters_to_set.empty() || - !response->query_parameters_to_remove.empty())) { + !response->query_parameters_to_remove.empty()) && + decoder_callbacks_->downstreamCallbacks()) { ENVOY_STREAM_LOG(debug, "ext_authz is clearing route cache", *decoder_callbacks_); decoder_callbacks_->downstreamCallbacks()->clearRouteCache(); } diff --git a/source/extensions/filters/http/header_to_metadata/header_to_metadata_filter.cc b/source/extensions/filters/http/header_to_metadata/header_to_metadata_filter.cc index b61e5ecf92c0..b5030d4c8993 100644 --- a/source/extensions/filters/http/header_to_metadata/header_to_metadata_filter.cc +++ b/source/extensions/filters/http/header_to_metadata/header_to_metadata_filter.cc @@ -35,7 +35,7 @@ absl::optional HeaderValueSelector::extract(Http::HeaderMap& map) c absl::optional CookieValueSelector::extract(Http::HeaderMap& map) const { std::string value = Envoy::Http::Utility::parseCookieValue(map, cookie_); if (!value.empty()) { - return absl::optional(std::move(value)); + return {std::move(value)}; } return absl::nullopt; } diff --git a/source/extensions/filters/http/rate_limit_quota/filter.cc b/source/extensions/filters/http/rate_limit_quota/filter.cc index 5ebb3c3dfd3c..3624e68765e2 100644 --- a/source/extensions/filters/http/rate_limit_quota/filter.cc +++ b/source/extensions/filters/http/rate_limit_quota/filter.cc @@ -9,8 +9,6 @@ namespace Extensions { namespace HttpFilters { namespace RateLimitQuota { -using ::envoy::type::v3::RateLimitStrategy; - Http::FilterHeadersStatus RateLimitQuotaFilter::decodeHeaders(Http::RequestHeaderMap& headers, bool end_stream) { ENVOY_LOG(trace, "decodeHeaders: end_stream = {}", end_stream); diff --git a/source/extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl.cc b/source/extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl.cc index 5e6abdf9ba2b..3ac46bd5e50d 100644 --- a/source/extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl.cc +++ b/source/extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl.cc @@ -76,7 +76,7 @@ DubboHessian2SerializerImpl::deserializeRpcInvocation(Buffer::Instance& buffer, } }); - return std::pair(invo, true); + return {invo, true}; } std::pair @@ -125,7 +125,7 @@ DubboHessian2SerializerImpl::deserializeRpcResult(Buffer::Instance& buffer, (context->bodySize() - total_size))); } - return std::pair(result, true); + return {result, true}; } size_t DubboHessian2SerializerImpl::serializeRpcResult(Buffer::Instance& output_buffer, diff --git a/source/extensions/filters/network/dubbo_proxy/dubbo_protocol_impl.cc b/source/extensions/filters/network/dubbo_proxy/dubbo_protocol_impl.cc index d512c59f6d68..1e5318a792cb 100644 --- a/source/extensions/filters/network/dubbo_proxy/dubbo_protocol_impl.cc +++ b/source/extensions/filters/network/dubbo_proxy/dubbo_protocol_impl.cc @@ -89,7 +89,7 @@ DubboProtocolImpl::decodeHeader(Buffer::Instance& buffer, MessageMetadataSharedP } if (buffer.length() < DubboProtocolImpl::MessageSize) { - return std::pair(nullptr, false); + return {nullptr, false}; } uint16_t magic_number = buffer.peekBEInt(); @@ -130,7 +130,7 @@ DubboProtocolImpl::decodeHeader(Buffer::Instance& buffer, MessageMetadataSharedP context->setBodySize(body_size); context->setHeartbeat(is_event); - return std::pair(context, true); + return {context, true}; } bool DubboProtocolImpl::decodeData(Buffer::Instance& buffer, ContextSharedPtr context, diff --git a/source/extensions/filters/udp/udp_proxy/config.cc b/source/extensions/filters/udp/udp_proxy/config.cc index 570b71eb7248..49f4f8d68683 100644 --- a/source/extensions/filters/udp/udp_proxy/config.cc +++ b/source/extensions/filters/udp/udp_proxy/config.cc @@ -17,7 +17,7 @@ UdpProxyFilterConfigImpl::UdpProxyFilterConfigImpl( // Default prefer_gro to true for upstream client traffic. upstream_socket_config_(config.upstream_socket_config(), true), random_(context.api().randomGenerator()) { - if (use_per_packet_load_balancing_ && config.session_filters().size() > 0) { + if (use_per_packet_load_balancing_ && !config.session_filters().empty()) { throw EnvoyException( "Only one of use_per_packet_load_balancing or session_filters can be used."); } diff --git a/source/extensions/grpc_credentials/aws_iam/config.cc b/source/extensions/grpc_credentials/aws_iam/config.cc index 42f7f28a9c41..0a8f0bab9782 100644 --- a/source/extensions/grpc_credentials/aws_iam/config.cc +++ b/source/extensions/grpc_credentials/aws_iam/config.cc @@ -101,9 +101,7 @@ AwsIamHeaderAuthenticator::GetMetadata(grpc::string_ref service_url, grpc::strin absl::string_view(method_name.data(), method_name.length())); TRY_NEEDS_AUDIT { signer_->sign(message, false); } - END_TRY catch (const EnvoyException& e) { - return grpc::Status(grpc::StatusCode::INTERNAL, e.what()); - } + END_TRY catch (const EnvoyException& e) { return {grpc::StatusCode::INTERNAL, e.what()}; } signedHeadersToMetadata(message.headers(), *metadata); diff --git a/source/extensions/http/header_validators/envoy_default/http1_header_validator.cc b/source/extensions/http/header_validators/envoy_default/http1_header_validator.cc index d2b5a57fa43f..cf29b3e612b4 100644 --- a/source/extensions/http/header_validators/envoy_default/http1_header_validator.cc +++ b/source/extensions/http/header_validators/envoy_default/http1_header_validator.cc @@ -18,7 +18,6 @@ namespace EnvoyDefault { using ::envoy::extensions::http::header_validators::envoy_default::v3::HeaderValidatorConfig; using ::Envoy::Http::HeaderString; -using ::Envoy::Http::LowerCaseString; using ::Envoy::Http::Protocol; using ::Envoy::Http::RequestHeaderMap; using ::Envoy::Http::UhvResponseCodeDetail; diff --git a/source/extensions/io_socket/user_space/BUILD b/source/extensions/io_socket/user_space/BUILD index f54cf9b054cd..2a1b27d71174 100644 --- a/source/extensions/io_socket/user_space/BUILD +++ b/source/extensions/io_socket/user_space/BUILD @@ -11,7 +11,7 @@ envoy_extension_package() envoy_cc_extension( name = "config", - srcs = ["config.h"], + hdrs = ["config.h"], # for integration tests and bootstrap.internal_listener visibility = ["//visibility:public"], deps = [ diff --git a/source/extensions/listener_managers/listener_manager/connection_handler_impl.cc b/source/extensions/listener_managers/listener_manager/connection_handler_impl.cc index 65dd4fa686b9..073760cb9088 100644 --- a/source/extensions/listener_managers/listener_manager/connection_handler_impl.cc +++ b/source/extensions/listener_managers/listener_manager/connection_handler_impl.cc @@ -357,8 +357,7 @@ ConnectionHandlerImpl::getBalancedHandlerByAddress(const Network::Address::Insta if (auto listener_it = tcp_listener_map_by_address_.find(address.asStringView()); listener_it != tcp_listener_map_by_address_.end() && listener_it->second->listener_->listener() != nullptr) { - return Network::BalancedConnectionHandlerOptRef( - listener_it->second->tcpListener().value().get()); + return {listener_it->second->tcpListener().value().get()}; } OptRef details; diff --git a/source/extensions/listener_managers/listener_manager/listener_manager_impl.cc b/source/extensions/listener_managers/listener_manager/listener_manager_impl.cc index 3f1b8a5167b6..66f4f777d5aa 100644 --- a/source/extensions/listener_managers/listener_manager/listener_manager_impl.cc +++ b/source/extensions/listener_managers/listener_manager/listener_manager_impl.cc @@ -272,9 +272,8 @@ Network::ListenerFilterMatcherSharedPtr ProdListenerComponentFactory::createList if (!listener_filter.has_filter_disabled()) { return nullptr; } - return std::shared_ptr( - Network::ListenerFilterMatcherBuilder::buildListenerFilterMatcher( - listener_filter.filter_disabled())); + return {Network::ListenerFilterMatcherBuilder::buildListenerFilterMatcher( + listener_filter.filter_disabled())}; } Network::SocketSharedPtr ProdListenerComponentFactory::createListenSocket( diff --git a/source/extensions/stat_sinks/open_telemetry/open_telemetry_impl.cc b/source/extensions/stat_sinks/open_telemetry/open_telemetry_impl.cc index dbbd376faee5..78c533948cbe 100644 --- a/source/extensions/stat_sinks/open_telemetry/open_telemetry_impl.cc +++ b/source/extensions/stat_sinks/open_telemetry/open_telemetry_impl.cc @@ -14,7 +14,7 @@ OtlpOptions::OtlpOptions(const SinkConfig& sink_config) PROTOBUF_GET_WRAPPED_OR_DEFAULT(sink_config, emit_tags_as_attributes, true)), use_tag_extracted_name_( PROTOBUF_GET_WRAPPED_OR_DEFAULT(sink_config, use_tag_extracted_name, true)), - stat_prefix_(sink_config.prefix() != "" ? sink_config.prefix() + "." : "") {} + stat_prefix_(!sink_config.prefix().empty() ? sink_config.prefix() + "." : "") {} OpenTelemetryGrpcMetricsExporterImpl::OpenTelemetryGrpcMetricsExporterImpl( const OtlpOptionsSharedPtr config, Grpc::RawAsyncClientSharedPtr raw_async_client) diff --git a/source/extensions/tracers/xray/localized_sampling.cc b/source/extensions/tracers/xray/localized_sampling.cc index 551ebfe66b9d..5126545b1736 100644 --- a/source/extensions/tracers/xray/localized_sampling.cc +++ b/source/extensions/tracers/xray/localized_sampling.cc @@ -31,8 +31,8 @@ void fail(absl::string_view msg) { ENVOY_LOG_TO_LOGGER(logger, error, "Failed to parse sampling rules - {}", msg); } -bool is_valid_rate(double n) { return n >= 0 && n <= 1.0; } -bool is_valid_fixed_target(double n) { return n >= 0 && static_cast(n) == n; } +bool isValidRate(double n) { return n >= 0 && n <= 1.0; } +bool isValidFixedTarget(double n) { return n >= 0 && static_cast(n) == n; } bool validateRule(const ProtobufWkt::Struct& rule) { using ProtobufWkt::Value; @@ -61,7 +61,7 @@ bool validateRule(const ProtobufWkt::Struct& rule) { const auto fixed_target_it = rule.fields().find(FixedTargetJsonKey); if (fixed_target_it == rule.fields().end() || fixed_target_it->second.kind_case() != Value::KindCase::kNumberValue || - !is_valid_fixed_target(fixed_target_it->second.number_value())) { + !isValidFixedTarget(fixed_target_it->second.number_value())) { fail("fixed target is missing or not a valid positive integer"); return false; } @@ -69,7 +69,7 @@ bool validateRule(const ProtobufWkt::Struct& rule) { const auto rate_it = rule.fields().find(RateJsonKey); if (rate_it == rule.fields().end() || rate_it->second.kind_case() != Value::KindCase::kNumberValue || - !is_valid_rate(rate_it->second.number_value())) { + !isValidRate(rate_it->second.number_value())) { fail("rate is missing or not a valid positive floating number"); return false; } diff --git a/source/extensions/tracers/zipkin/span_context_extractor.cc b/source/extensions/tracers/zipkin/span_context_extractor.cc index d51833f2e8b4..7ab3eb92af5f 100644 --- a/source/extensions/tracers/zipkin/span_context_extractor.cc +++ b/source/extensions/tracers/zipkin/span_context_extractor.cc @@ -135,7 +135,7 @@ SpanContextExtractor::extractSpanContextFromB3SingleFormat(bool is_sampled) { if (b3.length() == 1) { // possibly sampling flags if (validSamplingFlags(b3[0])) { - return std::pair(SpanContext(), false); + return {SpanContext(), false}; } throw ExtractorException(fmt::format("Invalid input: invalid sampling flag {}", b3[0])); } diff --git a/source/extensions/transport_sockets/proxy_protocol/proxy_protocol.cc b/source/extensions/transport_sockets/proxy_protocol/proxy_protocol.cc index 537483186b21..9ce25ebaea7c 100644 --- a/source/extensions/transport_sockets/proxy_protocol/proxy_protocol.cc +++ b/source/extensions/transport_sockets/proxy_protocol/proxy_protocol.cc @@ -21,7 +21,7 @@ namespace Extensions { namespace TransportSockets { namespace ProxyProtocol { -UpstreamProxyProtocolStats GenerateUpstreamProxyProtocolStats(Stats::Scope& stats_scope) { +UpstreamProxyProtocolStats generateUpstreamProxyProtocolStats(Stats::Scope& stats_scope) { const char prefix[]{"upstream.proxyprotocol."}; return {ALL_PROXY_PROTOCOL_TRANSPORT_SOCKET_STATS(POOL_COUNTER_PREFIX(stats_scope, prefix))}; } @@ -31,7 +31,7 @@ UpstreamProxyProtocolSocket::UpstreamProxyProtocolSocket( Network::TransportSocketOptionsConstSharedPtr options, ProxyProtocolConfig config, Stats::Scope& scope) : PassthroughSocket(std::move(transport_socket)), options_(options), version_(config.version()), - stats_(GenerateUpstreamProxyProtocolStats(scope)), + stats_(generateUpstreamProxyProtocolStats(scope)), pass_all_tlvs_(config.has_pass_through_tlvs() ? config.pass_through_tlvs().match_type() == ProxyProtocolPassThroughTLVs::INCLUDE_ALL : false) { diff --git a/source/extensions/transport_sockets/tls/context_config_impl.cc b/source/extensions/transport_sockets/tls/context_config_impl.cc index 76578b62b6fe..2fdf9c5ba8ab 100644 --- a/source/extensions/transport_sockets/tls/context_config_impl.cc +++ b/source/extensions/transport_sockets/tls/context_config_impl.cc @@ -401,6 +401,7 @@ ServerContextConfigImpl::ServerContextConfigImpl( ocsp_staple_policy_(ocspStaplePolicyFromProto(config.ocsp_staple_policy())), session_ticket_keys_provider_(getTlsSessionTicketKeysConfigProvider(factory_context, config)), disable_stateless_session_resumption_(getStatelessSessionResumptionDisabled(config)), + disable_stateful_session_resumption_(config.disable_stateful_session_resumption()), full_scan_certs_on_sni_mismatch_(PROTOBUF_GET_WRAPPED_OR_DEFAULT( config, full_scan_certs_on_sni_mismatch, !Runtime::runtimeFeatureEnabled( diff --git a/source/extensions/transport_sockets/tls/context_config_impl.h b/source/extensions/transport_sockets/tls/context_config_impl.h index 3cb896fbbeb5..25ba093be9d7 100644 --- a/source/extensions/transport_sockets/tls/context_config_impl.h +++ b/source/extensions/transport_sockets/tls/context_config_impl.h @@ -165,6 +165,9 @@ class ServerContextConfigImpl : public ContextConfigImpl, public Envoy::Ssl::Ser bool disableStatelessSessionResumption() const override { return disable_stateless_session_resumption_; } + bool disableStatefulSessionResumption() const override { + return disable_stateful_session_resumption_; + } bool fullScanCertsOnSNIMismatch() const override { return full_scan_certs_on_sni_mismatch_; } @@ -190,6 +193,7 @@ class ServerContextConfigImpl : public ContextConfigImpl, public Envoy::Ssl::Ser absl::optional session_timeout_; const bool disable_stateless_session_resumption_; + const bool disable_stateful_session_resumption_; bool full_scan_certs_on_sni_mismatch_; }; diff --git a/source/extensions/transport_sockets/tls/context_impl.cc b/source/extensions/transport_sockets/tls/context_impl.cc index d68219c23ef6..9ffb716f17a5 100644 --- a/source/extensions/transport_sockets/tls/context_impl.cc +++ b/source/extensions/transport_sockets/tls/context_impl.cc @@ -854,6 +854,10 @@ ServerContextImpl::ServerContextImpl(Stats::Scope& scope, }); } + if (config.disableStatefulSessionResumption()) { + SSL_CTX_set_session_cache_mode(ctx.ssl_ctx_.get(), SSL_SESS_CACHE_OFF); + } + if (config.sessionTimeout() && !config.capabilities().handles_session_resumption) { auto timeout = config.sessionTimeout().value().count(); SSL_CTX_set_timeout(ctx.ssl_ctx_.get(), uint32_t(timeout)); diff --git a/source/extensions/transport_sockets/tls/ocsp/ocsp.cc b/source/extensions/transport_sockets/tls/ocsp/ocsp.cc index 14070a8b0064..76063188b7f7 100644 --- a/source/extensions/transport_sockets/tls/ocsp/ocsp.cc +++ b/source/extensions/transport_sockets/tls/ocsp/ocsp.cc @@ -278,9 +278,7 @@ ResponseData Asn1OcspUtility::parseResponseData(CBS& cbs) { skipResponderId(elem); unwrap(Asn1Utility::skip(elem, CBS_ASN1_GENERALIZEDTIME)); auto responses = unwrap(Asn1Utility::parseSequenceOf( - elem, [](CBS& cbs) -> ParsingResult { - return ParsingResult(parseSingleResponse(cbs)); - })); + elem, [](CBS& cbs) -> ParsingResult { return {parseSingleResponse(cbs)}; })); // Extensions currently ignored. return {std::move(responses)}; diff --git a/source/extensions/transport_sockets/tls/utility.cc b/source/extensions/transport_sockets/tls/utility.cc index 2219998916de..9820f91c2d17 100644 --- a/source/extensions/transport_sockets/tls/utility.cc +++ b/source/extensions/transport_sockets/tls/utility.cc @@ -130,12 +130,12 @@ std::string getRFC2253NameFromCertificate(X509& cert, CertName desired_name) { size_t data_len; int rc = BIO_mem_contents(buf.get(), &data, &data_len); ASSERT(rc == 1); - return std::string(reinterpret_cast(data), data_len); + return {reinterpret_cast(data), data_len}; } } // namespace -const ASN1_TIME& epochASN1_Time() { +const ASN1_TIME& epochASN1Time() { static ASN1_TIME* e = []() -> ASN1_TIME* { ASN1_TIME* epoch = ASN1_TIME_new(); const time_t epoch_time = 0; @@ -145,7 +145,7 @@ const ASN1_TIME& epochASN1_Time() { return *e; } -inline bssl::UniquePtr currentASN1_Time(TimeSource& time_source) { +inline bssl::UniquePtr currentASN1Time(TimeSource& time_source) { bssl::UniquePtr current_asn_time(ASN1_TIME_new()); const time_t current_time = std::chrono::system_clock::to_time_t(time_source.systemTime()); RELEASE_ASSERT(ASN1_TIME_set(current_asn_time.get(), current_time) != nullptr, ""); @@ -238,7 +238,7 @@ absl::optional Utility::getDaysUntilExpiration(const X509* cert, return absl::make_optional(std::numeric_limits::max()); } int days, seconds; - if (ASN1_TIME_diff(&days, &seconds, currentASN1_Time(time_source).get(), + if (ASN1_TIME_diff(&days, &seconds, currentASN1Time(time_source).get(), X509_get0_notAfter(cert))) { if (days >= 0 && seconds >= 0) { return absl::make_optional(days); @@ -279,7 +279,7 @@ absl::string_view Utility::getCertificateExtensionValue(X509& cert, SystemTime Utility::getValidFrom(const X509& cert) { int days, seconds; - int rc = ASN1_TIME_diff(&days, &seconds, &epochASN1_Time(), X509_get0_notBefore(&cert)); + int rc = ASN1_TIME_diff(&days, &seconds, &epochASN1Time(), X509_get0_notBefore(&cert)); ASSERT(rc == 1); // Casting to to prevent multiplication overflow when certificate valid-from date // beyond 2038-01-19T03:14:08Z. @@ -288,7 +288,7 @@ SystemTime Utility::getValidFrom(const X509& cert) { SystemTime Utility::getExpirationTime(const X509& cert) { int days, seconds; - int rc = ASN1_TIME_diff(&days, &seconds, &epochASN1_Time(), X509_get0_notAfter(&cert)); + int rc = ASN1_TIME_diff(&days, &seconds, &epochASN1Time(), X509_get0_notAfter(&cert)); ASSERT(rc == 1); // Casting to to prevent multiplication overflow when certificate not-after date // beyond 2038-01-19T03:14:08Z. diff --git a/source/server/guarddog_impl.cc b/source/server/guarddog_impl.cc index 13373b080cb5..b3e2e1ebb29d 100644 --- a/source/server/guarddog_impl.cc +++ b/source/server/guarddog_impl.cc @@ -163,6 +163,8 @@ void GuardDogImpl::step() { multi_kill_threads.emplace_back(tid, last_checkin); if (multi_kill_threads.size() >= required_for_multi_kill) { + ENVOY_LOG_MISC(error, "Watchdog MULTIKILL as {} threads are stuck.", + multi_kill_threads.size()); invokeGuardDogActions(WatchDogAction::MULTIKILL, multi_kill_threads, now); } } diff --git a/source/server/server.h b/source/server/server.h index 923e68fae141..f5c43f9bfbf8 100644 --- a/source/server/server.h +++ b/source/server/server.h @@ -193,6 +193,7 @@ class ServerFactoryContextImpl : public Configuration::ServerFactoryContext, TimeSource& timeSource() override { return api().timeSource(); } AccessLog::AccessLogManager& accessLogManager() override { return server_.accessLogManager(); } Api::Api& api() override { return server_.api(); } + Http::Context& httpContext() override { return server_.httpContext(); } Grpc::Context& grpcContext() override { return server_.grpcContext(); } Router::Context& routerContext() override { return server_.routerContext(); } Envoy::Server::DrainManager& drainManager() override { return server_.drainManager(); } diff --git a/test/extensions/filters/common/ext_authz/check_request_utils_test.cc b/test/extensions/filters/common/ext_authz/check_request_utils_test.cc index 83674fc8f177..6c32477ba9b0 100644 --- a/test/extensions/filters/common/ext_authz/check_request_utils_test.cc +++ b/test/extensions/filters/common/ext_authz/check_request_utils_test.cc @@ -38,7 +38,6 @@ class CheckRequestUtilsTest : public testing::Test { void expectBasicHttp() { EXPECT_CALL(callbacks_, connection()) - .Times(2) .WillRepeatedly(Return(OptRef{connection_})); connection_.stream_info_.downstream_connection_info_provider_->setRemoteAddress(addr_); connection_.stream_info_.downstream_connection_info_provider_->setLocalAddress(addr_); @@ -201,6 +200,37 @@ TEST_F(CheckRequestUtilsTest, BasicHttp) { EXPECT_TRUE(request_.attributes().request().has_time()); } +// Certain connection-specific attributes cannot be included when there is no connection, even if +// include_peer_certificate or include_tls_session are true. +TEST_F(CheckRequestUtilsTest, BasicHttpWithNoConnection) { + const uint64_t size = 0; + envoy::service::auth::v3::CheckRequest request_; + + Http::TestRequestHeaderMapImpl request_headers{{Headers::get().EnvoyAuthPartialBody.get(), "1"}}; + EXPECT_CALL(callbacks_, connection()).WillRepeatedly(Return(std::nullopt)); + EXPECT_CALL(callbacks_, streamId()).WillOnce(Return(0)); + EXPECT_CALL(callbacks_, decodingBuffer()).WillOnce(Return(buffer_.get())); + EXPECT_CALL(callbacks_, streamInfo()).WillOnce(ReturnRef(req_info_)); + EXPECT_CALL(req_info_, protocol()).Times(2).WillRepeatedly(ReturnPointee(&protocol_)); + EXPECT_CALL(req_info_, startTime()).WillOnce(Return(SystemTime())); + + CheckRequestUtils::createHttpCheck( + &callbacks_, request_headers, Protobuf::Map(), + envoy::config::core::v3::Metadata(), request_, size, + /*pack_as_bytes=*/false, /*include_peer_certificate=*/true, + /*include_tls_session=*/true, Protobuf::Map(), nullptr); + + ASSERT_EQ(size, request_.attributes().request().http().body().size()); + EXPECT_EQ(buffer_->toString().substr(0, size), request_.attributes().request().http().body()); + EXPECT_EQ(request_.attributes().request().http().headers().end(), + request_.attributes().request().http().headers().find( + Headers::get().EnvoyAuthPartialBody.get())); + EXPECT_EQ(0, request_.attributes().source().principal().size()); + EXPECT_EQ(0, request_.attributes().destination().principal().size()); + EXPECT_EQ(0, request_.attributes().source().service().size()); + EXPECT_EQ(0, request_.attributes().source().certificate().size()); +} + // Verify that check request merges the duplicate headers. TEST_F(CheckRequestUtilsTest, BasicHttpWithDuplicateHeaders) { const uint64_t size = 0; @@ -351,7 +381,6 @@ TEST_F(CheckRequestUtilsTest, CheckAttrContextPeer) { {":path", "/bar"}}; envoy::service::auth::v3::CheckRequest request; EXPECT_CALL(callbacks_, connection()) - .Times(2) .WillRepeatedly(Return(OptRef{connection_})); connection_.stream_info_.downstream_connection_info_provider_->setRemoteAddress(addr_); connection_.stream_info_.downstream_connection_info_provider_->setLocalAddress(addr_); @@ -430,7 +459,6 @@ TEST_F(CheckRequestUtilsTest, CheckAttrContextPeerCertificate) { // Verify that the SNI is populated correctly. TEST_F(CheckRequestUtilsTest, CheckAttrContextPeerTLSSession) { EXPECT_CALL(callbacks_, connection()) - .Times(5) .WillRepeatedly(Return(OptRef{connection_})); connection_.stream_info_.downstream_connection_info_provider_->setRemoteAddress(addr_); connection_.stream_info_.downstream_connection_info_provider_->setLocalAddress(addr_); @@ -454,7 +482,6 @@ TEST_F(CheckRequestUtilsTest, CheckAttrContextPeerTLSSession) { // Verify that the SNI is populated correctly. TEST_F(CheckRequestUtilsTest, CheckAttrContextPeerTLSSessionWithoutSNI) { EXPECT_CALL(callbacks_, connection()) - .Times(4) .WillRepeatedly(Return(OptRef{connection_})); connection_.stream_info_.downstream_connection_info_provider_->setRemoteAddress(addr_); connection_.stream_info_.downstream_connection_info_provider_->setLocalAddress(addr_); diff --git a/test/extensions/filters/http/ext_authz/config_test.cc b/test/extensions/filters/http/ext_authz/config_test.cc index 2eddc7f01cec..f1778c19d56a 100644 --- a/test/extensions/filters/http/ext_authz/config_test.cc +++ b/test/extensions/filters/http/ext_authz/config_test.cc @@ -63,7 +63,7 @@ class ExtAuthzFilterTest : public Event::TestUsingSimulatedTime, const envoy::extensions::filters::http::ext_authz::v3::ExtAuthz& ext_authz_config) { // Delegate call to mock async client manager to real async client manager. ON_CALL(context_, getServerFactoryContext()).WillByDefault(testing::ReturnRef(server_context_)); - ON_CALL(context_.cluster_manager_.async_client_manager_, + ON_CALL(server_context_.cluster_manager_.async_client_manager_, getOrCreateRawAsyncClientWithHashKey(_, _, _)) .WillByDefault( Invoke([&](const Envoy::Grpc::GrpcServiceConfigWithHashKey& config_with_hash_key, @@ -71,7 +71,7 @@ class ExtAuthzFilterTest : public Event::TestUsingSimulatedTime, return async_client_manager_->getOrCreateRawAsyncClientWithHashKey( config_with_hash_key, scope, skip_cluster_check); })); - ExtAuthzFilterConfig factory; + ExtAuthzFilterFactory factory; return factory.createFilterFactoryFromProto(ext_authz_config, "stats", context_); } @@ -94,6 +94,29 @@ class ExtAuthzFilterTest : public Event::TestUsingSimulatedTime, std::unique_ptr async_client_manager_; }; +TEST_F(ExtAuthzFilterTest, DisallowedConfigurationFieldsAsUpstreamFilter) { + NiceMock context; + NiceMock server_context; + ON_CALL(context, getServerFactoryContext()).WillByDefault(testing::ReturnRef(server_context)); + + ExtAuthzFilterFactory factory; + envoy::extensions::filters::http::ext_authz::v3::ExtAuthz ext_authz_config; + ext_authz_config.set_transport_api_version(envoy::config::core::v3::ApiVersion::V3); + ext_authz_config.set_clear_route_cache(true); + EXPECT_THROW(factory.createFilterFactoryFromProto(ext_authz_config, "stats", context), + EnvoyException); + + ext_authz_config.set_clear_route_cache(false); + ext_authz_config.set_include_peer_certificate(true); + EXPECT_THROW(factory.createFilterFactoryFromProto(ext_authz_config, "stats", context), + EnvoyException); + + ext_authz_config.set_include_peer_certificate(false); + ext_authz_config.set_include_tls_session(true); + EXPECT_THROW(factory.createFilterFactoryFromProto(ext_authz_config, "stats", context), + EnvoyException); +} + class ExtAuthzFilterHttpTest : public ExtAuthzFilterTest { public: void testFilterFactory(const std::string& ext_authz_config_yaml) { diff --git a/test/extensions/filters/http/ext_authz/ext_authz_integration_test.cc b/test/extensions/filters/http/ext_authz/ext_authz_integration_test.cc index e5f9a74b1a35..863d0e3a2f00 100644 --- a/test/extensions/filters/http/ext_authz/ext_authz_integration_test.cc +++ b/test/extensions/filters/http/ext_authz/ext_authz_integration_test.cc @@ -16,32 +16,60 @@ #include "gtest/gtest.h" using testing::AssertionResult; +using testing::Combine; using testing::Not; +using testing::TestParamInfo; using testing::TestWithParam; using testing::ValuesIn; namespace Envoy { +namespace { + +std::string +testParamsToString(const TestParamInfo>& params) { + return fmt::format("{}_{}", + TestUtility::ipTestParamsToString( + TestParamInfo(std::get<0>(params.param), 0)), + std::get<1>(params.param) ? "as_downstream_filter" : "as_upstream_filter"); +} + +} // namespace + using Headers = std::vector>; -class ExtAuthzGrpcIntegrationTest : public Grpc::GrpcClientIntegrationParamTest, - public HttpIntegrationTest { +class ExtAuthzGrpcIntegrationTest + : public Grpc::BaseGrpcClientIntegrationParamTest, + public TestWithParam>, + public HttpIntegrationTest { public: ExtAuthzGrpcIntegrationTest() : HttpIntegrationTest(Http::CodecType::HTTP1, ipVersion()) {} + static std::string protocolTestParamsToString( + const TestParamInfo>& + params) { + return fmt::format("{}_{}_{}", TestUtility::ipVersionToString(std::get<0>(params.param)), + std::get<1>(params.param) == Grpc::ClientType::GoogleGrpc ? "GoogleGrpc" + : "EnvoyGrpc", + std::get<2>(params.param) ? "as_downstream_filter" : "as_upstream_filter"); + } + void createUpstreams() override { HttpIntegrationTest::createUpstreams(); addFakeUpstream(Http::CodecType::HTTP2); } + Network::Address::IpVersion ipVersion() const override { return std::get<0>(GetParam()); } + Grpc::ClientType clientType() const override { return std::get<1>(GetParam()); } + bool usingDownstreamFilter() { return std::get<2>(GetParam()); } + void initializeConfig(bool disable_with_metadata = false, bool failure_mode_allow = false) { + if (!usingDownstreamFilter()) { + // Need to set upstream protocol options. + setUpstreamProtocol(Http::CodecType::HTTP1); + } config_helper_.addConfigModifier([this, disable_with_metadata, failure_mode_allow]( envoy::config::bootstrap::v3::Bootstrap& bootstrap) { - auto* ext_authz_cluster = bootstrap.mutable_static_resources()->add_clusters(); - ext_authz_cluster->MergeFrom(bootstrap.static_resources().clusters()[0]); - ext_authz_cluster->set_name("ext_authz_cluster"); - ConfigHelper::setHttp2(*ext_authz_cluster); - TestUtility::loadFromYaml(base_filter_config_, proto_config_); setGrpcService(*proto_config_.mutable_grpc_service(), "ext_authz_cluster", fake_upstreams_.back()->localAddress()); @@ -82,7 +110,17 @@ class ExtAuthzGrpcIntegrationTest : public Grpc::GrpcClientIntegrationParamTest, envoy::config::listener::v3::Filter ext_authz_filter; ext_authz_filter.set_name("envoy.filters.http.ext_authz"); ext_authz_filter.mutable_typed_config()->PackFrom(proto_config_); - config_helper_.prependFilter(MessageUtil::getJsonStringFromMessageOrError(ext_authz_filter)); + config_helper_.prependFilter(MessageUtil::getJsonStringFromMessageOrError(ext_authz_filter), + /*downstream_filter=*/usingDownstreamFilter()); + + auto* ext_authz_cluster = bootstrap.mutable_static_resources()->add_clusters(); + ext_authz_cluster->MergeFrom(bootstrap.static_resources().clusters()[0]); + ext_authz_cluster->set_name("ext_authz_cluster"); + // Don't configure ext_authz_cluster to require a check call to ext_authz_cluster. + if (!usingDownstreamFilter()) { + ext_authz_cluster->clear_typed_extension_protocol_options(); + } + ConfigHelper::setHttp2(*ext_authz_cluster); }); } @@ -472,10 +510,14 @@ class ExtAuthzGrpcIntegrationTest : public Grpc::GrpcClientIntegrationParamTest, )EOF"; }; -class ExtAuthzHttpIntegrationTest : public HttpIntegrationTest, - public TestWithParam { +class ExtAuthzHttpIntegrationTest + : public HttpIntegrationTest, + public TestWithParam> { public: - ExtAuthzHttpIntegrationTest() : HttpIntegrationTest(Http::CodecType::HTTP1, GetParam()) {} + ExtAuthzHttpIntegrationTest() + : HttpIntegrationTest(Http::CodecType::HTTP1, std::get<0>(GetParam())) {} + + bool usingDownstreamFilter() { return std::get<1>(GetParam()); } void createUpstreams() override { HttpIntegrationTest::createUpstreams(); @@ -574,12 +616,12 @@ class ExtAuthzHttpIntegrationTest : public HttpIntegrationTest, } void initializeConfig(bool legacy_allowed_headers = true) { + if (!usingDownstreamFilter()) { + // Need to set upstream protocol options. + setUpstreamProtocol(Http::CodecType::HTTP1); + } config_helper_.addConfigModifier([this, legacy_allowed_headers]( envoy::config::bootstrap::v3::Bootstrap& bootstrap) { - auto* ext_authz_cluster = bootstrap.mutable_static_resources()->add_clusters(); - ext_authz_cluster->MergeFrom(bootstrap.static_resources().clusters()[0]); - ext_authz_cluster->set_name("ext_authz"); - if (legacy_allowed_headers) { TestUtility::loadFromYaml(legacy_default_config_, proto_config_); } else { @@ -589,7 +631,16 @@ class ExtAuthzHttpIntegrationTest : public HttpIntegrationTest, ext_authz_filter.set_name("envoy.filters.http.ext_authz"); ext_authz_filter.mutable_typed_config()->PackFrom(proto_config_); - config_helper_.prependFilter(MessageUtil::getJsonStringFromMessageOrError(ext_authz_filter)); + config_helper_.prependFilter(MessageUtil::getJsonStringFromMessageOrError(ext_authz_filter), + /*downstream_filter=*/usingDownstreamFilter()); + + auto* ext_authz_cluster = bootstrap.mutable_static_resources()->add_clusters(); + ext_authz_cluster->MergeFrom(bootstrap.static_resources().clusters()[0]); + ext_authz_cluster->set_name("ext_authz"); + // Don't configure ext_authz_cluster to require a check call to ext_authz_cluster. + if (!usingDownstreamFilter()) { + ext_authz_cluster->clear_typed_extension_protocol_options(); + } }); } @@ -718,8 +769,10 @@ class ExtAuthzHttpIntegrationTest : public HttpIntegrationTest, }; INSTANTIATE_TEST_SUITE_P(IpVersionsCientType, ExtAuthzGrpcIntegrationTest, - GRPC_CLIENT_INTEGRATION_PARAMS, - Grpc::GrpcClientIntegrationParamTest::protocolTestParamsToString); + Combine(ValuesIn(TestEnvironment::getIpVersionsForTest()), + ValuesIn(TestEnvironment::getsGrpcVersionsForTest()), + testing::Bool()), + ExtAuthzGrpcIntegrationTest::protocolTestParamsToString); // Verifies that the request body is included in the CheckRequest when the downstream protocol is // HTTP/1.1. @@ -829,6 +882,41 @@ TEST_P(ExtAuthzGrpcIntegrationTest, CheckAfterBufferingComplete) { cleanup(); } +TEST_P(ExtAuthzGrpcIntegrationTest, Shadow) { + config_helper_.addConfigModifier( + [](envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager& + hcm) { + auto* virtual_hosts = hcm.mutable_route_config()->mutable_virtual_hosts(0); + auto* request_mirror_policies = + virtual_hosts->mutable_routes(0)->mutable_route()->add_request_mirror_policies(); + request_mirror_policies->set_cluster(virtual_hosts->routes(0).route().cluster()); + }); + + // Set up ext_authz filter. + initializeConfig(); + + // Use h1, set up the test. + setDownstreamProtocol(Http::CodecType::HTTP1); + HttpIntegrationTest::initialize(); + + // Start a client connection and start request. + Http::TestRequestHeaderMapImpl headers{ + {":method", "POST"}, {":path", "/test"}, {":scheme", "http"}, {":authority", "host"}}; + + initiateClientConnection(0); + waitForExtAuthzRequest(expectedCheckRequest(Http::CodecType::HTTP1)); + sendExtAuthzResponse(Headers{}, Headers{}, Headers{}, Http::TestRequestHeaderMapImpl{}, + Http::TestRequestHeaderMapImpl{}, Headers{}, Headers{}); + + waitForSuccessfulUpstreamResponse("200"); + + const std::string expected_body(response_size_, 'a'); + verifyResponse(std::move(response_), "200", Http::TestResponseHeaderMapImpl{{":status", "200"}}, + expected_body); + + cleanup(); +} + TEST_P(ExtAuthzGrpcIntegrationTest, DownstreamHeadersOnSuccess) { // Set up ext_authz filter. initializeConfig(); @@ -926,8 +1014,9 @@ TEST_P(ExtAuthzGrpcIntegrationTest, FailureModeAllowNonUtf8) { } INSTANTIATE_TEST_SUITE_P(IpVersions, ExtAuthzHttpIntegrationTest, - ValuesIn(TestEnvironment::getIpVersionsForTest()), - TestUtility::ipTestParamsToString); + Combine(ValuesIn(TestEnvironment::getIpVersionsForTest()), + testing::Bool()), + testParamsToString); // Verifies that by default HTTP service uses the case-sensitive string matcher // (uses legacy config for allowed_headers). @@ -939,7 +1028,7 @@ TEST_P(ExtAuthzHttpIntegrationTest, } // (uses legacy config for allowed_headers). -TEST_P(ExtAuthzHttpIntegrationTest, DEPRECATED_FEATURE_TEST(LegacyDirectReponse)) { +TEST_P(ExtAuthzHttpIntegrationTest, DEPRECATED_FEATURE_TEST(LegacyDirectResponse)) { config_helper_.addConfigModifier( [](envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager& hcm) { @@ -952,7 +1041,9 @@ TEST_P(ExtAuthzHttpIntegrationTest, DEPRECATED_FEATURE_TEST(LegacyDirectReponse) initializeConfig(); HttpIntegrationTest::initialize(); initiateClientConnection(); - waitForExtAuthzRequest(); + if (usingDownstreamFilter()) { + waitForExtAuthzRequest(); + } ASSERT_TRUE(response_->waitForEndStream()); EXPECT_TRUE(response_->complete()); @@ -973,7 +1064,9 @@ TEST_P(ExtAuthzHttpIntegrationTest, DEPRECATED_FEATURE_TEST(LegacyRedirectRespon initializeConfig(); HttpIntegrationTest::initialize(); initiateClientConnection(); - waitForExtAuthzRequest(); + if (usingDownstreamFilter()) { + waitForExtAuthzRequest(); + } ASSERT_TRUE(response_->waitForEndStream()); EXPECT_TRUE(response_->complete()); @@ -1027,7 +1120,7 @@ TEST_P(ExtAuthzHttpIntegrationTest, BodyNonUtf8) { } // (uses new config for allowed_headers). -TEST_P(ExtAuthzHttpIntegrationTest, DirectReponse) { +TEST_P(ExtAuthzHttpIntegrationTest, DirectResponse) { config_helper_.addConfigModifier( [](envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager& hcm) { @@ -1040,7 +1133,9 @@ TEST_P(ExtAuthzHttpIntegrationTest, DirectReponse) { initializeConfig(false); HttpIntegrationTest::initialize(); initiateClientConnection(); - waitForExtAuthzRequest(); + if (usingDownstreamFilter()) { + waitForExtAuthzRequest(); + } ASSERT_TRUE(response_->waitForEndStream()); EXPECT_TRUE(response_->complete()); @@ -1061,7 +1156,9 @@ TEST_P(ExtAuthzHttpIntegrationTest, RedirectResponse) { initializeConfig(false); HttpIntegrationTest::initialize(); initiateClientConnection(); - waitForExtAuthzRequest(); + if (usingDownstreamFilter()) { + waitForExtAuthzRequest(); + } ASSERT_TRUE(response_->waitForEndStream()); EXPECT_TRUE(response_->complete()); @@ -1069,10 +1166,14 @@ TEST_P(ExtAuthzHttpIntegrationTest, RedirectResponse) { EXPECT_EQ("http://host/redirect", response_->headers().getLocationValue()); } -class ExtAuthzLocalReplyIntegrationTest : public HttpIntegrationTest, - public TestWithParam { +class ExtAuthzLocalReplyIntegrationTest + : public HttpIntegrationTest, + public TestWithParam> { public: - ExtAuthzLocalReplyIntegrationTest() : HttpIntegrationTest(Http::CodecType::HTTP1, GetParam()) {} + ExtAuthzLocalReplyIntegrationTest() + : HttpIntegrationTest(Http::CodecType::HTTP1, std::get<0>(GetParam())) {} + + bool usingDownstreamFilter() { return std::get<1>(GetParam()); } void createUpstreams() override { HttpIntegrationTest::createUpstreams(); @@ -1093,8 +1194,9 @@ class ExtAuthzLocalReplyIntegrationTest : public HttpIntegrationTest, }; INSTANTIATE_TEST_SUITE_P(IpVersions, ExtAuthzLocalReplyIntegrationTest, - ValuesIn(TestEnvironment::getIpVersionsForTest()), - TestUtility::ipTestParamsToString); + Combine(ValuesIn(TestEnvironment::getIpVersionsForTest()), + testing::Bool()), + testParamsToString); // This integration test uses ext_authz combined with `local_reply_config`. // * If ext_authz response status is 401; its response headers and body are sent to the client. @@ -1103,11 +1205,11 @@ INSTANTIATE_TEST_SUITE_P(IpVersions, ExtAuthzLocalReplyIntegrationTest, // This integration test verifies that content-type and content-length generated // from `local_reply_config` are not overridden by ext_authz response. TEST_P(ExtAuthzLocalReplyIntegrationTest, DeniedHeaderTest) { + if (!usingDownstreamFilter()) { + // Need to set upstream protocol options. + setUpstreamProtocol(Http::CodecType::HTTP1); + } config_helper_.addConfigModifier([this](envoy::config::bootstrap::v3::Bootstrap& bootstrap) { - auto* ext_authz_cluster = bootstrap.mutable_static_resources()->add_clusters(); - ext_authz_cluster->MergeFrom(bootstrap.static_resources().clusters()[0]); - ext_authz_cluster->set_name("ext_authz"); - envoy::extensions::filters::http::ext_authz::v3::ExtAuthz proto_config; const std::string ext_authz_config = R"EOF( transport_api_version: V3 @@ -1122,7 +1224,16 @@ TEST_P(ExtAuthzLocalReplyIntegrationTest, DeniedHeaderTest) { envoy::config::listener::v3::Filter ext_authz_filter; ext_authz_filter.set_name("envoy.filters.http.ext_authz"); ext_authz_filter.mutable_typed_config()->PackFrom(proto_config); - config_helper_.prependFilter(MessageUtil::getJsonStringFromMessageOrError(ext_authz_filter)); + config_helper_.prependFilter(MessageUtil::getJsonStringFromMessageOrError(ext_authz_filter), + /*downstream_filter=*/usingDownstreamFilter()); + + auto* ext_authz_cluster = bootstrap.mutable_static_resources()->add_clusters(); + ext_authz_cluster->MergeFrom(bootstrap.static_resources().clusters()[0]); + ext_authz_cluster->set_name("ext_authz"); + // Don't configure ext_authz_cluster to require a check call to ext_authz_cluster. + if (!usingDownstreamFilter()) { + ext_authz_cluster->clear_typed_extension_protocol_options(); + } }); const std::string local_reply_yaml = R"EOF( @@ -1192,13 +1303,16 @@ TEST_P(ExtAuthzGrpcIntegrationTest, GoogleAsyncClientCreation) { sendExtAuthzResponse(Headers{}, Headers{}, Headers{}, Http::TestRequestHeaderMapImpl{}, Http::TestRequestHeaderMapImpl{}, Headers{}); + std::string creation_stat_name = + usingDownstreamFilter() + ? "grpc.ext_authz_cluster.google_grpc_client_creation" + : "cluster.cluster_0.grpc.ext_authz_cluster.google_grpc_client_creation"; if (clientType() == Grpc::ClientType::GoogleGrpc) { // Make sure Google grpc client is created before the request coming in. // Since this is not laziness creation, it should create one client per // thread before the traffic comes. - expected_grpc_client_creation_count = - test_server_->counter("grpc.ext_authz_cluster.google_grpc_client_creation")->value(); + expected_grpc_client_creation_count = test_server_->counter(creation_stat_name)->value(); } waitForSuccessfulUpstreamResponse("200"); @@ -1225,7 +1339,7 @@ TEST_P(ExtAuthzGrpcIntegrationTest, GoogleAsyncClientCreation) { if (clientType() == Grpc::ClientType::GoogleGrpc) { // Make sure no more Google grpc client is created no matter how many requests coming in. EXPECT_EQ(expected_grpc_client_creation_count, - test_server_->counter("grpc.ext_authz_cluster.google_grpc_client_creation")->value()); + test_server_->counter(creation_stat_name)->value()); } sendExtAuthzResponse(Headers{}, Headers{}, Headers{}, Http::TestRequestHeaderMapImpl{}, Http::TestRequestHeaderMapImpl{}, Headers{}); @@ -1250,7 +1364,7 @@ TEST_P(ExtAuthzGrpcIntegrationTest, GoogleAsyncClientCreation) { if (clientType() == Grpc::ClientType::GoogleGrpc) { // Make sure no more Google grpc client is created no matter how many requests coming in. EXPECT_EQ(expected_grpc_client_creation_count, - test_server_->counter("grpc.ext_authz_cluster.google_grpc_client_creation")->value()); + test_server_->counter(creation_stat_name)->value()); } cleanup(); diff --git a/test/extensions/filters/http/ext_proc/streaming_integration_test.cc b/test/extensions/filters/http/ext_proc/streaming_integration_test.cc index 865df19817c8..274404740ee7 100644 --- a/test/extensions/filters/http/ext_proc/streaming_integration_test.cc +++ b/test/extensions/filters/http/ext_proc/streaming_integration_test.cc @@ -319,8 +319,8 @@ TEST_P(StreamingIntegrationTest, PostAndProcessStreamedRequestBodyPartially) { ProcessingResponse resp; if (req.has_request_body()) { received_count++; - if (received_count == 2) { - // After two body chunks, change the processing mode. Since the body + if (received_count == 1) { + // After first body chunk, change the processing mode. Since the body // is pipelined, we might still get body chunks, however. This test can't // validate this, but at least we can ensure that this doesn't blow up the // protocol. @@ -330,7 +330,7 @@ TEST_P(StreamingIntegrationTest, PostAndProcessStreamedRequestBodyPartially) { resp.mutable_request_body(); } else if (req.has_response_headers()) { // Should not see response headers until we changed the processing mode. - EXPECT_GE(received_count, 2); + EXPECT_GE(received_count, 1); resp.mutable_response_headers(); } else { FAIL() << "unexpected stream message"; diff --git a/test/extensions/transport_sockets/tls/context_impl_test.cc b/test/extensions/transport_sockets/tls/context_impl_test.cc index c7865f2cc29d..a01f08a050ab 100644 --- a/test/extensions/transport_sockets/tls/context_impl_test.cc +++ b/test/extensions/transport_sockets/tls/context_impl_test.cc @@ -1971,6 +1971,32 @@ TEST_F(ServerContextConfigImplTest, PrivateKeyMethodLoadFailureNoProvider) { "Failed to load private key provider: mock_provider"); } +TEST_F(ServerContextConfigImplTest, PrivateKeyMethodLoadFailureNoProviderFallback) { + envoy::extensions::transport_sockets::tls::v3::DownstreamTlsContext tls_context; + NiceMock context_manager; + NiceMock private_key_method_manager; + EXPECT_CALL(factory_context_, sslContextManager()).WillOnce(ReturnRef(context_manager)); + EXPECT_CALL(context_manager, privateKeyMethodManager()) + .WillOnce(ReturnRef(private_key_method_manager)); + const std::string tls_context_yaml = R"EOF( + common_tls_context: + tls_certificates: + - certificate_chain: + filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/selfsigned_cert.pem" + private_key_provider: + provider_name: mock_provider + typed_config: + "@type": type.googleapis.com/google.protobuf.Struct + value: + test_value: 100 + fallback: true + )EOF"; + TestUtility::loadFromYaml(TestEnvironment::substitute(tls_context_yaml), tls_context); + EXPECT_THROW_WITH_REGEX( + ServerContextConfigImpl server_context_config(tls_context, factory_context_), EnvoyException, + "Failed to load private key provider: mock_provider"); +} + TEST_F(ServerContextConfigImplTest, PrivateKeyMethodLoadFailureNoMethod) { envoy::extensions::transport_sockets::tls::v3::DownstreamTlsContext tls_context; tls_context.mutable_common_tls_context()->add_tls_certificates(); @@ -1986,6 +2012,7 @@ TEST_F(ServerContextConfigImplTest, PrivateKeyMethodLoadFailureNoMethod) { .WillOnce(ReturnRef(private_key_method_manager)); EXPECT_CALL(private_key_method_manager, createPrivateKeyMethodProvider(_, _)) .WillOnce(Return(private_key_method_provider_ptr)); + EXPECT_CALL(*private_key_method_provider_ptr, isAvailable()).WillRepeatedly(Return(true)); const std::string tls_context_yaml = R"EOF( common_tls_context: tls_certificates: @@ -2017,6 +2044,7 @@ TEST_F(ServerContextConfigImplTest, PrivateKeyMethodLoadSuccess) { .WillOnce(ReturnRef(private_key_method_manager)); EXPECT_CALL(private_key_method_manager, createPrivateKeyMethodProvider(_, _)) .WillOnce(Return(private_key_method_provider_ptr)); + EXPECT_CALL(*private_key_method_provider_ptr, isAvailable()).WillRepeatedly(Return(true)); const std::string tls_context_yaml = R"EOF( common_tls_context: tls_certificates: @@ -2033,12 +2061,18 @@ TEST_F(ServerContextConfigImplTest, PrivateKeyMethodLoadSuccess) { ServerContextConfigImpl server_context_config(tls_context, factory_context_); } -TEST_F(ServerContextConfigImplTest, PrivateKeyMethodLoadFailureBothKeyAndMethod) { +TEST_F(ServerContextConfigImplTest, PrivateKeyMethodFallback) { envoy::extensions::transport_sockets::tls::v3::DownstreamTlsContext tls_context; NiceMock context_manager; NiceMock private_key_method_manager; auto private_key_method_provider_ptr = std::make_shared>(); + EXPECT_CALL(factory_context_, sslContextManager()).WillOnce(ReturnRef(context_manager)); + EXPECT_CALL(context_manager, privateKeyMethodManager()) + .WillOnce(ReturnRef(private_key_method_manager)); + EXPECT_CALL(private_key_method_manager, createPrivateKeyMethodProvider(_, _)) + .WillOnce(Return(private_key_method_provider_ptr)); + EXPECT_CALL(*private_key_method_provider_ptr, isAvailable()).WillRepeatedly(Return(false)); const std::string tls_context_yaml = R"EOF( common_tls_context: tls_certificates: @@ -2052,11 +2086,10 @@ TEST_F(ServerContextConfigImplTest, PrivateKeyMethodLoadFailureBothKeyAndMethod) "@type": type.googleapis.com/google.protobuf.Struct value: test_value: 100 + fallback: true )EOF"; TestUtility::loadFromYaml(TestEnvironment::substitute(tls_context_yaml), tls_context); - EXPECT_THROW_WITH_MESSAGE( - ServerContextConfigImpl server_context_config(tls_context, factory_context_), EnvoyException, - "Certificate configuration can't have both private_key and private_key_provider"); + ServerContextConfigImpl server_context_config(tls_context, factory_context_); } // Test that if both typed and untyped matchers for sans are specified, we diff --git a/test/extensions/transport_sockets/tls/ssl_socket_test.cc b/test/extensions/transport_sockets/tls/ssl_socket_test.cc index 8f59823d3c5f..14fec9379f89 100644 --- a/test/extensions/transport_sockets/tls/ssl_socket_test.cc +++ b/test/extensions/transport_sockets/tls/ssl_socket_test.cc @@ -3618,10 +3618,10 @@ void testTicketSessionResumption(const std::string& server_ctx_yaml1, EXPECT_EQ(expect_reuse ? 1UL : 0UL, client_stats_store.counter("ssl.session_reused").value()); } -void testSupportForStatelessSessionResumption(const std::string& server_ctx_yaml, - const std::string& client_ctx_yaml, - bool expect_support, - const Network::Address::IpVersion ip_version) { +void testSupportForSessionResumption(const std::string& server_ctx_yaml, + const std::string& client_ctx_yaml, bool expect_stateless, + bool expect_stateful, + const Network::Address::IpVersion ip_version) { Event::SimulatedTimeSystem time_system; ContextManagerImpl manager(*time_system); @@ -3681,11 +3681,17 @@ void testSupportForStatelessSessionResumption(const std::string& server_ctx_yaml dynamic_cast(server_connection->ssl().get()); SSL* server_ssl_socket = ssl_socket->ssl(); SSL_CTX* server_ssl_context = SSL_get_SSL_CTX(server_ssl_socket); - if (expect_support) { + if (expect_stateless) { EXPECT_EQ(0, (SSL_CTX_get_options(server_ssl_context) & SSL_OP_NO_TICKET)); } else { EXPECT_EQ(SSL_OP_NO_TICKET, (SSL_CTX_get_options(server_ssl_context) & SSL_OP_NO_TICKET)); } + if (expect_stateful) { + EXPECT_EQ(SSL_SESS_CACHE_SERVER, + (SSL_CTX_get_session_cache_mode(server_ssl_context) & SSL_SESS_CACHE_SERVER)); + } else { + EXPECT_EQ(SSL_SESS_CACHE_OFF, SSL_CTX_get_session_cache_mode(server_ssl_context)); + } })); EXPECT_CALL(callbacks, recordConnectionsAcceptedOnSocketEvent(_)); @@ -4144,6 +4150,25 @@ TEST_P(SslSocketTest, TicketSessionResumptionDifferentServerCertDifferentSAN) { version_); } +TEST_P(SslSocketTest, SessionResumptionDisabled) { + const std::string server_ctx_yaml = R"EOF( + common_tls_context: + tls_certificates: + certificate_chain: + filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/unittest_cert.pem" + private_key: + filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/unittest_key.pem" + disable_stateless_session_resumption: true + disable_stateful_session_resumption: true +)EOF"; + + const std::string client_ctx_yaml = R"EOF( + common_tls_context: + )EOF"; + + testSupportForSessionResumption(server_ctx_yaml, client_ctx_yaml, false, false, version_); +} + TEST_P(SslSocketTest, StatelessSessionResumptionDisabled) { const std::string server_ctx_yaml = R"EOF( common_tls_context: @@ -4159,10 +4184,28 @@ TEST_P(SslSocketTest, StatelessSessionResumptionDisabled) { common_tls_context: )EOF"; - testSupportForStatelessSessionResumption(server_ctx_yaml, client_ctx_yaml, false, version_); + testSupportForSessionResumption(server_ctx_yaml, client_ctx_yaml, false, true, version_); } -TEST_P(SslSocketTest, SatelessSessionResumptionEnabledExplicitly) { +TEST_P(SslSocketTest, StatefulSessionResumptionDisabled) { + const std::string server_ctx_yaml = R"EOF( + common_tls_context: + tls_certificates: + certificate_chain: + filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/unittest_cert.pem" + private_key: + filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/unittest_key.pem" + disable_stateful_session_resumption: true +)EOF"; + + const std::string client_ctx_yaml = R"EOF( + common_tls_context: + )EOF"; + + testSupportForSessionResumption(server_ctx_yaml, client_ctx_yaml, true, false, version_); +} + +TEST_P(SslSocketTest, SessionResumptionEnabledExplicitly) { const std::string server_ctx_yaml = R"EOF( common_tls_context: tls_certificates: @@ -4171,16 +4214,17 @@ TEST_P(SslSocketTest, SatelessSessionResumptionEnabledExplicitly) { private_key: filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/unittest_key.pem" disable_stateless_session_resumption: false + disable_stateful_session_resumption: false )EOF"; const std::string client_ctx_yaml = R"EOF( common_tls_context: )EOF"; - testSupportForStatelessSessionResumption(server_ctx_yaml, client_ctx_yaml, true, version_); + testSupportForSessionResumption(server_ctx_yaml, client_ctx_yaml, true, true, version_); } -TEST_P(SslSocketTest, StatelessSessionResumptionEnabledByDefault) { +TEST_P(SslSocketTest, SessionResumptionEnabledByDefault) { const std::string server_ctx_yaml = R"EOF( common_tls_context: tls_certificates: @@ -4194,7 +4238,7 @@ TEST_P(SslSocketTest, StatelessSessionResumptionEnabledByDefault) { common_tls_context: )EOF"; - testSupportForStatelessSessionResumption(server_ctx_yaml, client_ctx_yaml, true, version_); + testSupportForSessionResumption(server_ctx_yaml, client_ctx_yaml, true, true, version_); } // Test that if two listeners use the same cert and session ticket key, but @@ -6312,6 +6356,47 @@ TEST_P(SslSocketTest, RsaPrivateKeyProviderSyncDecryptSuccess) { testUtil(successful_test_options.setPrivateKeyMethodExpected(true)); } +// Test fallback for key provider. +TEST_P(SslSocketTest, RsaPrivateKeyProviderFallbackSuccess) { + const std::string server_ctx_yaml = R"EOF( + common_tls_context: + tls_params: + cipher_suites: + - TLS_RSA_WITH_AES_128_GCM_SHA256 + tls_certificates: + certificate_chain: + filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/unittest_cert.pem" + private_key: + filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/unittest_key.pem" + private_key_provider: + provider_name: test + typed_config: + "@type": type.googleapis.com/google.protobuf.Struct + value: + private_key_file: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/unittest_key.pem" + expected_operation: decrypt + sync_mode: true + mode: rsa + is_available: false + fallback: true + validation_context: + trusted_ca: + filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/ca_cert.pem" + crl: + filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/ca_cert.crl" +)EOF"; + const std::string successful_client_ctx_yaml = R"EOF( + common_tls_context: + tls_params: + cipher_suites: + - TLS_RSA_WITH_AES_128_GCM_SHA256 +)EOF"; + + TestUtilOptions successful_test_options(successful_client_ctx_yaml, server_ctx_yaml, true, + version_); + testUtil(successful_test_options.setPrivateKeyMethodExpected(true)); +} + // Test asynchronous signing (ECDHE) failure (invalid signature). TEST_P(SslSocketTest, RsaPrivateKeyProviderAsyncSignFailure) { const std::string server_ctx_yaml = R"EOF( diff --git a/test/extensions/transport_sockets/tls/test_private_key_method_provider.cc b/test/extensions/transport_sockets/tls/test_private_key_method_provider.cc index 1f01175716ea..83e0ce46edae 100644 --- a/test/extensions/transport_sockets/tls/test_private_key_method_provider.cc +++ b/test/extensions/transport_sockets/tls/test_private_key_method_provider.cc @@ -257,6 +257,8 @@ bool TestPrivateKeyMethodProvider::checkFips() { return true; } +bool TestPrivateKeyMethodProvider::isAvailable() { return test_options_.is_available_; } + TestPrivateKeyConnection::TestPrivateKeyConnection( Ssl::PrivateKeyConnectionCallbacks& cb, Event::Dispatcher& dispatcher, bssl::UniquePtr pkey, TestPrivateKeyConnectionTestOptions& test_options) @@ -333,6 +335,9 @@ TestPrivateKeyMethodProvider::TestPrivateKeyMethodProvider( if (value_it.first == "method_error" && value.kind_case() == ProtobufWkt::Value::kBoolValue) { test_options_.method_error_ = value.bool_value(); } + if (value_it.first == "is_available" && value.kind_case() == ProtobufWkt::Value::kBoolValue) { + test_options_.is_available_ = value.bool_value(); + } if (value_it.first == "async_method_error" && value.kind_case() == ProtobufWkt::Value::kBoolValue) { test_options_.async_method_error_ = value.bool_value(); @@ -350,6 +355,10 @@ TestPrivateKeyMethodProvider::TestPrivateKeyMethodProvider( } } + if (!test_options_.is_available_) { + return; + } + std::string private_key = factory_context.serverFactoryContext().api().fileSystem().fileReadToEnd(private_key_path); bssl::UniquePtr bio( diff --git a/test/extensions/transport_sockets/tls/test_private_key_method_provider.h b/test/extensions/transport_sockets/tls/test_private_key_method_provider.h index efe94936d2f3..133d6a1d0ae0 100644 --- a/test/extensions/transport_sockets/tls/test_private_key_method_provider.h +++ b/test/extensions/transport_sockets/tls/test_private_key_method_provider.h @@ -31,6 +31,9 @@ struct TestPrivateKeyConnectionTestOptions { // Return an error from the private key method completion function. bool async_method_error_{}; + + // Return true if the private key method is available. + bool is_available_{true}; }; // An example private key method provider for testing the decrypt() and sign() @@ -68,6 +71,7 @@ class TestPrivateKeyMethodProvider : public virtual Ssl::PrivateKeyMethodProvide Event::Dispatcher& dispatcher) override; void unregisterPrivateKeyMethod(SSL* ssl) override; bool checkFips() override; + bool isAvailable() override; Ssl::BoringSslPrivateKeyMethodSharedPtr getBoringSslPrivateKeyMethod() override; static int rsaConnectionIndex(); diff --git a/test/integration/integration_test.cc b/test/integration/integration_test.cc index b37cdd34b415..f424bdc833b0 100644 --- a/test/integration/integration_test.cc +++ b/test/integration/integration_test.cc @@ -1078,13 +1078,6 @@ TEST_P(IntegrationTest, MissingDelimiter) { } TEST_P(IntegrationTest, InvalidCharacterInFirstline) { -#ifndef ENVOY_ENABLE_UHV - if (http1_implementation_ == Http1ParserImpl::BalsaParser) { - // BalsaParser allows custom methods if UHV is enabled. - return; - } -#endif - initialize(); std::string response; sendRawHttpAndWaitForResponse(lookupPort("http"), "GE(T / HTTP/1.1\r\nHost: host\r\n\r\n", diff --git a/test/integration/multiplexed_integration_test.cc b/test/integration/multiplexed_integration_test.cc index b678090bec3e..bc3288b2f3ff 100644 --- a/test/integration/multiplexed_integration_test.cc +++ b/test/integration/multiplexed_integration_test.cc @@ -2182,13 +2182,7 @@ TEST_P(Http2MetadataIntegrationTest, UpstreamMetadataAfterEndStream) { } TEST_P(MultiplexedIntegrationTest, InvalidTrailers) { -#ifdef ENVOY_ENABLE_UHV - if (GetParam().http2_implementation == Http2Impl::Oghttp2 && - downstreamProtocol() == Http::CodecType::HTTP2) { - return; - } -#endif - + disable_client_header_validation_ = true; autonomous_allow_incomplete_streams_ = true; useAccessLog("%RESPONSE_CODE_DETAILS%"); autonomous_upstream_ = true; @@ -2254,6 +2248,7 @@ TEST_P(MultiplexedIntegrationTest, InconsistentContentLength) { // reset the request. TEST_P(MultiplexedIntegrationTest, Reset101SwitchProtocolResponse) { #ifdef ENVOY_ENABLE_UHV + // TODO(#29071): reject responses with 101 in H/2 and H/3 UHV if (GetParam().http2_implementation == Http2Impl::Oghttp2 && downstreamProtocol() == Http::CodecType::HTTP2) { return; diff --git a/test/integration/protocol_integration_test.cc b/test/integration/protocol_integration_test.cc index a2402bafe07f..c3bb2fe597b8 100644 --- a/test/integration/protocol_integration_test.cc +++ b/test/integration/protocol_integration_test.cc @@ -4032,10 +4032,6 @@ TEST_P(DownstreamProtocolIntegrationTest, ValidateUpstreamHeaders) { } TEST_P(ProtocolIntegrationTest, ValidateUpstreamMixedCaseHeaders) { - if (use_universal_header_validator_) { - // UHV does not support this case so far. - return; - } if (upstreamProtocol() != Http::CodecType::HTTP1) { autonomous_allow_incomplete_streams_ = true; autonomous_upstream_ = true; diff --git a/test/integration/udp_tunneling_integration_test.cc b/test/integration/udp_tunneling_integration_test.cc index 44e240ec45ae..e657f5fd065b 100644 --- a/test/integration/udp_tunneling_integration_test.cc +++ b/test/integration/udp_tunneling_integration_test.cc @@ -247,5 +247,87 @@ INSTANTIATE_TEST_SUITE_P(Protocols, ConnectUdpTerminationIntegrationTest, {Http::CodecType::HTTP1})), HttpProtocolIntegrationTest::protocolTestParamsToString); +// Forwards the CONNECT-UDP request upstream. +class ForwardingConnectUdpIntegrationTest : public HttpProtocolIntegrationTest { +public: + void initialize() override { + config_helper_.addConfigModifier( + [&](envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager& + hcm) -> void { + ConfigHelper::setConnectUdpConfig(hcm, false, + downstream_protocol_ == Http::CodecType::HTTP3); + }); + + HttpProtocolIntegrationTest::initialize(); + } + + // The Envoy HTTP/2 and HTTP/3 clients expect the request header map to be in the form of HTTP/1 + // upgrade to issue an extended CONNECT request. + Http::TestRequestHeaderMapImpl connect_udp_headers_{ + {":method", "GET"}, {":path", "/.well-known/masque/udp/foo.lyft.com/80/"}, + {"upgrade", "connect-udp"}, {"connection", "upgrade"}, + {":scheme", "https"}, {":authority", "example.org"}, + {"capsule-protocol", "?1"}}; + + IntegrationStreamDecoderPtr response_; +}; + +INSTANTIATE_TEST_SUITE_P( + Protocols, ForwardingConnectUdpIntegrationTest, + testing::ValuesIn(HttpProtocolIntegrationTest::getProtocolTestParams( + {Http::CodecType::HTTP1, Http::CodecType::HTTP2, Http::CodecType::HTTP3}, + {Http::CodecType::HTTP1, Http::CodecType::HTTP2, Http::CodecType::HTTP3})), + HttpProtocolIntegrationTest::protocolTestParamsToString); + +TEST_P(ForwardingConnectUdpIntegrationTest, ForwardConnectUdp) { + initialize(); + + // Send request headers. + codec_client_ = makeHttpConnection(lookupPort("http")); + auto encoder_decoder = codec_client_->startRequest(connect_udp_headers_); + request_encoder_ = &encoder_decoder.first; + response_ = std::move(encoder_decoder.second); + + // Wait for them to arrive upstream. + AssertionResult result = + fake_upstreams_[0]->waitForHttpConnection(*dispatcher_, fake_upstream_connection_); + RELEASE_ASSERT(result, result.message()); + result = fake_upstream_connection_->waitForNewStream(*dispatcher_, upstream_request_); + RELEASE_ASSERT(result, result.message()); + ASSERT_TRUE(upstream_request_->waitForHeadersComplete()); + + // Check the request header contains correct field values (Normalized to HTTP/1). + EXPECT_EQ(upstream_request_->headers().getMethodValue(), "GET"); + EXPECT_EQ(upstream_request_->headers().getConnectionValue(), "upgrade"); + EXPECT_EQ(upstream_request_->headers().getUpgradeValue(), "connect-udp"); + EXPECT_EQ(upstream_request_->headers().getHostValue(), "foo.lyft.com:80"); + + // Send response headers + upstream_request_->encodeHeaders(default_response_headers_, false); + // Wait for them to arrive downstream. + response_->waitForHeaders(); + cleanupUpstreamAndDownstream(); +} + +TEST_P(ForwardingConnectUdpIntegrationTest, DoNotForwardNonConnectUdp) { + initialize(); + + Http::TestRequestHeaderMapImpl websocket_headers_{ + {":method", "GET"}, {":path", "/"}, {"upgrade", "websocket"}, + {"connection", "upgrade"}, {":scheme", "https"}, {":authority", "foo.lyft.com:80"}}; + + // Send WebSocket request headers. + codec_client_ = makeHttpConnection(lookupPort("http")); + auto encoder_decoder = codec_client_->startRequest(websocket_headers_); + request_encoder_ = &encoder_decoder.first; + response_ = std::move(encoder_decoder.second); + response_->waitForHeaders(); + + // Envoy should return a 404 error response. + EXPECT_EQ("404", response_->headers().getStatusValue()); + + cleanupUpstreamAndDownstream(); +} + } // namespace } // namespace Envoy diff --git a/test/mocks/server/server_factory_context.cc b/test/mocks/server/server_factory_context.cc index 0acd1b671908..860714c5e3b3 100644 --- a/test/mocks/server/server_factory_context.cc +++ b/test/mocks/server/server_factory_context.cc @@ -9,7 +9,8 @@ using ::testing::ReturnRef; MockServerFactoryContext::MockServerFactoryContext() : singleton_manager_(new Singleton::ManagerImpl(Thread::threadFactoryForTest())), - grpc_context_(store_.symbolTable()), router_context_(store_.symbolTable()) { + http_context_(store_.symbolTable()), grpc_context_(store_.symbolTable()), + router_context_(store_.symbolTable()) { ON_CALL(*this, clusterManager()).WillByDefault(ReturnRef(cluster_manager_)); ON_CALL(*this, mainThreadDispatcher()).WillByDefault(ReturnRef(dispatcher_)); ON_CALL(*this, drainDecision()).WillByDefault(ReturnRef(drain_manager_)); diff --git a/test/mocks/server/server_factory_context.h b/test/mocks/server/server_factory_context.h index d7bd11f4719f..3d0cddda2e99 100644 --- a/test/mocks/server/server_factory_context.h +++ b/test/mocks/server/server_factory_context.h @@ -71,6 +71,7 @@ class MockServerFactoryContext : public virtual ServerFactoryContext { MOCK_METHOD(ProtobufMessage::ValidationContext&, messageValidationContext, ()); MOCK_METHOD(ProtobufMessage::ValidationVisitor&, messageValidationVisitor, ()); MOCK_METHOD(Api::Api&, api, ()); + Http::Context& httpContext() override { return http_context_; } Grpc::Context& grpcContext() override { return grpc_context_; } Router::Context& routerContext() override { return router_context_; } envoy::config::bootstrap::v3::Bootstrap& bootstrap() override { return bootstrap_; } @@ -97,6 +98,7 @@ class MockServerFactoryContext : public virtual ServerFactoryContext { testing::NiceMock admin_; Event::GlobalTimeSystem time_system_; testing::NiceMock api_; + Http::ContextImpl http_context_; Grpc::ContextImpl grpc_context_; Router::ContextImpl router_context_; envoy::config::bootstrap::v3::Bootstrap bootstrap_; @@ -126,6 +128,7 @@ class StatelessMockServerFactoryContext : public virtual ServerFactoryContext { MOCK_METHOD(ProtobufMessage::ValidationContext&, messageValidationContext, ()); MOCK_METHOD(ProtobufMessage::ValidationVisitor&, messageValidationVisitor, ()); MOCK_METHOD(Api::Api&, api, ()); + MOCK_METHOD(Http::Context&, httpContext, ()); MOCK_METHOD(Grpc::Context&, grpcContext, ()); MOCK_METHOD(Router::Context&, routerContext, ()); MOCK_METHOD(envoy::config::bootstrap::v3::Bootstrap&, bootstrap, ()); diff --git a/test/mocks/ssl/mocks.h b/test/mocks/ssl/mocks.h index a6138922ebfd..a7e85351b41e 100644 --- a/test/mocks/ssl/mocks.h +++ b/test/mocks/ssl/mocks.h @@ -142,6 +142,7 @@ class MockServerContextConfig : public ServerContextConfig { MOCK_METHOD(OcspStaplePolicy, ocspStaplePolicy, (), (const)); MOCK_METHOD(const std::vector&, sessionTicketKeys, (), (const)); MOCK_METHOD(bool, disableStatelessSessionResumption, (), (const)); + MOCK_METHOD(bool, disableStatefulSessionResumption, (), (const)); MOCK_METHOD(const Network::Address::IpList&, tlsKeyLogLocal, (), (const)); MOCK_METHOD(const Network::Address::IpList&, tlsKeyLogRemote, (), (const)); MOCK_METHOD(const std::string&, tlsKeyLogPath, (), (const)); @@ -208,6 +209,7 @@ class MockPrivateKeyMethodProvider : public PrivateKeyMethodProvider { (SSL * ssl, PrivateKeyConnectionCallbacks& cb, Event::Dispatcher& dispatcher)); MOCK_METHOD(void, unregisterPrivateKeyMethod, (SSL * ssl)); MOCK_METHOD(bool, checkFips, ()); + MOCK_METHOD(bool, isAvailable, ()); #ifdef OPENSSL_IS_BORINGSSL MOCK_METHOD(BoringSslPrivateKeyMethodSharedPtr, getBoringSslPrivateKeyMethod, ()); diff --git a/test/server/guarddog_impl_test.cc b/test/server/guarddog_impl_test.cc index 4dd8646f4030..2f12ae1d8aec 100644 --- a/test/server/guarddog_impl_test.cc +++ b/test/server/guarddog_impl_test.cc @@ -198,7 +198,7 @@ TEST_P(GuardDogDeathTest, MultiKillDeathTest) { time_system_->advanceTimeWait(std::chrono::milliseconds(2)); // 1 ms past multi-death. guard_dog_->forceCheckForTest(); }; - EXPECT_DEATH(die_function(), ""); + EXPECT_DEATH(die_function(), "Watchdog MULTIKILL as 2 threads are stuck"); } TEST_P(GuardDogAlmostDeadTest, MultiKillNoFinalCheckTest) { diff --git a/tools/gen_compilation_database.py b/tools/gen_compilation_database.py index cf8c94df1fb1..11932552f6f5 100755 --- a/tools/gen_compilation_database.py +++ b/tools/gen_compilation_database.py @@ -89,6 +89,10 @@ def modify_compile_command(target, args): # old-style "-I". options = options.replace("-iquote ", "-I ") + if args.system_clang: + if cc.find("clang"): + cc = "clang++" + if is_header(target["file"]): options += " -Wno-pragma-once-outside-header -Wno-unused-const-variable" options += " -Wno-unused-function" @@ -118,6 +122,12 @@ def fix_compilation_database(args, db): parser.add_argument('--vscode', action='store_true') parser.add_argument('--include_all', action='store_true') parser.add_argument('--exclude_contrib', action='store_true') + parser.add_argument( + '--system-clang', + action='store_true', + help= + 'Use `clang++` instead of the bazel wrapper for commands. This may help if `clangd` cannot find/run the tools.' + ) parser.add_argument('--bazel', default='bazel') parser.add_argument( 'bazel_targets', nargs='*', default=[ diff --git a/tools/sha/BUILD b/tools/sha/BUILD new file mode 100644 index 000000000000..2ca0228500fa --- /dev/null +++ b/tools/sha/BUILD @@ -0,0 +1,12 @@ +load("@envoy_repo//:path.bzl", "PATH") +load("//bazel:envoy_build_system.bzl", "envoy_package") + +licenses(["notice"]) # Apache 2 + +envoy_package() + +sh_binary( + name = "replace", + srcs = ["replace.sh"], + args = [PATH], +) diff --git a/tools/sha/replace.sh b/tools/sha/replace.sh new file mode 100755 index 000000000000..12bb78918dc0 --- /dev/null +++ b/tools/sha/replace.sh @@ -0,0 +1,24 @@ +#!/bin/bash -e + +set -o pipefail + +# This tool is for replacing shas in the repo, altho it could be +# used to replace any strings. +# +# It does not currently validate that target/replacements are any kind of sha. + +REPO_PATH="$1" +shift + +cd "$REPO_PATH" || exit 1 + +for arg in "$@"; do + target="$(echo "$arg" | cut -d: -f1)" + replacement="$(echo "$arg" | cut -d: -f2)" + echo "Replacing ${target} -> ${replacement}" + git grep "$target" \ + | cut -d: -f1 \ + | xargs sed -i "s/${target}/${replacement}/g" || { + echo "No shas replaced for ${target}" >&2 + } +done