diff --git a/.azure-pipelines/pipelines.yml b/.azure-pipelines/pipelines.yml index 5afb77b97b204..ffa38e11198d9 100644 --- a/.azure-pipelines/pipelines.yml +++ b/.azure-pipelines/pipelines.yml @@ -393,6 +393,12 @@ stages: BAZEL_REMOTE_CACHE: grpcs://remotebuildexecution.googleapis.com BAZEL_REMOTE_INSTANCE: projects/envoy-ci/instances/default_instance GCP_SERVICE_ACCOUNT_KEY: $(GcpServiceAccountKey) + - task: PublishTestResults@2 + inputs: + testResultsFiles: "**/bazel-out/**/testlogs/**/test.xml" + testRunTitle: "windows" + searchFolder: $(Build.StagingDirectory)/tmp + condition: always() - task: PublishBuildArtifacts@1 inputs: pathtoPublish: "$(Build.StagingDirectory)/envoy" diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 97c37be6a6767..b6ee2969559fa 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -12,6 +12,9 @@ // Uncomment next line if you have devcontainer.env // "--env-file=.devcontainer/devcontainer.env" ], + "containerEnv": { + "ENVOY_SRCDIR": "${containerWorkspaceFolder}", + }, "settings": { "terminal.integrated.shell.linux": "/bin/bash", "bazel.buildifierFixOnFormat": true, diff --git a/.github/workflows/codeql-push.yml b/.github/workflows/codeql-push.yml index d6110bbddca2c..fbe091a90ec00 100644 --- a/.github/workflows/codeql-push.yml +++ b/.github/workflows/codeql-push.yml @@ -24,7 +24,9 @@ jobs: - name: Get build targets run: | . .github/workflows/get_build_targets.sh - echo ::set-env name=BUILD_TARGETS::$(echo $BUILD_TARGETS_LOCAL) + echo 'BUILD_TARGETS<> $GITHUB_ENV + echo $BUILD_TARGETS_LOCAL >> $GITHUB_ENV + echo 'EOF' >> $GITHUB_ENV # If this run was triggered by a pull request event, then checkout # the head of the pull request instead of the merge commit. - run: git checkout HEAD^2 diff --git a/CODEOWNERS b/CODEOWNERS index ab8af77e34016..7daa13077d26e 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -92,6 +92,8 @@ extensions/filters/common/original_src @snowp @klarose /*/extensions/filters/network/wasm @PiotrSikora @lizan # webassembly common extension /*/extensions/common/wasm @PiotrSikora @lizan +# webassembly runtimes +/*/extensions/wasm_runtime/ @PiotrSikora @lizan # common matcher /*/extensions/common/matcher @mattklein123 @yangminzhu # common crypto extension @@ -152,3 +154,5 @@ extensions/filters/http/oauth2 @rgs1 @derekargueta @snowp # HTTP Local Rate Limit /*/extensions/filters/http/local_ratelimit @rgs1 @mattklein123 /*/extensions/filters/common/local_ratelimit @mattklein123 @rgs1 +# HTTP Kill Request +/*/extensions/filters/http/kill_request @qqustc @htuch diff --git a/PULL_REQUESTS.md b/PULL_REQUESTS.md index aa8c5e7502478..3fb17835ebd01 100644 --- a/PULL_REQUESTS.md +++ b/PULL_REQUESTS.md @@ -60,7 +60,7 @@ changes may be in [docs/root](docs/root) and/or inline with the API protos. Plea N/A if there were no documentation changes. Any PRs with structural changes to the dataplane should also update the [Life of a -Request](docs/root/intro/life_of_a_request.md) documentation as appropriate. +Request](https://www.envoyproxy.io/docs/envoy/latest/intro/life_of_a_request) documentation as appropriate. ### Release notes diff --git a/REPO_LAYOUT.md b/REPO_LAYOUT.md index e4f2452a1417b..3eae104c8c35c 100644 --- a/REPO_LAYOUT.md +++ b/REPO_LAYOUT.md @@ -63,9 +63,8 @@ Not every directory within test is described below, but a few highlights: ## [source/extensions](source/extensions/) layout We maintain a very specific code and namespace layout for extensions. This aids in discovering -code/extensions, and also will allow us in the future to more easily scale out our extension -maintainers by having OWNERS files specific to certain extensions. (As of this writing, this is not -currently implemented but that is the plan moving forward.) +code/extensions, and allows us specify extension owners in [CODEOWNERS](CODEOWNERS). + * All extensions are either registered in [all_extensions.bzl](source/extensions/all_extensions.bzl) or [extensions_build_config.bzl](source/extensions/extensions_build_config.bzl). The former is @@ -76,6 +75,14 @@ currently implemented but that is the plan moving forward.) * These are the top level extension directories and associated namespaces: * [access_loggers/](/source/extensions/access_loggers): Access log implementations which use the `Envoy::Extensions::AccessLoggers` namespace. + * [bootstrap](/source/extensions/bootstrap): Bootstrap extensions which use + the `Envoy::Extensions::Bootstrap` namespace. + * [clusters](/source/extensions/clusters): Cluster extensions which use the + `Envoy::Extensions::Clusters` namespace. + * [compression](/source/extensions/compression): Compression extensions + which use `Envoy::Extensions::Compression` namespace. + * [fatal_actions](/source/extensions/fatal_actions): Fatal Action extensions + which use the `Envoy::Extensions::FatalActions` namespace. * [filters/http/](/source/extensions/filters/http): HTTP L7 filters which use the `Envoy::Extensions::HttpFilters` namespace. * [filters/listener/](/source/extensions/filters/listener): Listener filters which use the @@ -86,14 +93,24 @@ currently implemented but that is the plan moving forward.) `Envoy::Extensions::GrpcCredentials` namespace. * [health_checker/](/source/extensions/health_checker): Custom health checkers which use the `Envoy::Extensions::HealthCheckers` namespace. - * [resolvers/](/source/extensions/resolvers): Network address resolvers which use the - `Envoy::Extensions::Resolvers` namespace. + * [internal_redirect](/source/extensions/internal_redirect): Internal Redirect + extensions which use the `Envoy::Extensions::InternalRedirect` namespace. + * [quic_listeners](/source/extensions/quic_listeners): QUIC extensions which + use the `Envoy::Quic` namespace. + * [resource_monitors](/source/extensions/resource_monitors): Resource monitor + extensions which use the `Envoy::Extensions::ResourceMonitors` namespace. + * [retry](/source/extensions/retry): Retry extensions which use the + `Envoy::Extensions::Retry` namespace. * [stat_sinks/](/source/extensions/stat_sinks): Stat sink implementations which use the `Envoy::Extensions::StatSinks` namespace. * [tracers/](/source/extensions/tracers): Tracers which use the `Envoy::Extensions::Tracers` namespace. * [transport_sockets/](/source/extensions/transport_sockets): Transport socket implementations which use the `Envoy::Extensions::TransportSockets` namespace. + * [upstreams](/source/extensions/upstreams): Upstream extensions use the + `Envoy::Extensions::Upstreams` namespace. + * [watchdog](/source/extensions/watchdog): Watchdog extensions use the + `Envoy::Extensions::Watchdog` namespace. * Each extension is contained wholly in its own namespace. E.g., `Envoy::Extensions::NetworkFilters::Echo`. * Common code that is used by multiple extensions should be in a `common/` directory as close to diff --git a/STYLE.md b/STYLE.md index ee2deadf170bb..3feafbcc10a04 100644 --- a/STYLE.md +++ b/STYLE.md @@ -19,7 +19,7 @@ # Documentation * If you are modifying the data plane structually, please keep the [Life of a - Request](docs/root/intro/life_of_a_request.md) documentation up-to-date. + Request](https://www.envoyproxy.io/docs/envoy/latest/intro/life_of_a_request) documentation up-to-date. # Deviations from Google C++ style guidelines diff --git a/api/BUILD b/api/BUILD index 3df8b906b0067..b918a3c954c8f 100644 --- a/api/BUILD +++ b/api/BUILD @@ -190,6 +190,7 @@ proto_library( "//envoy/extensions/filters/http/health_check/v3:pkg", "//envoy/extensions/filters/http/ip_tagging/v3:pkg", "//envoy/extensions/filters/http/jwt_authn/v3:pkg", + "//envoy/extensions/filters/http/kill_request/v3:pkg", "//envoy/extensions/filters/http/local_ratelimit/v3:pkg", "//envoy/extensions/filters/http/lua/v3:pkg", "//envoy/extensions/filters/http/oauth2/v3alpha:pkg", diff --git a/api/envoy/config/bootstrap/v3/bootstrap.proto b/api/envoy/config/bootstrap/v3/bootstrap.proto index a9a0290b297cc..9581fd6ca7721 100644 --- a/api/envoy/config/bootstrap/v3/bootstrap.proto +++ b/api/envoy/config/bootstrap/v3/bootstrap.proto @@ -40,7 +40,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // ` for more detail. // Bootstrap :ref:`configuration overview `. -// [#next-free-field: 28] +// [#next-free-field: 29] message Bootstrap { option (udpa.annotations.versioning).previous_message_type = "envoy.config.bootstrap.v2.Bootstrap"; @@ -243,6 +243,10 @@ message Bootstrap { // Each item contains extension specific configuration. repeated core.v3.TypedExtensionConfig bootstrap_extensions = 21; + // Specifies optional extensions instantiated at startup time and + // invoked during crash time on the request that caused the crash. + repeated FatalAction fatal_actions = 28; + // Configuration sources that will participate in // *udpa.core.v1.ResourceLocator* authority resolution. The algorithm is as // follows: @@ -420,6 +424,20 @@ message Watchdog { type.v3.Percent multikill_threshold = 5; } +// Fatal actions to run while crashing. Actions can be safe (meaning they are +// async-signal safe) or unsafe. We run all safe actions before we run unsafe actions. +// If using an unsafe action that could get stuck or deadlock, it important to +// have an out of band system to terminate the process. +// +// The interface for the extension is ``Envoy::Server::Configuration::FatalAction``. +// *FatalAction* extensions live in the ``envoy.extensions.fatal_actions`` API +// namespace. +message FatalAction { + // Extension specific configuration for the action. It's expected to conform + // to the ``Envoy::Server::Configuration::FatalAction`` interface. + core.v3.TypedExtensionConfig config = 1; +} + // Runtime :ref:`configuration overview ` (deprecated). message Runtime { option (udpa.annotations.versioning).previous_message_type = "envoy.config.bootstrap.v2.Runtime"; diff --git a/api/envoy/config/bootstrap/v4alpha/bootstrap.proto b/api/envoy/config/bootstrap/v4alpha/bootstrap.proto index ef10dead97069..1fe40d6b9607a 100644 --- a/api/envoy/config/bootstrap/v4alpha/bootstrap.proto +++ b/api/envoy/config/bootstrap/v4alpha/bootstrap.proto @@ -38,7 +38,7 @@ option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSIO // ` for more detail. // Bootstrap :ref:`configuration overview `. -// [#next-free-field: 28] +// [#next-free-field: 29] message Bootstrap { option (udpa.annotations.versioning).previous_message_type = "envoy.config.bootstrap.v3.Bootstrap"; @@ -229,6 +229,10 @@ message Bootstrap { // Each item contains extension specific configuration. repeated core.v4alpha.TypedExtensionConfig bootstrap_extensions = 21; + // Specifies optional extensions instantiated at startup time and + // invoked during crash time on the request that caused the crash. + repeated FatalAction fatal_actions = 28; + // Configuration sources that will participate in // *udpa.core.v1.ResourceLocator* authority resolution. The algorithm is as // follows: @@ -412,6 +416,23 @@ message Watchdog { type.v3.Percent multikill_threshold = 5; } +// Fatal actions to run while crashing. Actions can be safe (meaning they are +// async-signal safe) or unsafe. We run all safe actions before we run unsafe actions. +// If using an unsafe action that could get stuck or deadlock, it important to +// have an out of band system to terminate the process. +// +// The interface for the extension is ``Envoy::Server::Configuration::FatalAction``. +// *FatalAction* extensions live in the ``envoy.extensions.fatal_actions`` API +// namespace. +message FatalAction { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.bootstrap.v3.FatalAction"; + + // Extension specific configuration for the action. It's expected to conform + // to the ``Envoy::Server::Configuration::FatalAction`` interface. + core.v4alpha.TypedExtensionConfig config = 1; +} + // Runtime :ref:`configuration overview ` (deprecated). message Runtime { option (udpa.annotations.versioning).previous_message_type = "envoy.config.bootstrap.v3.Runtime"; diff --git a/api/envoy/config/common/matcher/v3/matcher.proto b/api/envoy/config/common/matcher/v3/matcher.proto index 8a1cb4839c4a5..24ed5dafbdc54 100644 --- a/api/envoy/config/common/matcher/v3/matcher.proto +++ b/api/envoy/config/common/matcher/v3/matcher.proto @@ -4,7 +4,7 @@ package envoy.config.common.matcher.v3; import "envoy/config/core/v3/extension.proto"; import "envoy/config/route/v3/route_components.proto"; -import "envoy/type/matcher/v3/value.proto"; +import "envoy/type/matcher/v3/string.proto"; import "udpa/annotations/migrate.proto"; import "udpa/annotations/status.proto"; @@ -58,9 +58,8 @@ message Matcher { oneof matcher { option (validate.required) = true; - // Use existing infrastructure for actually matching the - // value. - type.matcher.v3.ValueMatcher value_match = 2; + // Built-in string matcher. + type.matcher.v3.StringMatcher value_match = 2; // Extension for custom matching logic. core.v3.TypedExtensionConfig custom_match = 3; diff --git a/api/envoy/config/common/matcher/v4alpha/matcher.proto b/api/envoy/config/common/matcher/v4alpha/matcher.proto index 15859474e6e12..ab1f4de6cccc1 100644 --- a/api/envoy/config/common/matcher/v4alpha/matcher.proto +++ b/api/envoy/config/common/matcher/v4alpha/matcher.proto @@ -4,7 +4,7 @@ package envoy.config.common.matcher.v4alpha; import "envoy/config/core/v4alpha/extension.proto"; import "envoy/config/route/v4alpha/route_components.proto"; -import "envoy/type/matcher/v4alpha/value.proto"; +import "envoy/type/matcher/v4alpha/string.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; @@ -72,9 +72,8 @@ message Matcher { oneof matcher { option (validate.required) = true; - // Use existing infrastructure for actually matching the - // value. - type.matcher.v4alpha.ValueMatcher value_match = 2; + // Built-in string matcher. + type.matcher.v4alpha.StringMatcher value_match = 2; // Extension for custom matching logic. core.v4alpha.TypedExtensionConfig custom_match = 3; diff --git a/api/envoy/config/core/v3/base.proto b/api/envoy/config/core/v3/base.proto index 4d7d69fae70bd..5b5339ea5bc5d 100644 --- a/api/envoy/config/core/v3/base.proto +++ b/api/envoy/config/core/v3/base.proto @@ -313,6 +313,13 @@ message HeaderMap { repeated HeaderValue headers = 1; } +// A directory that is watched for changes, e.g. by inotify on Linux. Move/rename +// events inside this directory trigger the watch. +message WatchedDirectory { + // Directory path to watch. + string path = 1 [(validate.rules).string = {min_len: 1}]; +} + // Data source consisting of either a file or an inline value. message DataSource { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.core.DataSource"; diff --git a/api/envoy/config/core/v4alpha/base.proto b/api/envoy/config/core/v4alpha/base.proto index dc1104a219b79..27b0b356b1a79 100644 --- a/api/envoy/config/core/v4alpha/base.proto +++ b/api/envoy/config/core/v4alpha/base.proto @@ -308,6 +308,16 @@ message HeaderMap { repeated HeaderValue headers = 1; } +// A directory that is watched for changes, e.g. by inotify on Linux. Move/rename +// events inside this directory trigger the watch. +message WatchedDirectory { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.core.v3.WatchedDirectory"; + + // Directory path to watch. + string path = 1 [(validate.rules).string = {min_len: 1}]; +} + // Data source consisting of either a file or an inline value. message DataSource { option (udpa.annotations.versioning).previous_message_type = "envoy.config.core.v3.DataSource"; diff --git a/api/envoy/config/trace/v3/zipkin.proto b/api/envoy/config/trace/v3/zipkin.proto index ee4e4d9b7898d..928e139831c59 100644 --- a/api/envoy/config/trace/v3/zipkin.proto +++ b/api/envoy/config/trace/v3/zipkin.proto @@ -46,9 +46,7 @@ message ZipkinConfig { GRPC = 3; } - // The cluster manager cluster that hosts the Zipkin collectors. Note that the - // Zipkin cluster must be defined in the :ref:`Bootstrap static cluster - // resources `. + // The cluster manager cluster that hosts the Zipkin collectors. string collector_cluster = 1 [(validate.rules).string = {min_len: 1}]; // The API endpoint of the Zipkin service where the spans will be sent. When diff --git a/api/envoy/extensions/filters/http/grpc_json_transcoder/v3/transcoder.proto b/api/envoy/extensions/filters/http/grpc_json_transcoder/v3/transcoder.proto index 3082089202eef..007ccabc3e47d 100644 --- a/api/envoy/extensions/filters/http/grpc_json_transcoder/v3/transcoder.proto +++ b/api/envoy/extensions/filters/http/grpc_json_transcoder/v3/transcoder.proto @@ -15,11 +15,27 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // gRPC-JSON transcoder :ref:`configuration overview `. // [#extension: envoy.filters.http.grpc_json_transcoder] -// [#next-free-field: 10] +// [#next-free-field: 11] message GrpcJsonTranscoder { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.http.transcoder.v2.GrpcJsonTranscoder"; + enum UrlUnescapeSpec { + // URL path parameters will not decode RFC 6570 reserved characters. + // For example, segment `%2f%23/%20%2523` is unescaped to `%2f%23/ %23`. + ALL_CHARACTERS_EXCEPT_RESERVED = 0; + + // URL path parameters will be fully URI-decoded except in + // cases of single segment matches in reserved expansion, where "%2F" will be + // left encoded. + // For example, segment `%2f%23/%20%2523` is unescaped to `%2f#/ %23`. + ALL_CHARACTERS_EXCEPT_SLASH = 1; + + // URL path parameters will be fully URI-decoded. + // For example, segment `%2f%23/%20%2523` is unescaped to `/#/ %23`. + ALL_CHARACTERS = 2; + } + message PrintOptions { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.http.transcoder.v2.GrpcJsonTranscoder.PrintOptions"; @@ -160,4 +176,11 @@ message GrpcJsonTranscoder { // the ``google/rpc/error_details.proto`` should be included in the configured // :ref:`proto descriptor set `. bool convert_grpc_status = 9; + + // URL unescaping policy. + // This spec is only applied when extracting variable with multiple segments. + // For example, in case of `/foo/{x=*}/bar/{y=prefix/*}/{z=**}` `x` variable is single segment and `y` and `z` are multiple segments. + // For a path with `/foo/first/bar/prefix/second/third/fourth`, `x=first`, `y=prefix/second`, `z=third/fourth`. + // If this setting is not specified, the value defaults to :ref:`ALL_CHARACTERS_EXCEPT_RESERVED`. + UrlUnescapeSpec url_unescape_spec = 10 [(validate.rules).enum = {defined_only: true}]; } diff --git a/api/envoy/extensions/filters/http/jwt_authn/v3/config.proto b/api/envoy/extensions/filters/http/jwt_authn/v3/config.proto index 0e4294608384f..a10fa68f30437 100644 --- a/api/envoy/extensions/filters/http/jwt_authn/v3/config.proto +++ b/api/envoy/extensions/filters/http/jwt_authn/v3/config.proto @@ -51,7 +51,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // cache_duration: // seconds: 300 // -// [#next-free-field: 10] +// [#next-free-field: 11] message JwtProvider { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.http.jwt_authn.v2alpha.JwtProvider"; @@ -191,6 +191,10 @@ message JwtProvider { // exp: 1501281058 // string payload_in_metadata = 9; + + // Specify the clock skew in seconds when verifying JWT time constraint, + // such as `exp`, and `nbf`. If not specified, default is 60 seconds. + uint32 clock_skew_seconds = 10; } // This message specifies how to fetch JWKS from remote and how to cache it. diff --git a/api/envoy/extensions/filters/http/jwt_authn/v4alpha/config.proto b/api/envoy/extensions/filters/http/jwt_authn/v4alpha/config.proto index 53ee84fd65ea6..2746640fa7380 100644 --- a/api/envoy/extensions/filters/http/jwt_authn/v4alpha/config.proto +++ b/api/envoy/extensions/filters/http/jwt_authn/v4alpha/config.proto @@ -51,7 +51,7 @@ option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSIO // cache_duration: // seconds: 300 // -// [#next-free-field: 10] +// [#next-free-field: 11] message JwtProvider { option (udpa.annotations.versioning).previous_message_type = "envoy.extensions.filters.http.jwt_authn.v3.JwtProvider"; @@ -191,6 +191,10 @@ message JwtProvider { // exp: 1501281058 // string payload_in_metadata = 9; + + // Specify the clock skew in seconds when verifying JWT time constraint, + // such as `exp`, and `nbf`. If not specified, default is 60 seconds. + uint32 clock_skew_seconds = 10; } // This message specifies how to fetch JWKS from remote and how to cache it. diff --git a/api/envoy/extensions/filters/http/kill_request/v3/BUILD b/api/envoy/extensions/filters/http/kill_request/v3/BUILD new file mode 100644 index 0000000000000..9a76b7e148e03 --- /dev/null +++ b/api/envoy/extensions/filters/http/kill_request/v3/BUILD @@ -0,0 +1,12 @@ +# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = [ + "//envoy/type/v3:pkg", + "@com_github_cncf_udpa//udpa/annotations:pkg", + ], +) diff --git a/api/envoy/extensions/filters/http/kill_request/v3/kill_request.proto b/api/envoy/extensions/filters/http/kill_request/v3/kill_request.proto new file mode 100644 index 0000000000000..fd7a3d3397c02 --- /dev/null +++ b/api/envoy/extensions/filters/http/kill_request/v3/kill_request.proto @@ -0,0 +1,23 @@ +syntax = "proto3"; + +package envoy.extensions.filters.http.kill_request.v3; + +import "envoy/type/v3/percent.proto"; + +import "udpa/annotations/status.proto"; +import "udpa/annotations/versioning.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.filters.http.kill_request.v3"; +option java_outer_classname = "KillRequestProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Kill Request] +// Kill Request :ref:`configuration overview `. +// [#extension: envoy.filters.http.kill_request] + +// Configuration for KillRequest filter. +message KillRequest { + // The probability that a Kill request will be triggered. + type.v3.FractionalPercent probability = 1; +} diff --git a/api/envoy/extensions/tracers/zipkin/v4alpha/zipkin.proto b/api/envoy/extensions/tracers/zipkin/v4alpha/zipkin.proto index a6974fcc0ea6e..5dbfdc00e6b32 100644 --- a/api/envoy/extensions/tracers/zipkin/v4alpha/zipkin.proto +++ b/api/envoy/extensions/tracers/zipkin/v4alpha/zipkin.proto @@ -44,9 +44,7 @@ message ZipkinConfig { GRPC = 3; } - // The cluster manager cluster that hosts the Zipkin collectors. Note that the - // Zipkin cluster must be defined in the :ref:`Bootstrap static cluster - // resources `. + // The cluster manager cluster that hosts the Zipkin collectors. string collector_cluster = 1 [(validate.rules).string = {min_len: 1}]; // The API endpoint of the Zipkin service where the spans will be sent. When diff --git a/api/envoy/extensions/transport_sockets/tls/v3/common.proto b/api/envoy/extensions/transport_sockets/tls/v3/common.proto index 2f45a754416b7..2b545b35ee12f 100644 --- a/api/envoy/extensions/transport_sockets/tls/v3/common.proto +++ b/api/envoy/extensions/transport_sockets/tls/v3/common.proto @@ -128,16 +128,37 @@ message PrivateKeyProvider { } } -// [#next-free-field: 7] +// [#next-free-field: 8] message TlsCertificate { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.auth.TlsCertificate"; // The TLS certificate chain. + // + // If *certificate_chain* is a filesystem path, a watch will be added to the + // parent directory for any file moves to support rotation. This currently + // only applies to dynamic secrets, when the *TlsCertificate* is delivered via + // SDS. config.core.v3.DataSource certificate_chain = 1; // The TLS private key. + // + // If *private_key* is a filesystem path, a watch will be added to the parent + // directory for any file moves to support rotation. This currently only + // applies to dynamic secrets, when the *TlsCertificate* is delivered via SDS. config.core.v3.DataSource private_key = 2 [(udpa.annotations.sensitive) = true]; + // If specified, updates of file-based *certificate_chain* and *private_key* + // sources will be triggered by this watch. The certificate/key pair will be + // read together and validated for atomic read consistency (i.e. no + // intervening modification occurred between cert/key read, verified by file + // hash comparisons). This allows explicit control over the path watched, by + // default the parent directories of the filesystem paths in + // *certificate_chain* and *private_key* are watched if this field is not + // specified. This only applies when a *TlsCertificate* is delivered by SDS + // with references to filesystem paths. See the :ref:`SDS key rotation + // ` documentation for further details. + config.core.v3.WatchedDirectory watched_directory = 7; + // BoringSSL private key method provider. This is an alternative to :ref:`private_key // ` field. This can't be // marked as ``oneof`` due to API compatibility reasons. Setting both :ref:`private_key @@ -191,7 +212,7 @@ message TlsSessionTicketKeys { [(validate.rules).repeated = {min_items: 1}, (udpa.annotations.sensitive) = true]; } -// [#next-free-field: 11] +// [#next-free-field: 12] message CertificateValidationContext { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.auth.CertificateValidationContext"; @@ -233,8 +254,22 @@ message CertificateValidationContext { // // See :ref:`the TLS overview ` for a list of common // system CA locations. + // + // If *trusted_ca* is a filesystem path, a watch will be added to the parent + // directory for any file moves to support rotation. This currently only + // applies to dynamic secrets, when the *CertificateValidationContext* is + // delivered via SDS. config.core.v3.DataSource trusted_ca = 1; + // If specified, updates of a file-based *trusted_ca* source will be triggered + // by this watch. This allows explicit control over the path watched, by + // default the parent directory of the filesystem path in *trusted_ca* is + // watched if this field is not specified. This only applies when a + // *CertificateValidationContext* is delivered by SDS with references to + // filesystem paths. See the :ref:`SDS key rotation ` + // documentation for further details. + config.core.v3.WatchedDirectory watched_directory = 11; + // An optional list of base64-encoded SHA-256 hashes. If specified, Envoy will verify that the // SHA-256 of the DER-encoded Subject Public Key Information (SPKI) of the presented certificate // matches one of the specified values. diff --git a/api/envoy/extensions/transport_sockets/tls/v4alpha/common.proto b/api/envoy/extensions/transport_sockets/tls/v4alpha/common.proto index 1382863cb804c..30859bc2a3eb9 100644 --- a/api/envoy/extensions/transport_sockets/tls/v4alpha/common.proto +++ b/api/envoy/extensions/transport_sockets/tls/v4alpha/common.proto @@ -129,17 +129,38 @@ message PrivateKeyProvider { } } -// [#next-free-field: 7] +// [#next-free-field: 8] message TlsCertificate { option (udpa.annotations.versioning).previous_message_type = "envoy.extensions.transport_sockets.tls.v3.TlsCertificate"; // The TLS certificate chain. + // + // If *certificate_chain* is a filesystem path, a watch will be added to the + // parent directory for any file moves to support rotation. This currently + // only applies to dynamic secrets, when the *TlsCertificate* is delivered via + // SDS. config.core.v4alpha.DataSource certificate_chain = 1; // The TLS private key. + // + // If *private_key* is a filesystem path, a watch will be added to the parent + // directory for any file moves to support rotation. This currently only + // applies to dynamic secrets, when the *TlsCertificate* is delivered via SDS. config.core.v4alpha.DataSource private_key = 2 [(udpa.annotations.sensitive) = true]; + // If specified, updates of file-based *certificate_chain* and *private_key* + // sources will be triggered by this watch. The certificate/key pair will be + // read together and validated for atomic read consistency (i.e. no + // intervening modification occurred between cert/key read, verified by file + // hash comparisons). This allows explicit control over the path watched, by + // default the parent directories of the filesystem paths in + // *certificate_chain* and *private_key* are watched if this field is not + // specified. This only applies when a *TlsCertificate* is delivered by SDS + // with references to filesystem paths. See the :ref:`SDS key rotation + // ` documentation for further details. + config.core.v4alpha.WatchedDirectory watched_directory = 7; + // BoringSSL private key method provider. This is an alternative to :ref:`private_key // ` field. This can't be // marked as ``oneof`` due to API compatibility reasons. Setting both :ref:`private_key @@ -193,7 +214,7 @@ message TlsSessionTicketKeys { [(validate.rules).repeated = {min_items: 1}, (udpa.annotations.sensitive) = true]; } -// [#next-free-field: 11] +// [#next-free-field: 12] message CertificateValidationContext { option (udpa.annotations.versioning).previous_message_type = "envoy.extensions.transport_sockets.tls.v3.CertificateValidationContext"; @@ -235,8 +256,22 @@ message CertificateValidationContext { // // See :ref:`the TLS overview ` for a list of common // system CA locations. + // + // If *trusted_ca* is a filesystem path, a watch will be added to the parent + // directory for any file moves to support rotation. This currently only + // applies to dynamic secrets, when the *CertificateValidationContext* is + // delivered via SDS. config.core.v4alpha.DataSource trusted_ca = 1; + // If specified, updates of a file-based *trusted_ca* source will be triggered + // by this watch. This allows explicit control over the path watched, by + // default the parent directory of the filesystem path in *trusted_ca* is + // watched if this field is not specified. This only applies when a + // *CertificateValidationContext* is delivered by SDS with references to + // filesystem paths. See the :ref:`SDS key rotation ` + // documentation for further details. + config.core.v4alpha.WatchedDirectory watched_directory = 11; + // An optional list of base64-encoded SHA-256 hashes. If specified, Envoy will verify that the // SHA-256 of the DER-encoded Subject Public Key Information (SPKI) of the presented certificate // matches one of the specified values. diff --git a/api/envoy/extensions/wasm/v3/wasm.proto b/api/envoy/extensions/wasm/v3/wasm.proto index b42fb75a0bf7c..c6affb8106115 100644 --- a/api/envoy/extensions/wasm/v3/wasm.proto +++ b/api/envoy/extensions/wasm/v3/wasm.proto @@ -28,7 +28,29 @@ message VmConfig { // See ref: "TODO: add ref" for details. string vm_id = 1; - // The Wasm runtime type (either "v8" or "null" for code compiled into Envoy). + // The Wasm runtime type. + // Available Wasm runtime types are registered as extensions. The following runtimes are included + // in Envoy code base: + // + // .. _extension_envoy.wasm.runtime.null: + // + // **envoy.wasm.runtime.null**: Null sandbox, the Wasm module must be compiled and linked into the + // Envoy binary. The registered name is given in the *code* field as *inline_string*. + // + // .. _extension_envoy.wasm.runtime.v8: + // + // **envoy.wasm.runtime.v8**: `V8 `_-based WebAssembly runtime. + // + // .. _extension_envoy.wasm.runtime.wavm: + // + // **envoy.wasm.runtime.wavm**: `WAVM `_-based WebAssembly runtime. + // This runtime is not enabled in the official build. + // + // .. _extension_envoy.wasm.runtime.wasmtime: + // + // **envoy.wasm.runtime.wasmtime**: `Wasmtime `_-based WebAssembly runtime. + // This runtime is not enabled in the official build. + // string runtime = 2 [(validate.rules).string = {min_len: 1}]; // The Wasm code that Envoy will execute. diff --git a/api/versioning/BUILD b/api/versioning/BUILD index dc1162bb93c7c..efd4715f83f96 100644 --- a/api/versioning/BUILD +++ b/api/versioning/BUILD @@ -73,6 +73,7 @@ proto_library( "//envoy/extensions/filters/http/health_check/v3:pkg", "//envoy/extensions/filters/http/ip_tagging/v3:pkg", "//envoy/extensions/filters/http/jwt_authn/v3:pkg", + "//envoy/extensions/filters/http/kill_request/v3:pkg", "//envoy/extensions/filters/http/local_ratelimit/v3:pkg", "//envoy/extensions/filters/http/lua/v3:pkg", "//envoy/extensions/filters/http/oauth2/v3alpha:pkg", diff --git a/bazel/BUILD b/bazel/BUILD index 268cdb752ec64..8f1b7f605278c 100644 --- a/bazel/BUILD +++ b/bazel/BUILD @@ -277,8 +277,8 @@ config_setting( ) config_setting( - name = "enable_new_codecs_in_integration_tests", - values = {"define": "use_new_codecs_in_integration_tests=true"}, + name = "enable_legacy_codecs_in_integration_tests", + values = {"define": "use_new_codecs_in_integration_tests=false"}, ) cc_proto_library( diff --git a/bazel/README.md b/bazel/README.md index f2b79eab5c003..50379a6efd0a1 100644 --- a/bazel/README.md +++ b/bazel/README.md @@ -126,14 +126,19 @@ for how to update or override dependencies. Install bazelisk in the PATH using the `bazel.exe` executable name as described above in the first section. When building Envoy, Bazel creates very long path names. One way to work around these excessive path - lengths is to change the output base directory for bazel to a very short root path. The CI pipeline - for Windows uses `C:\_eb` as the bazel base path. This and other preferences should be set up by placing + lengths is to change the output base directory for bazel to a very short root path. An example Bazel configuration + to help with this is to use `C:\_eb` as the bazel base path. This and other preferences should be set up by placing the following bazelrc configuration line in a system `%ProgramData%\bazel.bazelrc` file or the individual user's `%USERPROFILE%\.bazelrc` file (rather than including it on every bazel command line): + ``` startup --output_base=C:/_eb ``` + Another option to shorten the the output root for Bazel is to set the `USERNAME` environment variable in your shell + session to a short value. Bazel uses this value when constructing its output root path if no explicit `--output_base` + is set. + Bazel also creates file symlinks when building Envoy. It's strongly recommended to enable file symlink support using [Bazel's instructions](https://docs.bazel.build/versions/master/windows.html#enable-symlink-support). For other common issues, see the @@ -721,13 +726,18 @@ https://github.com/bazelbuild/bazel/issues/2805. # Coverage builds -To generate coverage results, make sure you are using a clang toolchain and have `llvm-cov` and +To generate coverage results, make sure you are using a Clang toolchain and have `llvm-cov` and `llvm-profdata` in your `PATH`. Then run: ``` test/run_envoy_bazel_coverage.sh ``` +**Note** that it is important to ensure that the versions of `clang`, `llvm-cov` and `llvm-profdata` +are consistent and that they match the most recent Clang/LLVM toolchain version in use by Envoy (see +the [build container +toolchain](https://github.com/envoyproxy/envoy-build-tools/blob/master/build_container/build_container_ubuntu.sh) for reference). + The summary results are printed to the standard output and the full coverage report is available in `generated/coverage/coverage.html`. diff --git a/bazel/envoy_internal.bzl b/bazel/envoy_internal.bzl index 91d7ac2abee8b..c122e36cd9c76 100644 --- a/bazel/envoy_internal.bzl +++ b/bazel/envoy_internal.bzl @@ -63,6 +63,8 @@ def envoy_copts(repository, test = False): }) + select({ repository + "//bazel:clang_build": ["-fno-limit-debug-info", "-Wgnu-conditional-omitted-operand", "-Wc++2a-extensions", "-Wrange-loop-analysis"], repository + "//bazel:gcc_build": ["-Wno-maybe-uninitialized"], + # TODO: Replace with /Zc:preprocessor for cl.exe versions >= 16.5 + repository + "//bazel:windows_x86_64": ["-experimental:preprocessor", "-Wv:19.4"], "//conditions:default": [], }) + select({ repository + "//bazel:no_debug_info": ["-g0"], diff --git a/bazel/envoy_library.bzl b/bazel/envoy_library.bzl index adcee0750790e..a2f7c6b0ae028 100644 --- a/bazel/envoy_library.bzl +++ b/bazel/envoy_library.bzl @@ -144,7 +144,7 @@ def envoy_cc_library( hdrs = hdrs, copts = envoy_copts(repository) + copts, visibility = visibility, - tags = ["nocompdb"], + tags = ["nocompdb"] + tags, deps = [":" + name], strip_include_prefix = strip_include_prefix, ) diff --git a/bazel/envoy_select.bzl b/bazel/envoy_select.bzl index 8cbecb26075cc..b0789ae51291c 100644 --- a/bazel/envoy_select.bzl +++ b/bazel/envoy_select.bzl @@ -59,9 +59,9 @@ def envoy_select_wasm_wasmtime(xs): "//conditions:default": [], }) -# Select the given values if use legacy codecs in test is on in the current build. +# Select the given values by default and remove if use new codecs are disabled for current build. def envoy_select_new_codecs_in_integration_tests(xs, repository = ""): return select({ - repository + "//bazel:enable_new_codecs_in_integration_tests": xs, - "//conditions:default": [], + repository + "//bazel:enable_legacy_codecs_in_integration_tests": [], + "//conditions:default": xs, }) diff --git a/bazel/external/proxy_wasm_cpp_host.BUILD b/bazel/external/proxy_wasm_cpp_host.BUILD index 6157654ed5ea2..148635bc099de 100644 --- a/bazel/external/proxy_wasm_cpp_host.BUILD +++ b/bazel/external/proxy_wasm_cpp_host.BUILD @@ -1,10 +1,4 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load( - "@envoy//bazel:envoy_build_system.bzl", - "envoy_select_wasm_v8", - "envoy_select_wasm_wasmtime", - "envoy_select_wasm_wavm", -) licenses(["notice"]) # Apache 2 @@ -19,29 +13,14 @@ cc_library( ) cc_library( - name = "lib", - # Note that the select cannot appear in the glob. - srcs = glob( - [ - "src/**/*.h", - "src/**/*.cc", - ], - exclude = [ - "src/v8/*.cc", - "src/wavm/*.cc", - "src/wasmtime/*.cc", - ], - ) + envoy_select_wasm_v8(glob([ - "src/v8/*.cc", - ])) + envoy_select_wasm_wavm(glob([ - "src/wavm/*.cc", - ])) + envoy_select_wasm_wasmtime(glob([ - "src/wasmtime/*.cc", - ])), - copts = envoy_select_wasm_wavm([ - '-DWAVM_API=""', - "-Wno-non-virtual-dtor", - "-Wno-old-style-cast", + name = "common_lib", + srcs = glob([ + "src/*.h", + "src/*.cc", + "src/common/*.h", + "src/common/*.cc", + "src/third_party/*.h", + "src/third_party/*.cc", ]), deps = [ ":include", @@ -53,11 +32,54 @@ cc_library( "//external:zlib", "@proxy_wasm_cpp_sdk//:api_lib", "@proxy_wasm_cpp_sdk//:common_lib", - ] + envoy_select_wasm_v8([ + ], +) + +cc_library( + name = "null_lib", + srcs = glob([ + "src/null/*.cc", + ]), + deps = [ + ":common_lib", + ], +) + +cc_library( + name = "v8_lib", + srcs = glob([ + "src/v8/*.cc", + ]), + deps = [ + ":common_lib", "//external:wee8", - ]) + envoy_select_wasm_wavm([ + ], +) + +cc_library( + name = "wavm_lib", + srcs = glob([ + "src/wavm/*.cc", + ]), + copts = [ + '-DWAVM_API=""', + "-Wno-non-virtual-dtor", + "-Wno-old-style-cast", + ], + deps = [ + ":common_lib", "@envoy//bazel/foreign_cc:wavm", - ]) + envoy_select_wasm_wasmtime([ - "@com_github_wasm_c_api//:wasmtime_lib", + ], +) + +cc_library( + name = "wasmtime_lib", + srcs = glob([ + "src/wasmtime/*.h", + "src/wasmtime/*.cc", ]), + deps = [ + ":common_lib", + "@com_github_wasm_c_api//:wasmtime_lib", + ], ) diff --git a/bazel/external/quiche.BUILD b/bazel/external/quiche.BUILD index 7541909aa1914..a3c430cf9fa4d 100644 --- a/bazel/external/quiche.BUILD +++ b/bazel/external/quiche.BUILD @@ -57,16 +57,12 @@ quiche_common_copts = [ "-Wno-unused-function", # quic_inlined_frame.h uses offsetof() to optimize memory usage in frames. "-Wno-invalid-offsetof", - "-Wno-range-loop-analysis", ] quiche_copts = select({ # Ignore unguarded #pragma GCC statements in QUICHE sources "@envoy//bazel:windows_x86_64": ["-wd4068"], # Remove these after upstream fix. - "@envoy//bazel:gcc_build": [ - "-Wno-sign-compare", - ] + quiche_common_copts, "//conditions:default": quiche_common_copts, }) @@ -737,7 +733,6 @@ envoy_cc_library( hdrs = [ "quiche/spdy/platform/api/spdy_bug_tracker.h", "quiche/spdy/platform/api/spdy_containers.h", - "quiche/spdy/platform/api/spdy_endianness_util.h", "quiche/spdy/platform/api/spdy_estimate_memory_usage.h", "quiche/spdy/platform/api/spdy_flags.h", "quiche/spdy/platform/api/spdy_logging.h", @@ -935,6 +930,7 @@ envoy_cc_library( copts = quiche_copts, repository = "@envoy", deps = [ + ":http2_hpack_huffman_hpack_huffman_encoder_lib", ":spdy_core_protocol_lib", ":spdy_platform", ], @@ -1049,19 +1045,16 @@ envoy_cc_library( envoy_cc_library( name = "quic_platform_base", hdrs = [ - "quiche/quic/platform/api/quic_aligned.h", "quiche/quic/platform/api/quic_bug_tracker.h", "quiche/quic/platform/api/quic_client_stats.h", "quiche/quic/platform/api/quic_containers.h", "quiche/quic/platform/api/quic_error_code_wrappers.h", "quiche/quic/platform/api/quic_estimate_memory_usage.h", "quiche/quic/platform/api/quic_exported_stats.h", - "quiche/quic/platform/api/quic_fallthrough.h", "quiche/quic/platform/api/quic_flag_utils.h", "quiche/quic/platform/api/quic_flags.h", "quiche/quic/platform/api/quic_iovec.h", "quiche/quic/platform/api/quic_logging.h", - "quiche/quic/platform/api/quic_macros.h", "quiche/quic/platform/api/quic_map_util.h", "quiche/quic/platform/api/quic_mem_slice.h", "quiche/quic/platform/api/quic_prefetch.h", @@ -1072,6 +1065,7 @@ envoy_cc_library( "quiche/quic/platform/api/quic_stream_buffer_allocator.h", "quiche/quic/platform/api/quic_string_utils.h", "quiche/quic/platform/api/quic_uint128.h", + "quiche/quic/platform/api/quic_testvalue.h", # TODO: uncomment the following files as implementations are added. # "quiche/quic/platform/api/quic_fuzzed_data_provider.h", # "quiche/quic/platform/api/quic_test_loopback.h", @@ -1147,7 +1141,6 @@ envoy_cc_test_library( hdrs = ["quiche/quic/platform/api/quic_port_utils.h"], repository = "@envoy", tags = ["nofips"], - deps = ["@envoy//test/extensions/quic_listeners/quiche/platform:quic_platform_port_utils_impl_lib"], ) envoy_cc_library( @@ -1216,15 +1209,14 @@ envoy_cc_test_library( ) envoy_cc_library( - name = "quiche_common_platform_endian", - hdrs = ["quiche/common/platform/api/quiche_endian.h"], + name = "quiche_common_endian_lib", + hdrs = ["quiche/common/quiche_endian.h"], repository = "@envoy", tags = ["nofips"], visibility = ["//visibility:public"], deps = [ ":quiche_common_platform_export", - "@envoy//source/extensions/quic_listeners/quiche/platform:quiche_common_platform_endian_impl_lib", ], ) @@ -1932,6 +1924,7 @@ envoy_cc_library( visibility = ["//visibility:public"], deps = [ ":quic_core_clock_lib", + ":quic_core_crypto_certificate_view_lib", ":quic_core_crypto_encryption_lib", ":quic_core_crypto_hkdf_lib", ":quic_core_crypto_proof_source_interface_lib", @@ -2167,6 +2160,15 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "quic_core_flags_list_lib", + hdrs = ["quiche/quic/core/quic_flags_list.h"], + copts = quiche_copts, + repository = "@envoy", + tags = ["nofips"], + visibility = ["//visibility:public"], +) + envoy_cc_library( name = "quic_core_framer_lib", srcs = ["quiche/quic/core/quic_framer.cc"], @@ -2339,6 +2341,7 @@ envoy_cc_library( repository = "@envoy", tags = ["nofips"], deps = [ + ":http2_constants_lib", ":quic_core_data_lib", ":quic_core_error_codes_lib", ":quic_core_http_http_frames_lib", @@ -2723,6 +2726,27 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "quic_core_path_validator_lib", + srcs = ["quiche/quic/core/quic_path_validator.cc"], + hdrs = ["quiche/quic/core/quic_path_validator.h"], + copts = quiche_copts, + repository = "@envoy", + tags = ["nofips"], + deps = [ + ":quic_core_alarm_factory_interface_lib", + ":quic_core_alarm_interface_lib", + ":quic_core_arena_scoped_ptr_lib", + ":quic_core_clock_lib", + ":quic_core_constants_lib", + ":quic_core_crypto_random_lib", + ":quic_core_one_block_arena_lib", + ":quic_core_packet_writer_interface_lib", + ":quic_core_types_lib", + ":quic_platform", + ], +) + envoy_cc_library( name = "quic_core_process_packet_interface_lib", hdrs = ["quiche/quic/core/quic_process_packet_interface.h"], @@ -2735,6 +2759,15 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "quic_core_protocol_flags_list_lib", + hdrs = ["quiche/quic/core/quic_protocol_flags_list.h"], + copts = quiche_copts, + repository = "@envoy", + tags = ["nofips"], + visibility = ["//visibility:public"], +) + envoy_cc_library( name = "quic_core_qpack_blocking_manager_lib", srcs = ["quiche/quic/core/qpack/qpack_blocking_manager.cc"], @@ -2896,6 +2929,7 @@ envoy_cc_library( deps = [ ":http2_decoder_decode_buffer_lib", ":http2_decoder_decode_status_lib", + ":quic_core_error_codes_lib", ":quic_core_qpack_qpack_instruction_decoder_lib", ":quic_core_qpack_qpack_instructions_lib", ":quic_core_qpack_qpack_stream_receiver_lib", @@ -3368,7 +3402,7 @@ envoy_cc_library( ":quic_core_error_codes_lib", ":quic_core_time_lib", ":quic_platform_base", - ":quiche_common_platform_endian", + ":quiche_common_endian_lib", ], ) @@ -3420,6 +3454,7 @@ envoy_cc_library( repository = "@envoy", tags = ["nofips"], deps = [ + ":quic_core_circular_deque_lib", ":quic_core_connection_stats_lib", ":quic_core_packets_lib", ":quic_core_session_notifier_interface_lib", @@ -3459,6 +3494,7 @@ envoy_cc_library( deps = [ ":quic_core_versions_lib", ":quic_platform_base", + ":quiche_common_endian_lib", ], ) @@ -3475,7 +3511,6 @@ envoy_cc_library( ":quic_core_tag_lib", ":quic_core_types_lib", ":quic_platform_base", - ":quiche_common_platform_endian", ], ) @@ -3619,6 +3654,35 @@ envoy_cc_test_library( ], ) +envoy_cc_test_library( + name = "quic_test_tools_qpack_qpack_encoder_test_utils_lib", + srcs = ["quiche/quic/test_tools/qpack/qpack_encoder_test_utils.cc"], + hdrs = ["quiche/quic/test_tools/qpack/qpack_encoder_test_utils.h"], + copts = quiche_copts, + repository = "@envoy", + tags = ["nofips"], + deps = [ + ":quic_core_qpack_qpack_encoder_lib", + ":quic_platform_test", + ":quic_test_tools_qpack_qpack_test_utils_lib", + ":spdy_core_header_block_lib", + ":spdy_core_hpack_hpack_lib", + ], +) + +envoy_cc_test_library( + name = "quic_test_tools_qpack_qpack_test_utils_lib", + srcs = ["quiche/quic/test_tools/qpack/qpack_test_utils.cc"], + hdrs = ["quiche/quic/test_tools/qpack/qpack_test_utils.h"], + copts = quiche_copts, + repository = "@envoy", + tags = ["nofips"], + deps = [ + ":quic_core_qpack_qpack_stream_sender_delegate_lib", + ":quic_platform_test", + ], +) + envoy_cc_test_library( name = "quic_test_tools_sent_packet_manager_peer_lib", srcs = ["quiche/quic/test_tools/quic_sent_packet_manager_peer.cc"], @@ -3746,6 +3810,7 @@ envoy_cc_test_library( ":quic_core_packet_creator_lib", ":quic_core_packet_writer_interface_lib", ":quic_core_packets_lib", + ":quic_core_path_validator_lib", ":quic_core_received_packet_manager_lib", ":quic_core_sent_packet_manager_lib", ":quic_core_server_id_lib", @@ -3836,25 +3901,10 @@ envoy_cc_test_library( deps = [":epoll_server_platform"], ) -envoy_cc_library( - name = "quiche_common_platform_optional", - hdrs = ["quiche/common/platform/api/quiche_optional.h"], - repository = "@envoy", - tags = ["nofips"], - visibility = ["//visibility:public"], - deps = [ - ":quiche_common_platform_export", - "@envoy//source/extensions/quic_listeners/quiche/platform:quiche_common_platform_optional_impl_lib", - ], -) - envoy_cc_library( name = "quiche_common_platform", hdrs = [ - "quiche/common/platform/api/quiche_arraysize.h", "quiche/common/platform/api/quiche_logging.h", - "quiche/common/platform/api/quiche_optional.h", - "quiche/common/platform/api/quiche_ptr_util.h", "quiche/common/platform/api/quiche_str_cat.h", "quiche/common/platform/api/quiche_string_piece.h", "quiche/common/platform/api/quiche_text_utils.h", @@ -3866,7 +3916,6 @@ envoy_cc_library( visibility = ["//visibility:public"], deps = [ ":quiche_common_platform_export", - ":quiche_common_platform_optional", "@envoy//source/extensions/quic_listeners/quiche/platform:quiche_common_platform_impl_lib", ], ) @@ -3874,7 +3923,6 @@ envoy_cc_library( envoy_cc_test_library( name = "quiche_common_platform_test", srcs = [ - "quiche/common/platform/api/quiche_endian_test.cc", "quiche/common/platform/api/quiche_str_cat_test.cc", "quiche/common/platform/api/quiche_text_utils_test.cc", "quiche/common/platform/api/quiche_time_utils_test.cc", @@ -3884,7 +3932,6 @@ envoy_cc_test_library( tags = ["nofips"], deps = [ ":quiche_common_platform", - ":quiche_common_platform_endian", "@envoy//test/extensions/quic_listeners/quiche/platform:quiche_common_platform_test_impl_lib", ], ) @@ -3904,8 +3951,8 @@ envoy_cc_library( tags = ["nofips"], visibility = ["//visibility:public"], deps = [ + ":quiche_common_endian_lib", ":quiche_common_platform", - ":quiche_common_platform_endian", ], ) @@ -3944,6 +3991,7 @@ envoy_cc_test( deps = [ ":http2_platform", ":http2_test_tools_random", + ":quiche_common_test_tools_test_utils_lib", ], ) diff --git a/bazel/repository_locations.bzl b/bazel/repository_locations.bzl index 402f03c42bdf9..77a28e6596138 100644 --- a/bazel/repository_locations.bzl +++ b/bazel/repository_locations.bzl @@ -60,18 +60,18 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_name = "BoringSSL", project_desc = "Minimal OpenSSL fork", project_url = "https://github.com/google/boringssl", - version = "2192bbc878822cf6ab5977d4257a1339453d9d39", - sha256 = "bb55b0ed2f0cb548b5dce6a6b8307ce37f7f748eb9f1be6bfe2d266ff2b4d52b", + version = "1ce6682c7f6cfe0426ed54a37c10775bea9d3502", + sha256 = "b878d84f90b9a95fa1e53f46f1b69a5116621e117a6d4dbf602d884311ee6aa7", strip_prefix = "boringssl-{version}", # To update BoringSSL, which tracks Chromium releases: # 1. Open https://omahaproxy.appspot.com/ and note of linux/stable release. # 2. Open https://chromium.googlesource.com/chromium/src/+/refs/tags//DEPS and note . # 3. Find a commit in BoringSSL's "master-with-bazel" branch that merges . # - # chromium-86.0.4240.80 + # chromium-87.0.4280.66 urls = ["https://github.com/google/boringssl/archive/{version}.tar.gz"], use_category = ["controlplane", "dataplane_core"], - release_date = "2020-07-30", + release_date = "2020-09-21", cpe = "cpe:2.3:a:google:boringssl:*", ), boringssl_fips = dict( @@ -408,13 +408,13 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_name = "jwt_verify_lib", project_desc = "JWT verification library for C++", project_url = "https://github.com/google/jwt_verify_lib", - version = "7276a339af8426724b744216f619c99152f8c141", - sha256 = "f1fde4f3ebb3b2d841332c7a02a4b50e0529a19709934c63bc6208d1bbe28fb1", + version = "28efec2e4df1072db0ed03597591360ec9f80aac", + sha256 = "7a5c35b7cbf633398503ae12cad8c2833e92b3a796eed68b6256d22d51ace5e1", strip_prefix = "jwt_verify_lib-{version}", urls = ["https://github.com/google/jwt_verify_lib/archive/{version}.tar.gz"], use_category = ["dataplane_ext"], extensions = ["envoy.filters.http.jwt_authn"], - release_date = "2020-07-10", + release_date = "2020-11-04", cpe = "N/A", ), com_github_nodejs_http_parser = dict( @@ -507,13 +507,13 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_name = "grpc-httpjson-transcoding", project_desc = "Library that supports transcoding so that HTTP/JSON can be converted to gRPC", project_url = "https://github.com/grpc-ecosystem/grpc-httpjson-transcoding", - version = "b48d8aa15b3825e146168146755475ab918e95b7", - sha256 = "4147e992ec239fb78c435fdd9f68e8d93d89106f67278bf2995f3672dddba52b", + version = "4d095f048889d4fc3b8d4579aa80ca4290319802", + sha256 = "7af66e0674340932683ab4f04ea6f03e2550849a54741738d94310b84d396a2c", strip_prefix = "grpc-httpjson-transcoding-{version}", urls = ["https://github.com/grpc-ecosystem/grpc-httpjson-transcoding/archive/{version}.tar.gz"], use_category = ["dataplane_ext"], extensions = ["envoy.filters.http.grpc_json_transcoder"], - release_date = "2020-11-05", + release_date = "2020-11-12", cpe = "N/A", ), io_bazel_rules_go = dict( @@ -587,13 +587,7 @@ REPOSITORY_LOCATIONS_SPEC = dict( urls = ["https://github.com/llvm/llvm-project/releases/download/llvmorg-{version}/llvm-{version}.src.tar.xz"], release_date = "2020-03-23", use_category = ["dataplane_ext"], - extensions = [ - "envoy.access_loggers.wasm", - "envoy.bootstrap.wasm", - "envoy.filters.http.wasm", - "envoy.filters.network.wasm", - "envoy.stat_sinks.wasm", - ], + extensions = ["envoy.wasm.runtime.wavm"], cpe = "cpe:2.3:a:llvm:*:*", ), com_github_wavm_wavm = dict( @@ -606,13 +600,7 @@ REPOSITORY_LOCATIONS_SPEC = dict( urls = ["https://github.com/WAVM/WAVM/archive/{version}.tar.gz"], release_date = "2020-09-17", use_category = ["dataplane_ext"], - extensions = [ - "envoy.access_loggers.wasm", - "envoy.bootstrap.wasm", - "envoy.filters.http.wasm", - "envoy.filters.network.wasm", - "envoy.stat_sinks.wasm", - ], + extensions = ["envoy.wasm.runtime.wavm"], cpe = "cpe:2.3:a:webassembly_virtual_machine_project:webassembly_virtual_machine:*", ), com_github_wasmtime = dict( @@ -625,14 +613,8 @@ REPOSITORY_LOCATIONS_SPEC = dict( urls = ["https://github.com/bytecodealliance/wasmtime/archive/v{version}.tar.gz"], release_date = "2020-11-05", use_category = ["dataplane_ext"], - extensions = [ - "envoy.access_loggers.wasm", - "envoy.bootstrap.wasm", - "envoy.filters.http.wasm", - "envoy.filters.network.wasm", - "envoy.stat_sinks.wasm", - ], - cpe = "cpe:2.3:a:webassembly_virtual_machine_project:webassembly_virtual_machine:*", + extensions = ["envoy.wasm.runtime.wasmtime"], + cpe = "N/A", ), com_github_wasm_c_api = dict( project_name = "wasm-c-api", @@ -646,13 +628,7 @@ REPOSITORY_LOCATIONS_SPEC = dict( urls = ["https://github.com/WebAssembly/wasm-c-api/archive/{version}.tar.gz"], release_date = "2019-11-14", use_category = ["dataplane_ext"], - extensions = [ - "envoy.access_loggers.wasm", - "envoy.bootstrap.wasm", - "envoy.filters.http.wasm", - "envoy.filters.network.wasm", - "envoy.stat_sinks.wasm", - ], + extensions = ["envoy.wasm.runtime.wasmtime"], cpe = "N/A", ), io_opencensus_cpp = dict( @@ -697,13 +673,7 @@ REPOSITORY_LOCATIONS_SPEC = dict( sha256 = "f22734640e0515bc34d1ca3772513aef24374fafa44d0489d3a9a57cadec69fb", urls = ["https://storage.googleapis.com/envoyproxy-wee8/wee8-{version}.tar.gz"], use_category = ["dataplane_ext"], - extensions = [ - "envoy.access_loggers.wasm", - "envoy.bootstrap.wasm", - "envoy.filters.http.wasm", - "envoy.filters.network.wasm", - "envoy.stat_sinks.wasm", - ], + extensions = ["envoy.wasm.runtime.v8"], release_date = "2020-10-27", cpe = "cpe:2.3:a:google:v8:*", ), @@ -711,13 +681,13 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_name = "QUICHE", project_desc = "QUICHE (QUIC, HTTP/2, Etc) is Google‘s implementation of QUIC and related protocols", project_url = "https://quiche.googlesource.com/quiche", - # Static snapshot of https://quiche.googlesource.com/quiche/+archive/f555d99a084cdd086a349548c70fb558ac5847cf.tar.gz - version = "f555d99a084cdd086a349548c70fb558ac5847cf", - sha256 = "1833f08e7b0f18b49d7498b029b7f3e6559a82113ec82a98a9e945553756e351", + # Static snapshot of https://quiche.googlesource.com/quiche/+archive/ecc28c0d7428f3323ea26eb1ddb98a5e06b23dea.tar.gz + version = "ecc28c0d7428f3323ea26eb1ddb98a5e06b23dea", + sha256 = "52680dea984dbe899c27176155578b97276e1f1516b7c3a63fb16ba593061859", urls = ["https://storage.googleapis.com/quiche-envoy-integration/{version}.tar.gz"], use_category = ["dataplane_ext"], extensions = ["envoy.transport_sockets.quic"], - release_date = "2020-09-17", + release_date = "2020-11-10", cpe = "N/A", ), com_googlesource_googleurl = dict( @@ -862,6 +832,10 @@ REPOSITORY_LOCATIONS_SPEC = dict( "envoy.filters.http.wasm", "envoy.filters.network.wasm", "envoy.stat_sinks.wasm", + "envoy.wasm.runtime.null", + "envoy.wasm.runtime.v8", + "envoy.wasm.runtime.wavm", + "envoy.wasm.runtime.wasmtime", ], release_date = "2020-10-22", cpe = "N/A", @@ -881,6 +855,10 @@ REPOSITORY_LOCATIONS_SPEC = dict( "envoy.filters.http.wasm", "envoy.filters.network.wasm", "envoy.stat_sinks.wasm", + "envoy.wasm.runtime.null", + "envoy.wasm.runtime.v8", + "envoy.wasm.runtime.wavm", + "envoy.wasm.runtime.wasmtime", ], release_date = "2020-11-12", cpe = "N/A", @@ -905,13 +883,7 @@ REPOSITORY_LOCATIONS_SPEC = dict( strip_prefix = "rules_rust-{version}", urls = ["https://github.com/bazelbuild/rules_rust/archive/{version}.tar.gz"], use_category = ["dataplane_ext"], - extensions = [ - "envoy.access_loggers.wasm", - "envoy.bootstrap.wasm", - "envoy.filters.http.wasm", - "envoy.filters.network.wasm", - "envoy.stat_sinks.wasm", - ], + extensions = ["envoy.wasm.runtime.wasmtime"], release_date = "2020-10-21", cpe = "N/A", ), diff --git a/ci/Dockerfile-envoy-google-vrp b/ci/Dockerfile-envoy-google-vrp index 802e148851e06..abc84f1269aba 100644 --- a/ci/Dockerfile-envoy-google-vrp +++ b/ci/Dockerfile-envoy-google-vrp @@ -16,6 +16,9 @@ ADD configs/google-vrp/supervisor.conf /etc/supervisor.conf ADD test/config/integration/certs/serverkey.pem /etc/envoy/certs/serverkey.pem ADD test/config/integration/certs/servercert.pem /etc/envoy/certs/servercert.pem # ADD %local envoy bin% /usr/local/bin/envoy +RUN chmod 777 /var/log/supervisor +RUN chmod a+r /etc/supervisor.conf /etc/envoy/* /etc/envoy/certs/* +RUN chmod a+rx /usr/local/bin/launch_envoy.sh EXPOSE 10000 EXPOSE 10001 diff --git a/ci/run_clang_tidy.sh b/ci/run_clang_tidy.sh index fe5d5fdd20478..b29a624c3f453 100755 --- a/ci/run_clang_tidy.sh +++ b/ci/run_clang_tidy.sh @@ -113,9 +113,7 @@ elif [[ "${RUN_FULL_CLANG_TIDY}" == 1 ]]; then run_clang_tidy else if [[ -z "${DIFF_REF}" ]]; then - if [[ "${BUILD_REASON}" == "PullRequest" ]]; then - DIFF_REF="remotes/origin/${SYSTEM_PULLREQUEST_TARGETBRANCH}" - elif [[ "${BUILD_REASON}" == *CI ]]; then + if [[ "${BUILD_REASON}" == *CI ]]; then DIFF_REF="HEAD^" else DIFF_REF=$("${ENVOY_SRCDIR}"/tools/git/last_github_commit.sh) diff --git a/ci/run_envoy_docker.sh b/ci/run_envoy_docker.sh index e0f204e67fcfa..da5115db52747 100755 --- a/ci/run_envoy_docker.sh +++ b/ci/run_envoy_docker.sh @@ -83,7 +83,6 @@ docker run --rm \ -e ENVOY_BUILD_IMAGE \ -e ENVOY_SRCDIR \ -e ENVOY_BUILD_TARGET \ - -e SYSTEM_PULLREQUEST_TARGETBRANCH \ -e SYSTEM_PULLREQUEST_PULLREQUESTNUMBER \ -e GCS_ARTIFACT_BUCKET \ -e GITHUB_TOKEN \ diff --git a/ci/windows_ci_steps.sh b/ci/windows_ci_steps.sh index ff77a9ea14656..91e5cf39cfa3f 100755 --- a/ci/windows_ci_steps.sh +++ b/ci/windows_ci_steps.sh @@ -42,7 +42,7 @@ export TEST_TMPDIR=${BUILD_DIR}/tmp [[ "${BUILD_REASON}" != "PullRequest" ]] && BAZEL_EXTRA_TEST_OPTIONS+=(--nocache_test_results) -BAZEL_STARTUP_OPTIONS+=("--output_base=c:/_eb") +BAZEL_STARTUP_OPTIONS+=("--output_base=${TEST_TMPDIR/\/c/c:}") BAZEL_BUILD_OPTIONS=( -c opt --show_task_finish diff --git a/configs/configgen.py b/configs/configgen.py index baf95c4b3c49c..4cc5292ba5951 100755 --- a/configs/configgen.py +++ b/configs/configgen.py @@ -139,5 +139,7 @@ def generate_config(template_path, template, output_file, **context): mongos_servers=mongos_servers) shutil.copy(os.path.join(SCRIPT_DIR, 'envoyproxy_io_proxy.yaml'), OUT_DIR) -shutil.copy(os.path.join(SCRIPT_DIR, 'encapsulate_in_connect.yaml'), OUT_DIR) -shutil.copy(os.path.join(SCRIPT_DIR, 'terminate_connect.yaml'), OUT_DIR) +shutil.copy(os.path.join(SCRIPT_DIR, 'encapsulate_in_http1_connect.yaml'), OUT_DIR) +shutil.copy(os.path.join(SCRIPT_DIR, 'encapsulate_in_http2_connect.yaml'), OUT_DIR) +shutil.copy(os.path.join(SCRIPT_DIR, 'terminate_http1_connect.yaml'), OUT_DIR) +shutil.copy(os.path.join(SCRIPT_DIR, 'terminate_http2_connect.yaml'), OUT_DIR) diff --git a/configs/encapsulate_in_http1_connect.yaml b/configs/encapsulate_in_http1_connect.yaml new file mode 100644 index 0000000000000..1aee73d81841c --- /dev/null +++ b/configs/encapsulate_in_http1_connect.yaml @@ -0,0 +1,44 @@ +# This configuration takes incoming data on port 10000 and encapsulates it in a CONNECT +# request which is sent upstream port 10001. +# It can be used to test TCP tunneling as described in docs/root/intro/arch_overview/http/upgrades.rst +# and running `curl --x 127.0.0.1:10000 https://www.google.com` + +admin: + access_log_path: /tmp/admin_access.log + address: + socket_address: + protocol: TCP + address: 127.0.0.1 + port_value: 9903 +static_resources: + listeners: + - name: listener_0 + address: + socket_address: + protocol: TCP + address: 127.0.0.1 + port_value: 10000 + filter_chains: + - filters: + - name: tcp + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy + stat_prefix: tcp_stats + cluster: "cluster_0" + tunneling_config: + hostname: host.com:443 + clusters: + - name: cluster_0 + connect_timeout: 5s + # This ensures HTTP/1.1 CONNECT is used for establishing the tunnel. + http_protocol_options: + {} + load_assignment: + cluster_name: cluster_0 + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: 127.0.0.1 + port_value: 10001 diff --git a/configs/encapsulate_in_connect.yaml b/configs/encapsulate_in_http2_connect.yaml similarity index 91% rename from configs/encapsulate_in_connect.yaml rename to configs/encapsulate_in_http2_connect.yaml index 2394f6e44cc40..1d815f122d82d 100644 --- a/configs/encapsulate_in_connect.yaml +++ b/configs/encapsulate_in_http2_connect.yaml @@ -26,10 +26,11 @@ static_resources: stat_prefix: tcp_stats cluster: "cluster_0" tunneling_config: - hostname: host.com + hostname: host.com:443 clusters: - name: cluster_0 connect_timeout: 5s + # This ensures HTTP/2 CONNECT is used for establishing the tunnel. http2_protocol_options: {} load_assignment: diff --git a/configs/google-vrp/supervisor.conf b/configs/google-vrp/supervisor.conf index e019581d079c2..1e1d09f336602 100644 --- a/configs/google-vrp/supervisor.conf +++ b/configs/google-vrp/supervisor.conf @@ -1,5 +1,6 @@ [supervisord] nodaemon=true +logfile=/var/log/supervisor/supervisord.log [program:envoy-edge] command=launch_envoy.sh -c /etc/envoy/envoy-edge.yaml %(ENV_ENVOY_EDGE_EXTRA_ARGS)s diff --git a/configs/terminate_http1_connect.yaml b/configs/terminate_http1_connect.yaml new file mode 100644 index 0000000000000..67e6f2289a2c3 --- /dev/null +++ b/configs/terminate_http1_connect.yaml @@ -0,0 +1,61 @@ +# This configuration terminates a CONNECT request and sends the CONNECT payload upstream. +# It can be used to test TCP tunneling as described in docs/root/intro/arch_overview/http/upgrades.rst +# or used to test CONNECT directly, by running `curl -k -v -x 127.0.0.1:10001 https://www.google.com` +admin: + access_log_path: /tmp/admin_access.log + address: + socket_address: + protocol: TCP + address: 127.0.0.1 + port_value: 9902 +static_resources: + listeners: + - name: listener_0 + address: + socket_address: + protocol: TCP + address: 127.0.0.1 + port_value: 10001 + filter_chains: + - filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + 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 + connect_config: + {} + http_filters: + - name: envoy.filters.http.router + http_protocol_options: {} + upgrade_configs: + - upgrade_type: CONNECT + clusters: + - name: service_google + connect_timeout: 0.25s + 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/configs/terminate_connect.yaml b/configs/terminate_http2_connect.yaml similarity index 100% rename from configs/terminate_connect.yaml rename to configs/terminate_http2_connect.yaml diff --git a/docs/requirements.txt b/docs/requirements.txt index c8e98061b50ec..edff23bf38239 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -116,9 +116,9 @@ sphinxcontrib-jsmath==1.0.1 \ sphinxcontrib-qthelp==1.0.3 \ --hash=sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72 \ --hash=sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6 -sphinxext-rediraffe==0.2.4 \ - --hash=sha256:5428fb614d1fbc16964ba587aaa6b1c8ec92fd0b1d01bb6b369637446f43a27d \ - --hash=sha256:13e6474342df6643723976a3429edfc5e811e9f48b9f832c9fb6bdd9fe53fd83 +sphinxext-rediraffe==0.2.5 \ + --hash=sha256:7b706284d20602acecc1783cc58c8d0543937af1ee53f912bfdc4b258a7e649a \ + --hash=sha256:a17287cdee7763341b91762879e042b33a4916d6a2fc6d2f97a18107325bd2cc sphinxcontrib-serializinghtml==1.1.4 \ --hash=sha256:eaa0eccc86e982a9b939b2b82d12cc5d013385ba5eadcc7e4fed23f4405f77bc \ --hash=sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a diff --git a/docs/root/configuration/http/http_filters/http_filters.rst b/docs/root/configuration/http/http_filters/http_filters.rst index 801d9f1319432..1b1e4b420bdc6 100644 --- a/docs/root/configuration/http/http_filters/http_filters.rst +++ b/docs/root/configuration/http/http_filters/http_filters.rst @@ -30,6 +30,7 @@ HTTP filters header_to_metadata_filter ip_tagging_filter jwt_authn_filter + kill_request_filter local_rate_limit_filter lua_filter oauth2_filter diff --git a/docs/root/configuration/http/http_filters/kill_request_filter.rst b/docs/root/configuration/http/http_filters/kill_request_filter.rst new file mode 100644 index 0000000000000..bc128d8f679e8 --- /dev/null +++ b/docs/root/configuration/http/http_filters/kill_request_filter.rst @@ -0,0 +1,39 @@ +.. _config_http_filters_kill_request: + +Kill Request +=============== + +The KillRequest filter can be used to crash Envoy when receiving a Kill request. +By default, KillRequest filter is not built into Envoy binary since it is commmented out in *extensions_build_config.bzl*. If you want to use this extenstion, you need to uncomment it in *extensions_build_config.bzl*. + +Configuration +------------- + +* This filter should be configured with the name *envoy.filters.http.kill_request*. + +.. _config_http_filters_kill_request_http_header: + +Enable Kill Request via HTTP header +-------------------------------------------- + +The KillRequest filter requires the following header in the request: + +x-envoy-kill-request + whether the request is a Kill request. + The header value must be one of (case-insensitive) ["true", "t", "yes", "y", "1"] + in order for the request to be a Kill request. + +.. note:: + + If the headers appear multiple times only the first value is used. + +The following is an example configuration: + +.. code-block:: yaml + + name: envoy.filters.http.kill_request + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.kill_request.v3.KillRequest + probability: + numerator: 100 + diff --git a/docs/root/configuration/observability/access_log/usage.rst b/docs/root/configuration/observability/access_log/usage.rst index 75c0630285fa0..73ca330f7333c 100644 --- a/docs/root/configuration/observability/access_log/usage.rst +++ b/docs/root/configuration/observability/access_log/usage.rst @@ -187,6 +187,10 @@ The following command operators are supported: HTTP response code. Note that a response code of '0' means that the server never sent the beginning of a response. This generally means that the (downstream) client disconnected. + Note that in the case of 100-continue responses, only the response code of the final headers + will be logged. If a 100-continue is followed by a 200, the logged response will be 200. + If a 100-continue results in a disconnect, the 100 will be logged. + TCP Not implemented ("-"). diff --git a/docs/root/configuration/security/secret.rst b/docs/root/configuration/security/secret.rst index 087cf388b759e..5ad3650cc19eb 100644 --- a/docs/root/configuration/security/secret.rst +++ b/docs/root/configuration/security/secret.rst @@ -33,6 +33,30 @@ SDS Configuration *SdsSecretConfig* is used in two fields in :ref:`CommonTlsContext `. The first field is *tls_certificate_sds_secret_configs* to use SDS to get :ref:`TlsCertificate `. The second field is *validation_context_sds_secret_config* to use SDS to get :ref:`CertificateValidationContext `. +.. _sds_key_rotation: + +Key rotation +------------ + +It's usually preferrable to perform key rotation via gRPC SDS, but when this is not possible or +desired (e.g. during bootstrap of SDS credentials), SDS allows for filesystem rotation when secrets +refer to filesystem paths. This currently is supported for the following secret types: + +* :ref:`TlsCertificate ` +* :ref:`CertificateValidationContext ` + +By default, directories containing secrets are watched for filesystem move events. For example, a +key or trusted CA certificates at ``/foo/bar/baz/cert.pem`` will be watched at `/foo/bar/baz`. +Explicit control over the watched directory is possible by specifying a *watched_directory* path in +:ref:`TlsCertificate +` and +:ref:`CertificateValidationContext +`. +This allows watches to be established at path predecessors, e.g. ``/foo/bar``; this capability is +useful when implementing common key rotation schemes. + +An example of key rotation is provided :ref:`below `. + Example one: static_resource ----------------------------- @@ -211,9 +235,11 @@ In contrast, :ref:`sds_server_example` requires a restart to reload xDS certific "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext" common_tls_context: tls_certificate_sds_secret_configs: + name: tls_sds sds_config: path: /etc/envoy/tls_certificate_sds_secret.yaml validation_context_sds_secret_config: + name: validation_context_sds sds_config: path: /etc/envoy/validation_context_sds_secret.yaml @@ -239,6 +265,39 @@ Path to CA certificate bundle for validating the xDS server certificate is given trusted_ca: filename: /certs/cacert.pem +In the above example, a watch will be established on ``/certs``. File movement in this directory +will trigger an update. An alternative common key rotation scheme that provides improved atomicity +is to establish an active symlink ``/certs/current`` and use an atomic move operation to replace the +symlink. The watch in this case needs to be on the certificate's grandparent directory. Envoy +supports this scheme via the use of *watched_directory*. Continuing the above examples: + +.. code-block:: yaml + + resources: + - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret" + tls_certificate: + certificate_chain: + filename: /certs/current/sds_cert.pem + private_key: + filename: /certs/current/sds_key.pem + watched_directory: + path: /certs + +.. code-block:: yaml + + resources: + - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret" + validation_context: + trusted_ca: + filename: /certs/current/cacert.pem + watched_directory: + path: /certs + +Secret rotation can be performed with: + +.. code-block:: bash + + ln -s /certs/new && mv -Tf /certs/new /certs/current Statistics ---------- @@ -261,3 +320,12 @@ For upstream clusters, they are in the *cluster..client_ssl_socket ssl_context_update_by_sds, Total number of ssl context has been updated. upstream_context_secrets_not_ready, Total number of upstream connections reset due to empty ssl certificate. + +SDS has a :ref:`statistics ` tree rooted in the *sds..* +namespace. In addition, the following statistics are tracked in this namespace: + +.. csv-table:: + :header: Name, Description + :widths: 1, 2 + + key_rotation_failed, Total number of filesystem key rotations that failed outside of an SDS update. diff --git a/docs/root/extending/extending.rst b/docs/root/extending/extending.rst index cd36ddb2188db..7f2e676e20eb1 100644 --- a/docs/root/extending/extending.rst +++ b/docs/root/extending/extending.rst @@ -24,6 +24,8 @@ types including: * :ref:`Watchdog action ` * :ref:`Internal redirect policy ` * :ref:`Compression libraries ` +* :ref:`Bootstrap extensions ` +* :ref:`Fatal actions ` As of this writing there is no high level extension developer documentation. The :repo:`existing extensions ` are a good way to learn what is possible. diff --git a/docs/root/intro/arch_overview/http/upgrades.rst b/docs/root/intro/arch_overview/http/upgrades.rst index 959c576960dfc..08e5254a8ca74 100644 --- a/docs/root/intro/arch_overview/http/upgrades.rst +++ b/docs/root/intro/arch_overview/http/upgrades.rst @@ -94,17 +94,32 @@ will synthesize 200 response headers, and then forward the TCP data as the HTTP For an example of proxying connect, please see :repo:`configs/proxy_connect.yaml ` For an example of terminating connect, please see :repo:`configs/terminate_connect.yaml ` -Tunneling TCP over HTTP/2 -^^^^^^^^^^^^^^^^^^^^^^^^^ -Envoy also has support for transforming raw TCP into HTTP/2 CONNECT requests. This can be used to -proxy multiplexed TCP over pre-warmed secure connections and amortize the cost of any TLS handshake. -An example set up proxying SMTP would look something like this +Tunneling TCP over HTTP +^^^^^^^^^^^^^^^^^^^^^^^ +Envoy also has support for tunneling raw TCP over HTTP CONNECT requests. Find +below some usage scenarios. + +HTTP/2 CONNECT can be used to proxy multiplexed TCP over pre-warmed secure connections and amortize the cost of any TLS +handshake. +An example set up proxying SMTP would look something like this: [SMTP Upstream] --- raw SMTP --- [L2 Envoy] --- SMTP tunneled over HTTP/2 --- [L1 Envoy] --- raw SMTP --- [Client] +HTTP/1.1 CONNECT can be used to have TCP client connecting to its own +destination passing through an HTTP proxy server (e.g. corporate proxy not +supporting HTTP/2): + +[HTTP Server] --- raw HTTP --- [L2 Envoy] --- HTTP tunneled over HTTP/1.1 --- [L1 Envoy] --- raw HTTP --- [HTTP Client] + +Note that when using HTTP/1 CONNECT you will end up having a TCP connection +between L1 and L2 Envoy for each TCP client connection, it is preferable to use +HTTP/2 when you have the choice. + Examples of such a set up can be found in the Envoy example config :repo:`directory ` -If you run `bazel-bin/source/exe/envoy-static --config-path configs/encapsulate_in_connect.yaml --base-id 1` -and `bazel-bin/source/exe/envoy-static --config-path configs/terminate_connect.yaml` -you will be running two Envoys, the first listening for TCP traffic on port 10000 and encapsulating it in an HTTP/2 -CONNECT request, and the second listening for HTTP/2 on 10001, stripping the CONNECT headers, and forwarding the +For HTTP/1.1 run `bazel-bin/source/exe/envoy-static --config-path configs/encapsulate_in_http1_connect.yaml --base-id 1` +and `bazel-bin/source/exe/envoy-static --config-path configs/terminate_http1_connect.yaml`. +For HTTP/2 run `bazel-bin/source/exe/envoy-static --config-path configs/encapsulate_in_http2_connect.yaml --base-id 1` +and `bazel-bin/source/exe/envoy-static --config-path configs/terminate_http2_connect.yaml`. +In both cases you will be running a first Envoy listening for TCP traffic on port 10000 and encapsulating it in an HTTP +CONNECT request, and a second one listening on 10001, stripping the CONNECT headers, and forwarding the original TCP upstream, in this case to google.com. diff --git a/docs/root/operations/cli.rst b/docs/root/operations/cli.rst index d4f6f28082135..4f7129a1b4dfc 100644 --- a/docs/root/operations/cli.rst +++ b/docs/root/operations/cli.rst @@ -332,7 +332,7 @@ following are the command line options that Envoy supports. extensions cannot be used by static or dynamic configuration, though they are still linked into Envoy and may run start-up code or have other runtime effects. Extension names are created by joining the extension category and name with a forward slash, - e.g. ``grpc_credentials/envoy.grpc_credentials.file_based_metadata``. + e.g. ``envoy.grpc_credentials/envoy.grpc_credentials.file_based_metadata``. .. option:: --version diff --git a/docs/root/start/sandboxes/dynamic-configuration-filesystem.rst b/docs/root/start/sandboxes/dynamic-configuration-filesystem.rst index 9364e98f40aa4..ade85340a492c 100644 --- a/docs/root/start/sandboxes/dynamic-configuration-filesystem.rst +++ b/docs/root/start/sandboxes/dynamic-configuration-filesystem.rst @@ -115,7 +115,7 @@ the ``example_proxy_cluster`` should now be configured to proxy to ``service2``: .. code-block:: console - $ curl -s http://localhost:19000/config_dump jq -r '.configs[1].dynamic_active_clusters' + $ curl -s http://localhost:19000/config_dump | jq -r '.configs[1].dynamic_active_clusters' .. literalinclude:: _include/dynamic-config-fs/response-config-active-clusters-updated.json :language: json diff --git a/docs/root/start/sandboxes/load_reporting_service.rst b/docs/root/start/sandboxes/load_reporting_service.rst index 59d1bdfd19f8c..a3e2bb7977def 100644 --- a/docs/root/start/sandboxes/load_reporting_service.rst +++ b/docs/root/start/sandboxes/load_reporting_service.rst @@ -28,7 +28,7 @@ Change to the ``examples/load-reporting-service`` directory. Terminal 1 :: $ pwd - envoy/examples/load_reporting_service + envoy/examples/load-reporting-service $ docker-compose pull $ docker-compose up --scale http_service=2 diff --git a/docs/root/start/sandboxes/mysql.rst b/docs/root/start/sandboxes/mysql.rst index ca588f94faa0d..065198a7a8760 100644 --- a/docs/root/start/sandboxes/mysql.rst +++ b/docs/root/start/sandboxes/mysql.rst @@ -49,7 +49,7 @@ Terminal 1 .. code-block:: console - $ docker run --rm -it --network envoymesh mysql:5.5 mysql -h envoy -P 1999 -u root + $ docker run --rm -it --network envoymesh mysql:5.5 mysql -h proxy -P 1999 -u root ... snip ... mysql> CREATE DATABASE test; diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index 19f263230518d..ea81db272720c 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -17,7 +17,9 @@ Minor Behavior Changes * ext_authz filter: disable `envoy.reloadable_features.ext_authz_measure_timeout_on_check_created` by default. * ext_authz filter: the deprecated field :ref:`use_alpha ` is no longer supported and cannot be set anymore. * grpc_web filter: if a `grpc-accept-encoding` header is present it's passed as-is to the upstream and if it isn't `grpc-accept-encoding:identity` is sent instead. The header was always overwriten with `grpc-accept-encoding:identity,deflate,gzip` before. +* jwt_authn filter: added support of Jwt time constraint verification with a clock skew (default to 60 seconds) and added a filter config field :ref:`clock_skew_seconds ` to configure it. * memory: enable new tcmalloc with restartable sequences for aarch64 builds. +* mongo proxy metrics: swapped network connection remote and local closed counters previously set reversed (`cx_destroy_local_with_active_rq` and `cx_destroy_remote_with_active_rq`). * tls: removed RSA key transport and SHA-1 cipher suites from the client-side defaults. * watchdog: the watchdog action :ref:`abort_action ` is now the default action to terminate the process if watchdog kill / multikill is enabled. * xds: to support TTLs, heartbeating has been added to xDS. As a result, responses that contain empty resources without updating the version will no longer be propagated to the @@ -34,14 +36,17 @@ Bug Fixes * http: reject requests with missing required headers after filter chain processing. * http: sending CONNECT_ERROR for HTTP/2 where appropriate during CONNECT requests. * proxy_proto: fixed a bug where the wrong downstream address got sent to upstream connections. +* proxy_proto: fixed a bug where network filters would not have the correct downstreamRemoteAddress() when accessed from the StreamInfo. This could result in incorrect enforcement of RBAC rules in the RBAC network filter (but not in the RBAC HTTP filter), or incorrect access log addresses from tcp_proxy. * tls: fix detection of the upstream connection close event. * tls: fix read resumption after triggering buffer high-watermark and all remaining request/response bytes are stored in the SSL connection's internal buffers. +* udp: fixed issue in which receiving truncated UDP datagrams would cause Envoy to crash. * watchdog: touch the watchdog before most event loop operations to avoid misses when handling bursts of callbacks. Removed Config or Runtime ------------------------- *Normally occurs at the end of the* :ref:`deprecation period ` +* dispatcher: removed legacy socket read/write resumption code path and runtime guard `envoy.reloadable_features.activate_fds_next_event_loop`. * ext_authz: removed auto ignore case in HTTP-based `ext_authz` header matching and the runtime guard `envoy.reloadable_features.ext_authz_http_service_enable_case_sensitive_string_matcher`. To ignore case, set the :ref:`ignore_case ` field to true. * http: flip default HTTP/1 and HTTP/2 server codec implementations to new codecs that remove the use of exceptions for control flow. To revert to old codec behavior, set the runtime feature `envoy.reloadable_features.new_codec_behavior` to false. * http: removed `envoy.reloadable_features.http1_flood_protection` and legacy code path for turning flood protection off. @@ -50,11 +55,13 @@ New Features ------------ * config: added new runtime feature `envoy.features.enable_all_deprecated_features` that allows the use of all deprecated features. * grpc: implemented header value syntax support when defining :ref:`initial metadata ` for gRPC-based `ext_authz` :ref:`HTTP ` and :ref:`network ` filters, and :ref:`ratelimit ` filters. +* grpc-json: added support for configuring :ref:`unescaping behavior ` for path components. * hds: added support for delta updates in the :ref:`HealthCheckSpecifier `, making only the Endpoints and Health Checkers that changed be reconstructed on receiving a new message, rather than the entire HDS. * health_check: added option to use :ref:`no_traffic_healthy_interval ` which allows a different no traffic interval when the host is healthy. * http: added HCM :ref:`timeout config field ` to control how long a downstream has to finish sending headers before the stream is cancelled. * http: added frame flood and abuse checks to the upstream HTTP/2 codec. This check is off by default and can be enabled by setting the `envoy.reloadable_features.upstream_http2_flood_checks` runtime key to true. * jwt_authn: added support for :ref:`per-route config `. +* kill_request: added new :ref:`HTTP kill request filter `. * listener: added an optional :ref:`default filter chain `. If this field is supplied, and none of the :ref:`filter_chains ` matches, this default filter chain is used to serve the connection. * log: added a new custom flag ``%_`` to the log pattern to print the actual message to log, but with escaped newlines. * lua: added `downstreamDirectRemoteAddress()` and `downstreamLocalAddress()` APIs to :ref:`streamInfo() `. @@ -63,6 +70,10 @@ New Features * overload: add :ref:`envoy.overload_actions.reduce_timeouts ` overload action to enable scaling timeouts down with load. * ratelimit: added support for use of various :ref:`metadata ` as a ratelimit action. * ratelimit: added :ref:`disable_x_envoy_ratelimited_header ` option to disable `X-Envoy-RateLimited` header. +* sds: improved support for atomic :ref:`key rotations ` and added configurable rotation triggers for + :ref:`TlsCertificate ` and + :ref:`CertificateValidationContext `. +* signal: added an extension point for custom actions to run on the thread that has encountered a fatal error. Actions are configurable via :ref:`fatal_actions `. * tcp: added a new :ref:`envoy.overload_actions.reject_incoming_connections ` action to reject incoming TCP connections. * tls: added support for RSA certificates with 4096-bit keys in FIPS mode. * tracing: added SkyWalking tracer. diff --git a/examples/skywalking-tracing/docker-compose.yaml b/examples/skywalking-tracing/docker-compose.yaml index 5ac0e647a7fe4..359f7be74dca0 100644 --- a/examples/skywalking-tracing/docker-compose.yaml +++ b/examples/skywalking-tracing/docker-compose.yaml @@ -56,7 +56,7 @@ services: soft: -1 hard: -1 skywalking-oap: - image: apache/skywalking-oap-server:8.1.0-es7 + image: apache/skywalking-oap-server:8.2.0-es7 networks: - envoymesh depends_on: @@ -72,7 +72,7 @@ services: start_period: 40s restart: on-failure skywalking-ui: - image: apache/skywalking-ui:8.1.0 + image: apache/skywalking-ui:8.2.0 networks: - envoymesh depends_on: diff --git a/examples/vrp-litmus/Dockerfile-vrp b/examples/vrp-litmus/Dockerfile-vrp new file mode 100644 index 0000000000000..f0e6704d6d216 --- /dev/null +++ b/examples/vrp-litmus/Dockerfile-vrp @@ -0,0 +1 @@ +FROM envoyproxy/envoy-google-vrp-dev:latest diff --git a/examples/vrp-litmus/README.md b/examples/vrp-litmus/README.md new file mode 100644 index 0000000000000..58c14b3fd8cb8 --- /dev/null +++ b/examples/vrp-litmus/README.md @@ -0,0 +1,3 @@ +Simple litmus test to verify the VRP image in CI. For more details on VRP, +please see +https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/security/google_vrp. diff --git a/examples/vrp-litmus/docker-compose.yaml b/examples/vrp-litmus/docker-compose.yaml new file mode 100644 index 0000000000000..46eefcafb9aa5 --- /dev/null +++ b/examples/vrp-litmus/docker-compose.yaml @@ -0,0 +1,17 @@ +version: "3.7" +services: + + vrp: + build: + context: . + dockerfile: Dockerfile-vrp + environment: + ENVOY_EDGE_EXTRA_ARGS: "" + ENVOY_ORIGIN_EXTRA_ARGS: "" + networks: + - envoymesh + ports: + - "10000:10000" + +networks: + envoymesh: {} diff --git a/examples/vrp-litmus/verify.sh b/examples/vrp-litmus/verify.sh new file mode 100755 index 0000000000000..02791785c6283 --- /dev/null +++ b/examples/vrp-litmus/verify.sh @@ -0,0 +1,14 @@ +#!/bin/bash -e + +export NAME=vrp-litmus +export DELAY=10 + +# shellcheck source=examples/verify-common.sh +. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" + + +run_log "Test proxy" +responds_with \ + normal \ + https://localhost:10000/content \ + -k diff --git a/generated_api_shadow/envoy/config/bootstrap/v3/bootstrap.proto b/generated_api_shadow/envoy/config/bootstrap/v3/bootstrap.proto index cce2dceb72d89..52b9a88365d0e 100644 --- a/generated_api_shadow/envoy/config/bootstrap/v3/bootstrap.proto +++ b/generated_api_shadow/envoy/config/bootstrap/v3/bootstrap.proto @@ -40,7 +40,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // ` for more detail. // Bootstrap :ref:`configuration overview `. -// [#next-free-field: 28] +// [#next-free-field: 29] message Bootstrap { option (udpa.annotations.versioning).previous_message_type = "envoy.config.bootstrap.v2.Bootstrap"; @@ -241,6 +241,10 @@ message Bootstrap { // Each item contains extension specific configuration. repeated core.v3.TypedExtensionConfig bootstrap_extensions = 21; + // Specifies optional extensions instantiated at startup time and + // invoked during crash time on the request that caused the crash. + repeated FatalAction fatal_actions = 28; + // Configuration sources that will participate in // *udpa.core.v1.ResourceLocator* authority resolution. The algorithm is as // follows: @@ -421,6 +425,20 @@ message Watchdog { type.v3.Percent multikill_threshold = 5; } +// Fatal actions to run while crashing. Actions can be safe (meaning they are +// async-signal safe) or unsafe. We run all safe actions before we run unsafe actions. +// If using an unsafe action that could get stuck or deadlock, it important to +// have an out of band system to terminate the process. +// +// The interface for the extension is ``Envoy::Server::Configuration::FatalAction``. +// *FatalAction* extensions live in the ``envoy.extensions.fatal_actions`` API +// namespace. +message FatalAction { + // Extension specific configuration for the action. It's expected to conform + // to the ``Envoy::Server::Configuration::FatalAction`` interface. + core.v3.TypedExtensionConfig config = 1; +} + // Runtime :ref:`configuration overview ` (deprecated). message Runtime { option (udpa.annotations.versioning).previous_message_type = "envoy.config.bootstrap.v2.Runtime"; diff --git a/generated_api_shadow/envoy/config/bootstrap/v4alpha/bootstrap.proto b/generated_api_shadow/envoy/config/bootstrap/v4alpha/bootstrap.proto index 57f37e5ff6ee1..074936c7226e7 100644 --- a/generated_api_shadow/envoy/config/bootstrap/v4alpha/bootstrap.proto +++ b/generated_api_shadow/envoy/config/bootstrap/v4alpha/bootstrap.proto @@ -39,7 +39,7 @@ option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSIO // ` for more detail. // Bootstrap :ref:`configuration overview `. -// [#next-free-field: 28] +// [#next-free-field: 29] message Bootstrap { option (udpa.annotations.versioning).previous_message_type = "envoy.config.bootstrap.v3.Bootstrap"; @@ -242,6 +242,10 @@ message Bootstrap { // Each item contains extension specific configuration. repeated core.v4alpha.TypedExtensionConfig bootstrap_extensions = 21; + // Specifies optional extensions instantiated at startup time and + // invoked during crash time on the request that caused the crash. + repeated FatalAction fatal_actions = 28; + // Configuration sources that will participate in // *udpa.core.v1.ResourceLocator* authority resolution. The algorithm is as // follows: @@ -425,6 +429,23 @@ message Watchdog { type.v3.Percent multikill_threshold = 5; } +// Fatal actions to run while crashing. Actions can be safe (meaning they are +// async-signal safe) or unsafe. We run all safe actions before we run unsafe actions. +// If using an unsafe action that could get stuck or deadlock, it important to +// have an out of band system to terminate the process. +// +// The interface for the extension is ``Envoy::Server::Configuration::FatalAction``. +// *FatalAction* extensions live in the ``envoy.extensions.fatal_actions`` API +// namespace. +message FatalAction { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.bootstrap.v3.FatalAction"; + + // Extension specific configuration for the action. It's expected to conform + // to the ``Envoy::Server::Configuration::FatalAction`` interface. + core.v4alpha.TypedExtensionConfig config = 1; +} + // Runtime :ref:`configuration overview ` (deprecated). message Runtime { option (udpa.annotations.versioning).previous_message_type = "envoy.config.bootstrap.v3.Runtime"; diff --git a/generated_api_shadow/envoy/config/common/matcher/v3/matcher.proto b/generated_api_shadow/envoy/config/common/matcher/v3/matcher.proto index 8a1cb4839c4a5..24ed5dafbdc54 100644 --- a/generated_api_shadow/envoy/config/common/matcher/v3/matcher.proto +++ b/generated_api_shadow/envoy/config/common/matcher/v3/matcher.proto @@ -4,7 +4,7 @@ package envoy.config.common.matcher.v3; import "envoy/config/core/v3/extension.proto"; import "envoy/config/route/v3/route_components.proto"; -import "envoy/type/matcher/v3/value.proto"; +import "envoy/type/matcher/v3/string.proto"; import "udpa/annotations/migrate.proto"; import "udpa/annotations/status.proto"; @@ -58,9 +58,8 @@ message Matcher { oneof matcher { option (validate.required) = true; - // Use existing infrastructure for actually matching the - // value. - type.matcher.v3.ValueMatcher value_match = 2; + // Built-in string matcher. + type.matcher.v3.StringMatcher value_match = 2; // Extension for custom matching logic. core.v3.TypedExtensionConfig custom_match = 3; diff --git a/generated_api_shadow/envoy/config/common/matcher/v4alpha/matcher.proto b/generated_api_shadow/envoy/config/common/matcher/v4alpha/matcher.proto index 15859474e6e12..ab1f4de6cccc1 100644 --- a/generated_api_shadow/envoy/config/common/matcher/v4alpha/matcher.proto +++ b/generated_api_shadow/envoy/config/common/matcher/v4alpha/matcher.proto @@ -4,7 +4,7 @@ package envoy.config.common.matcher.v4alpha; import "envoy/config/core/v4alpha/extension.proto"; import "envoy/config/route/v4alpha/route_components.proto"; -import "envoy/type/matcher/v4alpha/value.proto"; +import "envoy/type/matcher/v4alpha/string.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; @@ -72,9 +72,8 @@ message Matcher { oneof matcher { option (validate.required) = true; - // Use existing infrastructure for actually matching the - // value. - type.matcher.v4alpha.ValueMatcher value_match = 2; + // Built-in string matcher. + type.matcher.v4alpha.StringMatcher value_match = 2; // Extension for custom matching logic. core.v4alpha.TypedExtensionConfig custom_match = 3; diff --git a/generated_api_shadow/envoy/config/core/v3/base.proto b/generated_api_shadow/envoy/config/core/v3/base.proto index 35b015710e5cb..1184c89de6e22 100644 --- a/generated_api_shadow/envoy/config/core/v3/base.proto +++ b/generated_api_shadow/envoy/config/core/v3/base.proto @@ -311,6 +311,13 @@ message HeaderMap { repeated HeaderValue headers = 1; } +// A directory that is watched for changes, e.g. by inotify on Linux. Move/rename +// events inside this directory trigger the watch. +message WatchedDirectory { + // Directory path to watch. + string path = 1 [(validate.rules).string = {min_len: 1}]; +} + // Data source consisting of either a file or an inline value. message DataSource { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.core.DataSource"; diff --git a/generated_api_shadow/envoy/config/core/v4alpha/base.proto b/generated_api_shadow/envoy/config/core/v4alpha/base.proto index 03fcc5a461e0c..95ca4f77a2bcd 100644 --- a/generated_api_shadow/envoy/config/core/v4alpha/base.proto +++ b/generated_api_shadow/envoy/config/core/v4alpha/base.proto @@ -315,6 +315,16 @@ message HeaderMap { repeated HeaderValue headers = 1; } +// A directory that is watched for changes, e.g. by inotify on Linux. Move/rename +// events inside this directory trigger the watch. +message WatchedDirectory { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.core.v3.WatchedDirectory"; + + // Directory path to watch. + string path = 1 [(validate.rules).string = {min_len: 1}]; +} + // Data source consisting of either a file or an inline value. message DataSource { option (udpa.annotations.versioning).previous_message_type = "envoy.config.core.v3.DataSource"; diff --git a/generated_api_shadow/envoy/config/trace/v3/zipkin.proto b/generated_api_shadow/envoy/config/trace/v3/zipkin.proto index b31f697b16ca3..63d16130779d6 100644 --- a/generated_api_shadow/envoy/config/trace/v3/zipkin.proto +++ b/generated_api_shadow/envoy/config/trace/v3/zipkin.proto @@ -46,9 +46,7 @@ message ZipkinConfig { GRPC = 3; } - // The cluster manager cluster that hosts the Zipkin collectors. Note that the - // Zipkin cluster must be defined in the :ref:`Bootstrap static cluster - // resources `. + // The cluster manager cluster that hosts the Zipkin collectors. string collector_cluster = 1 [(validate.rules).string = {min_len: 1}]; // The API endpoint of the Zipkin service where the spans will be sent. When diff --git a/generated_api_shadow/envoy/extensions/filters/http/grpc_json_transcoder/v3/transcoder.proto b/generated_api_shadow/envoy/extensions/filters/http/grpc_json_transcoder/v3/transcoder.proto index 3082089202eef..007ccabc3e47d 100644 --- a/generated_api_shadow/envoy/extensions/filters/http/grpc_json_transcoder/v3/transcoder.proto +++ b/generated_api_shadow/envoy/extensions/filters/http/grpc_json_transcoder/v3/transcoder.proto @@ -15,11 +15,27 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // gRPC-JSON transcoder :ref:`configuration overview `. // [#extension: envoy.filters.http.grpc_json_transcoder] -// [#next-free-field: 10] +// [#next-free-field: 11] message GrpcJsonTranscoder { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.http.transcoder.v2.GrpcJsonTranscoder"; + enum UrlUnescapeSpec { + // URL path parameters will not decode RFC 6570 reserved characters. + // For example, segment `%2f%23/%20%2523` is unescaped to `%2f%23/ %23`. + ALL_CHARACTERS_EXCEPT_RESERVED = 0; + + // URL path parameters will be fully URI-decoded except in + // cases of single segment matches in reserved expansion, where "%2F" will be + // left encoded. + // For example, segment `%2f%23/%20%2523` is unescaped to `%2f#/ %23`. + ALL_CHARACTERS_EXCEPT_SLASH = 1; + + // URL path parameters will be fully URI-decoded. + // For example, segment `%2f%23/%20%2523` is unescaped to `/#/ %23`. + ALL_CHARACTERS = 2; + } + message PrintOptions { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.http.transcoder.v2.GrpcJsonTranscoder.PrintOptions"; @@ -160,4 +176,11 @@ message GrpcJsonTranscoder { // the ``google/rpc/error_details.proto`` should be included in the configured // :ref:`proto descriptor set `. bool convert_grpc_status = 9; + + // URL unescaping policy. + // This spec is only applied when extracting variable with multiple segments. + // For example, in case of `/foo/{x=*}/bar/{y=prefix/*}/{z=**}` `x` variable is single segment and `y` and `z` are multiple segments. + // For a path with `/foo/first/bar/prefix/second/third/fourth`, `x=first`, `y=prefix/second`, `z=third/fourth`. + // If this setting is not specified, the value defaults to :ref:`ALL_CHARACTERS_EXCEPT_RESERVED`. + UrlUnescapeSpec url_unescape_spec = 10 [(validate.rules).enum = {defined_only: true}]; } diff --git a/generated_api_shadow/envoy/extensions/filters/http/jwt_authn/v3/config.proto b/generated_api_shadow/envoy/extensions/filters/http/jwt_authn/v3/config.proto index 0e4294608384f..a10fa68f30437 100644 --- a/generated_api_shadow/envoy/extensions/filters/http/jwt_authn/v3/config.proto +++ b/generated_api_shadow/envoy/extensions/filters/http/jwt_authn/v3/config.proto @@ -51,7 +51,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // cache_duration: // seconds: 300 // -// [#next-free-field: 10] +// [#next-free-field: 11] message JwtProvider { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.http.jwt_authn.v2alpha.JwtProvider"; @@ -191,6 +191,10 @@ message JwtProvider { // exp: 1501281058 // string payload_in_metadata = 9; + + // Specify the clock skew in seconds when verifying JWT time constraint, + // such as `exp`, and `nbf`. If not specified, default is 60 seconds. + uint32 clock_skew_seconds = 10; } // This message specifies how to fetch JWKS from remote and how to cache it. diff --git a/generated_api_shadow/envoy/extensions/filters/http/jwt_authn/v4alpha/config.proto b/generated_api_shadow/envoy/extensions/filters/http/jwt_authn/v4alpha/config.proto index 53ee84fd65ea6..2746640fa7380 100644 --- a/generated_api_shadow/envoy/extensions/filters/http/jwt_authn/v4alpha/config.proto +++ b/generated_api_shadow/envoy/extensions/filters/http/jwt_authn/v4alpha/config.proto @@ -51,7 +51,7 @@ option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSIO // cache_duration: // seconds: 300 // -// [#next-free-field: 10] +// [#next-free-field: 11] message JwtProvider { option (udpa.annotations.versioning).previous_message_type = "envoy.extensions.filters.http.jwt_authn.v3.JwtProvider"; @@ -191,6 +191,10 @@ message JwtProvider { // exp: 1501281058 // string payload_in_metadata = 9; + + // Specify the clock skew in seconds when verifying JWT time constraint, + // such as `exp`, and `nbf`. If not specified, default is 60 seconds. + uint32 clock_skew_seconds = 10; } // This message specifies how to fetch JWKS from remote and how to cache it. diff --git a/generated_api_shadow/envoy/extensions/filters/http/kill_request/v3/BUILD b/generated_api_shadow/envoy/extensions/filters/http/kill_request/v3/BUILD new file mode 100644 index 0000000000000..9a76b7e148e03 --- /dev/null +++ b/generated_api_shadow/envoy/extensions/filters/http/kill_request/v3/BUILD @@ -0,0 +1,12 @@ +# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = [ + "//envoy/type/v3:pkg", + "@com_github_cncf_udpa//udpa/annotations:pkg", + ], +) diff --git a/generated_api_shadow/envoy/extensions/filters/http/kill_request/v3/kill_request.proto b/generated_api_shadow/envoy/extensions/filters/http/kill_request/v3/kill_request.proto new file mode 100644 index 0000000000000..fd7a3d3397c02 --- /dev/null +++ b/generated_api_shadow/envoy/extensions/filters/http/kill_request/v3/kill_request.proto @@ -0,0 +1,23 @@ +syntax = "proto3"; + +package envoy.extensions.filters.http.kill_request.v3; + +import "envoy/type/v3/percent.proto"; + +import "udpa/annotations/status.proto"; +import "udpa/annotations/versioning.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.filters.http.kill_request.v3"; +option java_outer_classname = "KillRequestProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Kill Request] +// Kill Request :ref:`configuration overview `. +// [#extension: envoy.filters.http.kill_request] + +// Configuration for KillRequest filter. +message KillRequest { + // The probability that a Kill request will be triggered. + type.v3.FractionalPercent probability = 1; +} diff --git a/generated_api_shadow/envoy/extensions/tracers/zipkin/v4alpha/zipkin.proto b/generated_api_shadow/envoy/extensions/tracers/zipkin/v4alpha/zipkin.proto index a33aae4bc57ef..4c166eba6b603 100644 --- a/generated_api_shadow/envoy/extensions/tracers/zipkin/v4alpha/zipkin.proto +++ b/generated_api_shadow/envoy/extensions/tracers/zipkin/v4alpha/zipkin.proto @@ -44,9 +44,7 @@ message ZipkinConfig { GRPC = 3; } - // The cluster manager cluster that hosts the Zipkin collectors. Note that the - // Zipkin cluster must be defined in the :ref:`Bootstrap static cluster - // resources `. + // The cluster manager cluster that hosts the Zipkin collectors. string collector_cluster = 1 [(validate.rules).string = {min_len: 1}]; // The API endpoint of the Zipkin service where the spans will be sent. When diff --git a/generated_api_shadow/envoy/extensions/transport_sockets/tls/v3/common.proto b/generated_api_shadow/envoy/extensions/transport_sockets/tls/v3/common.proto index da834e8afc548..2ddca5720fc89 100644 --- a/generated_api_shadow/envoy/extensions/transport_sockets/tls/v3/common.proto +++ b/generated_api_shadow/envoy/extensions/transport_sockets/tls/v3/common.proto @@ -127,16 +127,37 @@ message PrivateKeyProvider { } } -// [#next-free-field: 7] +// [#next-free-field: 8] message TlsCertificate { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.auth.TlsCertificate"; // The TLS certificate chain. + // + // If *certificate_chain* is a filesystem path, a watch will be added to the + // parent directory for any file moves to support rotation. This currently + // only applies to dynamic secrets, when the *TlsCertificate* is delivered via + // SDS. config.core.v3.DataSource certificate_chain = 1; // The TLS private key. + // + // If *private_key* is a filesystem path, a watch will be added to the parent + // directory for any file moves to support rotation. This currently only + // applies to dynamic secrets, when the *TlsCertificate* is delivered via SDS. config.core.v3.DataSource private_key = 2 [(udpa.annotations.sensitive) = true]; + // If specified, updates of file-based *certificate_chain* and *private_key* + // sources will be triggered by this watch. The certificate/key pair will be + // read together and validated for atomic read consistency (i.e. no + // intervening modification occurred between cert/key read, verified by file + // hash comparisons). This allows explicit control over the path watched, by + // default the parent directories of the filesystem paths in + // *certificate_chain* and *private_key* are watched if this field is not + // specified. This only applies when a *TlsCertificate* is delivered by SDS + // with references to filesystem paths. See the :ref:`SDS key rotation + // ` documentation for further details. + config.core.v3.WatchedDirectory watched_directory = 7; + // BoringSSL private key method provider. This is an alternative to :ref:`private_key // ` field. This can't be // marked as ``oneof`` due to API compatibility reasons. Setting both :ref:`private_key @@ -190,7 +211,7 @@ message TlsSessionTicketKeys { [(validate.rules).repeated = {min_items: 1}, (udpa.annotations.sensitive) = true]; } -// [#next-free-field: 11] +// [#next-free-field: 12] message CertificateValidationContext { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.auth.CertificateValidationContext"; @@ -230,8 +251,22 @@ message CertificateValidationContext { // // See :ref:`the TLS overview ` for a list of common // system CA locations. + // + // If *trusted_ca* is a filesystem path, a watch will be added to the parent + // directory for any file moves to support rotation. This currently only + // applies to dynamic secrets, when the *CertificateValidationContext* is + // delivered via SDS. config.core.v3.DataSource trusted_ca = 1; + // If specified, updates of a file-based *trusted_ca* source will be triggered + // by this watch. This allows explicit control over the path watched, by + // default the parent directory of the filesystem path in *trusted_ca* is + // watched if this field is not specified. This only applies when a + // *CertificateValidationContext* is delivered by SDS with references to + // filesystem paths. See the :ref:`SDS key rotation ` + // documentation for further details. + config.core.v3.WatchedDirectory watched_directory = 11; + // An optional list of base64-encoded SHA-256 hashes. If specified, Envoy will verify that the // SHA-256 of the DER-encoded Subject Public Key Information (SPKI) of the presented certificate // matches one of the specified values. diff --git a/generated_api_shadow/envoy/extensions/transport_sockets/tls/v4alpha/common.proto b/generated_api_shadow/envoy/extensions/transport_sockets/tls/v4alpha/common.proto index 1382863cb804c..30859bc2a3eb9 100644 --- a/generated_api_shadow/envoy/extensions/transport_sockets/tls/v4alpha/common.proto +++ b/generated_api_shadow/envoy/extensions/transport_sockets/tls/v4alpha/common.proto @@ -129,17 +129,38 @@ message PrivateKeyProvider { } } -// [#next-free-field: 7] +// [#next-free-field: 8] message TlsCertificate { option (udpa.annotations.versioning).previous_message_type = "envoy.extensions.transport_sockets.tls.v3.TlsCertificate"; // The TLS certificate chain. + // + // If *certificate_chain* is a filesystem path, a watch will be added to the + // parent directory for any file moves to support rotation. This currently + // only applies to dynamic secrets, when the *TlsCertificate* is delivered via + // SDS. config.core.v4alpha.DataSource certificate_chain = 1; // The TLS private key. + // + // If *private_key* is a filesystem path, a watch will be added to the parent + // directory for any file moves to support rotation. This currently only + // applies to dynamic secrets, when the *TlsCertificate* is delivered via SDS. config.core.v4alpha.DataSource private_key = 2 [(udpa.annotations.sensitive) = true]; + // If specified, updates of file-based *certificate_chain* and *private_key* + // sources will be triggered by this watch. The certificate/key pair will be + // read together and validated for atomic read consistency (i.e. no + // intervening modification occurred between cert/key read, verified by file + // hash comparisons). This allows explicit control over the path watched, by + // default the parent directories of the filesystem paths in + // *certificate_chain* and *private_key* are watched if this field is not + // specified. This only applies when a *TlsCertificate* is delivered by SDS + // with references to filesystem paths. See the :ref:`SDS key rotation + // ` documentation for further details. + config.core.v4alpha.WatchedDirectory watched_directory = 7; + // BoringSSL private key method provider. This is an alternative to :ref:`private_key // ` field. This can't be // marked as ``oneof`` due to API compatibility reasons. Setting both :ref:`private_key @@ -193,7 +214,7 @@ message TlsSessionTicketKeys { [(validate.rules).repeated = {min_items: 1}, (udpa.annotations.sensitive) = true]; } -// [#next-free-field: 11] +// [#next-free-field: 12] message CertificateValidationContext { option (udpa.annotations.versioning).previous_message_type = "envoy.extensions.transport_sockets.tls.v3.CertificateValidationContext"; @@ -235,8 +256,22 @@ message CertificateValidationContext { // // See :ref:`the TLS overview ` for a list of common // system CA locations. + // + // If *trusted_ca* is a filesystem path, a watch will be added to the parent + // directory for any file moves to support rotation. This currently only + // applies to dynamic secrets, when the *CertificateValidationContext* is + // delivered via SDS. config.core.v4alpha.DataSource trusted_ca = 1; + // If specified, updates of a file-based *trusted_ca* source will be triggered + // by this watch. This allows explicit control over the path watched, by + // default the parent directory of the filesystem path in *trusted_ca* is + // watched if this field is not specified. This only applies when a + // *CertificateValidationContext* is delivered by SDS with references to + // filesystem paths. See the :ref:`SDS key rotation ` + // documentation for further details. + config.core.v4alpha.WatchedDirectory watched_directory = 11; + // An optional list of base64-encoded SHA-256 hashes. If specified, Envoy will verify that the // SHA-256 of the DER-encoded Subject Public Key Information (SPKI) of the presented certificate // matches one of the specified values. diff --git a/generated_api_shadow/envoy/extensions/wasm/v3/wasm.proto b/generated_api_shadow/envoy/extensions/wasm/v3/wasm.proto index b42fb75a0bf7c..c6affb8106115 100644 --- a/generated_api_shadow/envoy/extensions/wasm/v3/wasm.proto +++ b/generated_api_shadow/envoy/extensions/wasm/v3/wasm.proto @@ -28,7 +28,29 @@ message VmConfig { // See ref: "TODO: add ref" for details. string vm_id = 1; - // The Wasm runtime type (either "v8" or "null" for code compiled into Envoy). + // The Wasm runtime type. + // Available Wasm runtime types are registered as extensions. The following runtimes are included + // in Envoy code base: + // + // .. _extension_envoy.wasm.runtime.null: + // + // **envoy.wasm.runtime.null**: Null sandbox, the Wasm module must be compiled and linked into the + // Envoy binary. The registered name is given in the *code* field as *inline_string*. + // + // .. _extension_envoy.wasm.runtime.v8: + // + // **envoy.wasm.runtime.v8**: `V8 `_-based WebAssembly runtime. + // + // .. _extension_envoy.wasm.runtime.wavm: + // + // **envoy.wasm.runtime.wavm**: `WAVM `_-based WebAssembly runtime. + // This runtime is not enabled in the official build. + // + // .. _extension_envoy.wasm.runtime.wasmtime: + // + // **envoy.wasm.runtime.wasmtime**: `Wasmtime `_-based WebAssembly runtime. + // This runtime is not enabled in the official build. + // string runtime = 2 [(validate.rules).string = {min_len: 1}]; // The Wasm code that Envoy will execute. diff --git a/include/envoy/api/io_error.h b/include/envoy/api/io_error.h index 247e102a49d59..d671dea790e1f 100644 --- a/include/envoy/api/io_error.h +++ b/include/envoy/api/io_error.h @@ -71,6 +71,12 @@ template struct IoCallResult { */ bool ok() const { return err_ == nullptr; } + /** + * This return code is frequent enough that we have a separate function to check. + * @return true if the system call failed because the socket would block. + */ + bool wouldBlock() const { return !ok() && err_->getErrorCode() == IoError::IoErrorCode::Again; } + // TODO(danzh): rename it to be more meaningful, i.e. return_value_. ReturnValue rc_; IoErrorPtr err_; diff --git a/include/envoy/buffer/buffer.h b/include/envoy/buffer/buffer.h index 3ab150504ccd5..42b414c665f64 100644 --- a/include/envoy/buffer/buffer.h +++ b/include/envoy/buffer/buffer.h @@ -160,6 +160,14 @@ class Instance { virtual RawSliceVector getRawSlices(absl::optional max_slices = absl::nullopt) const PURE; + /** + * Fetch the valid data pointer and valid data length of the first non-zero-length + * slice in the buffer. + * @return RawSlice the first non-empty slice in the buffer, or {nullptr, 0} if the buffer + * is empty. + */ + virtual RawSlice frontSlice() const PURE; + /** * Transfer ownership of the front slice to the caller. Must only be called if the * buffer is not empty otherwise the implementation will have undefined behavior. diff --git a/include/envoy/event/BUILD b/include/envoy/event/BUILD index a51c9345e55f4..790fb45f18398 100644 --- a/include/envoy/event/BUILD +++ b/include/envoy/event/BUILD @@ -41,10 +41,17 @@ envoy_cc_library( hdrs = ["file_event.h"], ) +envoy_cc_library( + name = "scaled_timer_minimum", + hdrs = ["scaled_timer_minimum.h"], + deps = [], +) + envoy_cc_library( name = "scaled_range_timer_manager_interface", hdrs = ["scaled_range_timer_manager.h"], deps = [ + ":scaled_timer_minimum", ":timer_interface", ], ) diff --git a/include/envoy/event/file_event.h b/include/envoy/event/file_event.h index e66289cdb4f0c..cfcb298b30809 100644 --- a/include/envoy/event/file_event.h +++ b/include/envoy/event/file_event.h @@ -18,15 +18,38 @@ struct FileReadyType { static const uint32_t Closed = 0x4; }; -enum class FileTriggerType { Level, Edge }; +enum class FileTriggerType { + // See @man 7 epoll(7) + // They are used on all platforms for DNS and TCP listeners. + Level, + // See @man 7 epoll(7) + // They are used on all platforms that support Edge triggering as the default trigger type. + Edge, + // These are synthetic edge events managed by Envoy. They are based on level events and when they + // are activated they are immediately disabled. This makes them behave like Edge events. Then it + // is is the responsibility of the consumer of the event to reactivate the event + // when the socket operation would block. + // + // Their main application in Envoy is for Win32 which does not support edge-triggered events. They + // should be used in Win32 instead of level events. They can only be used in platforms where + // `PlatformDefaultTriggerType` is `FileTriggerType::EmulatedEdge`. + EmulatedEdge +}; -static constexpr FileTriggerType PlatformDefaultTriggerType -#ifdef WIN32 - // Libevent only supports Level trigger on Windows. - {FileTriggerType::Level}; +// For POSIX developers to get the Windows behavior of file events +// you need to add the following definition: +// `FORCE_LEVEL_EVENTS` +// You can do this with bazel if you add the following build/test options +// `--copt="-DFORCE_LEVEL_EVENTS"` +constexpr FileTriggerType determinePlatformPreferredEventType() { +#if defined(WIN32) || defined(FORCE_LEVEL_EVENTS) + return FileTriggerType::EmulatedEdge; #else - {FileTriggerType::Edge}; + return FileTriggerType::Edge; #endif +} + +static constexpr FileTriggerType PlatformDefaultTriggerType = determinePlatformPreferredEventType(); /** * Callback invoked when a FileEvent is ready for reading or writing. @@ -53,6 +76,16 @@ class FileEvent { * registered events and fire callbacks when they are active. */ virtual void setEnabled(uint32_t events) PURE; + + /** + * Add a single event from the event registration mark. + */ + virtual void registerEventIfEmulatedEdge(uint32_t event) PURE; + + /** + * Remove a single event from the event registration mark. + */ + virtual void unregisterEventIfEmulatedEdge(uint32_t event) PURE; }; using FileEventPtr = std::unique_ptr; diff --git a/include/envoy/event/scaled_range_timer_manager.h b/include/envoy/event/scaled_range_timer_manager.h index 29f5e6b1ae0b1..c563050783526 100644 --- a/include/envoy/event/scaled_range_timer_manager.h +++ b/include/envoy/event/scaled_range_timer_manager.h @@ -1,60 +1,12 @@ #pragma once #include "envoy/common/pure.h" +#include "envoy/event/scaled_timer_minimum.h" #include "envoy/event/timer.h" -#include "absl/types/variant.h" - namespace Envoy { namespace Event { -/** - * Describes a minimum timer value that is equal to a scale factor applied to the maximum. - */ -struct ScaledMinimum { - explicit ScaledMinimum(double scale_factor) : scale_factor_(scale_factor) {} - const double scale_factor_; -}; - -/** - * Describes a minimum timer value that is an absolute duration. - */ -struct AbsoluteMinimum { - explicit AbsoluteMinimum(std::chrono::milliseconds value) : value_(value) {} - const std::chrono::milliseconds value_; -}; - -/** - * Class that describes how to compute a minimum timeout given a maximum timeout value. It wraps - * ScaledMinimum and AbsoluteMinimum and provides a single computeMinimum() method. - */ -class ScaledTimerMinimum : private absl::variant { -public: - // Use base class constructor. - using absl::variant::variant; - - // Computes the minimum value for a given maximum timeout. If this object was constructed with a - // - ScaledMinimum value: - // the return value is the scale factor applied to the provided maximum. - // - AbsoluteMinimum: - // the return value is that minimum, and the provided maximum is ignored. - std::chrono::milliseconds computeMinimum(std::chrono::milliseconds maximum) const { - struct Visitor { - explicit Visitor(std::chrono::milliseconds value) : value_(value) {} - std::chrono::milliseconds operator()(ScaledMinimum scale_factor) { - return std::chrono::duration_cast(scale_factor.scale_factor_ * - value_); - } - std::chrono::milliseconds operator()(AbsoluteMinimum absolute_value) { - return absolute_value.value_; - } - const std::chrono::milliseconds value_; - }; - return absl::visit&>( - Visitor(maximum), *this); - } -}; - /** * Class for creating Timer objects that can be adjusted towards either the minimum or maximum * of their range by the owner of the manager object. Users of this class can call createTimer() to diff --git a/include/envoy/event/scaled_timer_minimum.h b/include/envoy/event/scaled_timer_minimum.h new file mode 100644 index 0000000000000..e0f25aa4f2305 --- /dev/null +++ b/include/envoy/event/scaled_timer_minimum.h @@ -0,0 +1,58 @@ +#pragma once + +#include + +#include "absl/types/variant.h" + +namespace Envoy { +namespace Event { + +/** + * Describes a minimum timer value that is equal to a scale factor applied to the maximum. + */ +struct ScaledMinimum { + explicit ScaledMinimum(double scale_factor) : scale_factor_(scale_factor) {} + const double scale_factor_; +}; + +/** + * Describes a minimum timer value that is an absolute duration. + */ +struct AbsoluteMinimum { + explicit AbsoluteMinimum(std::chrono::milliseconds value) : value_(value) {} + const std::chrono::milliseconds value_; +}; + +/** + * Class that describes how to compute a minimum timeout given a maximum timeout value. It wraps + * ScaledMinimum and AbsoluteMinimum and provides a single computeMinimum() method. + */ +class ScaledTimerMinimum : private absl::variant { +public: + // Use base class constructor. + using absl::variant::variant; + + // Computes the minimum value for a given maximum timeout. If this object was constructed with a + // - ScaledMinimum value: + // the return value is the scale factor applied to the provided maximum. + // - AbsoluteMinimum: + // the return value is that minimum, and the provided maximum is ignored. + std::chrono::milliseconds computeMinimum(std::chrono::milliseconds maximum) const { + struct Visitor { + explicit Visitor(std::chrono::milliseconds value) : value_(value) {} + std::chrono::milliseconds operator()(ScaledMinimum scale_factor) { + return std::chrono::duration_cast(scale_factor.scale_factor_ * + value_); + } + std::chrono::milliseconds operator()(AbsoluteMinimum absolute_value) { + return absolute_value.value_; + } + const std::chrono::milliseconds value_; + }; + return absl::visit&>( + Visitor(maximum), *this); + } +}; + +} // namespace Event +} // namespace Envoy diff --git a/include/envoy/network/connection.h b/include/envoy/network/connection.h index 7efc6ada81754..98c995ab5444c 100644 --- a/include/envoy/network/connection.h +++ b/include/envoy/network/connection.h @@ -118,6 +118,11 @@ class Connection : public Event::DeferredDeletable, public FilterManager { */ virtual void enableHalfClose(bool enabled) PURE; + /** + * @return true if half-close semantics are enabled, false otherwise. + */ + virtual bool isHalfCloseEnabled() PURE; + /** * Close the connection. */ diff --git a/include/envoy/network/io_handle.h b/include/envoy/network/io_handle.h index 03c1b654f1bf3..de530474592a0 100644 --- a/include/envoy/network/io_handle.h +++ b/include/envoy/network/io_handle.h @@ -86,11 +86,12 @@ class IoHandle { virtual Api::IoCallUint64Result writev(const Buffer::RawSlice* slices, uint64_t num_slice) PURE; /** - * Write the buffer out to a file descriptor. - * @param buffer supplies the buffer to write to. - * @return a IoCallUint64Result with err_ = nullptr and rc_ = the number of bytes - * written if successful, or err_ = some IoError for failure. If call failed, rc_ shouldn't be - * used. + * Write the contents of the buffer out to a file descriptor. Bytes that were successfully written + * are drained from the buffer. + * @param buffer supplies the buffer to write from. + * @return a IoCallUint64Result with err_ = nullptr and rc_ = if successful, the number of bytes + * written and drained from the buffer, or err_ = some IoError for failure. If call failed, rc_ + * shouldn't be used. */ virtual Api::IoCallUint64Result write(Buffer::Instance& buffer) PURE; @@ -117,6 +118,9 @@ class IoHandle { unsigned int msg_len_{0}; // The gso_size, if specified in the transport header unsigned int gso_size_{0}; + // If true indicates a successful syscall, but the packet was dropped due to truncation. We do + // not support receiving truncated packets. + bool truncated_and_dropped_{false}; }; /** diff --git a/include/envoy/network/listener.h b/include/envoy/network/listener.h index 4401df6cc20c0..d708d02ce7e07 100644 --- a/include/envoy/network/listener.h +++ b/include/envoy/network/listener.h @@ -378,9 +378,6 @@ class UdpListener : public virtual Listener { /** * Make this listener readable at the beginning of the next event loop. - * - * @note: it may become readable during the current loop if feature - * ``envoy.reloadable_features.activate_fds_next_event_loop`` is disabled. */ virtual void activateRead() PURE; }; diff --git a/include/envoy/server/BUILD b/include/envoy/server/BUILD index a9f7854ba1c2a..0fbd876f0a948 100644 --- a/include/envoy/server/BUILD +++ b/include/envoy/server/BUILD @@ -329,3 +329,15 @@ envoy_cc_library( "//include/envoy/config:typed_config_interface", ], ) + +envoy_cc_library( + name = "fatal_action_interface", + hdrs = ["fatal_action_config.h"], + deps = [ + "//include/envoy/config:typed_config_interface", + "//include/envoy/event:dispatcher_interface", + "//include/envoy/protobuf:message_validator_interface", + "//include/envoy/server:instance_interface", + "@envoy_api//envoy/config/bootstrap/v3:pkg_cc_proto", + ], +) diff --git a/include/envoy/server/fatal_action_config.h b/include/envoy/server/fatal_action_config.h new file mode 100644 index 0000000000000..c8768dced40a9 --- /dev/null +++ b/include/envoy/server/fatal_action_config.h @@ -0,0 +1,59 @@ +#pragma once + +#include + +#include "envoy/common/pure.h" +#include "envoy/config/bootstrap/v3/bootstrap.pb.h" +#include "envoy/config/typed_config.h" +#include "envoy/event/dispatcher.h" +#include "envoy/protobuf/message_validator.h" +#include "envoy/server/instance.h" + +namespace Envoy { +namespace Server { +namespace Configuration { + +class FatalAction { +public: + virtual ~FatalAction() = default; + /** + * Callback function to run when we are crashing. + * @param current_object the object we were working on when we started + * crashing. + */ + virtual void run(const ScopeTrackedObject* current_object) PURE; + + /** + * @return whether the action is async-signal-safe. + * See man 7 signal-safety for the definition of async-signal-safe. + */ + virtual bool isAsyncSignalSafe() const PURE; +}; + +using FatalActionPtr = std::unique_ptr; + +/** + * Implemented by each custom FatalAction and registered via Registry::registerFactory() + * or the convenience class RegisterFactory. + */ +class FatalActionFactory : public Config::TypedFactory { +public: + ~FatalActionFactory() override = default; + + /** + * Creates a particular FatalAction implementation. + * + * @param config supplies the configuration for the action. + * @param context supplies the GuardDog Action's context. + * @return FatalActionsPtr the FatalActions object. + */ + virtual FatalActionPtr + createFatalActionFromProto(const envoy::config::bootstrap::v3::FatalAction& config, + Instance* server) PURE; + + std::string category() const override { return "envoy.fatal_action"; } +}; + +} // namespace Configuration +} // namespace Server +} // namespace Envoy diff --git a/include/envoy/server/overload/BUILD b/include/envoy/server/overload/BUILD index 990a306c7fd48..89ae23c63c2a5 100644 --- a/include/envoy/server/overload/BUILD +++ b/include/envoy/server/overload/BUILD @@ -23,6 +23,7 @@ envoy_cc_library( name = "thread_local_overload_state", hdrs = ["thread_local_overload_state.h"], deps = [ + "//include/envoy/event:scaled_timer_minimum", "//include/envoy/event:timer_interface", "//include/envoy/thread_local:thread_local_object", ], diff --git a/include/envoy/server/overload/thread_local_overload_state.h b/include/envoy/server/overload/thread_local_overload_state.h index 6c94fab5cd42f..8d95a42b01323 100644 --- a/include/envoy/server/overload/thread_local_overload_state.h +++ b/include/envoy/server/overload/thread_local_overload_state.h @@ -4,6 +4,7 @@ #include #include "envoy/common/pure.h" +#include "envoy/event/scaled_timer_minimum.h" #include "envoy/event/timer.h" #include "envoy/thread_local/thread_local_object.h" @@ -57,6 +58,10 @@ class ThreadLocalOverloadState : public ThreadLocal::ThreadLocalObject { // Get a scaled timer whose minimum corresponds to the configured value for the given timer type. virtual Event::TimerPtr createScaledTimer(OverloadTimerType timer_type, Event::TimerCb callback) PURE; + + // Get a scaled timer whose minimum is determined by the given scaling rule. + virtual Event::TimerPtr createScaledTimer(Event::ScaledTimerMinimum minimum, + Event::TimerCb callback) PURE; }; } // namespace Server diff --git a/include/envoy/upstream/cluster_manager.h b/include/envoy/upstream/cluster_manager.h index 5939092a371be..aff096838adc5 100644 --- a/include/envoy/upstream/cluster_manager.h +++ b/include/envoy/upstream/cluster_manager.h @@ -73,6 +73,47 @@ using ClusterUpdateCallbacksHandlePtr = std::unique_ptr void checkAndDecrement(T& value, uint32_t delta) { + ASSERT(delta <= value); + value -= delta; + } + + template void checkAndIncrement(T& value, uint32_t delta) { + ASSERT(std::numeric_limits::max() - value > delta); + value += delta; + } + + void incrPendingStreams(uint32_t delta) { checkAndIncrement(pending_streams_, delta); } + void decrPendingStreams(uint32_t delta) { checkAndDecrement(pending_streams_, delta); } + void incrConnectingStreamCapacity(uint32_t delta) { + checkAndIncrement(connecting_stream_capacity_, delta); + } + void decrConnectingStreamCapacity(uint32_t delta) { + checkAndDecrement(connecting_stream_capacity_, delta); + } + void incrActiveStreams(uint32_t delta) { checkAndIncrement(active_streams_, delta); } + void decrActiveStreams(uint32_t delta) { checkAndDecrement(active_streams_, delta); } + + // Tracks the number of pending streams for this ClusterManager. + uint32_t pending_streams_{}; + // Tracks the number of active streams for this ClusterManager. + uint32_t active_streams_{}; + // Tracks the available stream capacity if all connecting connections were connected. + // + // For example, if an H2 connection is started with concurrent stream limit of 100, this + // goes up by 100. If the connection is established and 2 streams are in use, it + // would be reduced to 98 (as 2 of the 100 are not available). + uint64_t connecting_stream_capacity_{}; +}; + /** * Manages connection pools and load balancing for upstream clusters. The cluster manager is * persistent and shared among multiple ongoing requests/connections. @@ -126,12 +167,15 @@ class ClusterManager { initializeSecondaryClusters(const envoy::config::bootstrap::v3::Bootstrap& bootstrap) PURE; using ClusterInfoMap = absl::node_hash_map>; + struct ClusterInfoMaps { + ClusterInfoMap active_clusters_; + ClusterInfoMap warming_clusters_; + }; /** - * @return ClusterInfoMap all current clusters. These are the primary (not thread local) - * clusters which should only be used for stats/admin. + * @return ClusterInfoMap all current clusters including active and warming. */ - virtual ClusterInfoMap clusters() PURE; + virtual ClusterInfoMaps clusters() PURE; using ClusterSet = absl::flat_hash_set; @@ -318,7 +362,8 @@ class ClusterManagerFactory { allocateConnPool(Event::Dispatcher& dispatcher, HostConstSharedPtr host, ResourcePriority priority, Http::Protocol protocol, const Network::ConnectionSocket::OptionsSharedPtr& options, - const Network::TransportSocketOptionsSharedPtr& transport_socket_options) PURE; + const Network::TransportSocketOptionsSharedPtr& transport_socket_options, + ClusterConnectivityState& state) PURE; /** * Allocate a TCP connection pool for the host. Pools are separated by 'priority' and @@ -328,7 +373,8 @@ class ClusterManagerFactory { allocateTcpConnPool(Event::Dispatcher& dispatcher, HostConstSharedPtr host, ResourcePriority priority, const Network::ConnectionSocket::OptionsSharedPtr& options, - Network::TransportSocketOptionsSharedPtr transport_socket_options) PURE; + Network::TransportSocketOptionsSharedPtr transport_socket_options, + ClusterConnectivityState& state) PURE; /** * Allocate a cluster from configuration proto. diff --git a/source/common/api/win32/os_sys_calls_impl.cc b/source/common/api/win32/os_sys_calls_impl.cc index 5169f6855b504..f0f9768dc0c17 100644 --- a/source/common/api/win32/os_sys_calls_impl.cc +++ b/source/common/api/win32/os_sys_calls_impl.cc @@ -144,14 +144,22 @@ SysCallSizeResult OsSysCallsImpl::recv(os_fd_t socket, void* buffer, size_t leng } SysCallSizeResult OsSysCallsImpl::recvmsg(os_fd_t sockfd, msghdr* msg, int flags) { - DWORD bytes_received; + DWORD bytes_received = 0; LPFN_WSARECVMSG recvmsg_fn_ptr = getFnPtrWSARecvMsg(); wsamsgResult wsamsg = msghdrToWSAMSG(msg); // Windows supports only a single flag on input to WSARecvMsg wsamsg.wsamsg_->dwFlags = flags & MSG_PEEK; const int rc = recvmsg_fn_ptr(sockfd, wsamsg.wsamsg_.get(), &bytes_received, nullptr, nullptr); if (rc == SOCKET_ERROR) { - return {-1, ::WSAGetLastError()}; + // We try to match the UNIX behavior for truncated packages. In that case the return code is + // the length of the allocated buffer and we get the value from `dwFlags`. + auto last_error = ::WSAGetLastError(); + if (last_error == WSAEMSGSIZE) { + msg->msg_flags = wsamsg.wsamsg_->dwFlags; + return {bytes_received, 0}; + } + + return {rc, last_error}; } msg->msg_namelen = wsamsg.wsamsg_->namelen; msg->msg_flags = wsamsg.wsamsg_->dwFlags; diff --git a/source/common/buffer/buffer_impl.cc b/source/common/buffer/buffer_impl.cc index 556faf73d6385..f43507ac9530e 100644 --- a/source/common/buffer/buffer_impl.cc +++ b/source/common/buffer/buffer_impl.cc @@ -201,6 +201,17 @@ RawSliceVector OwnedImpl::getRawSlices(absl::optional max_slices) cons return raw_slices; } +RawSlice OwnedImpl::frontSlice() const { + // Ignore zero-size slices and return the first slice with data. + for (const auto& slice : slices_) { + if (slice->dataSize() > 0) { + return RawSlice{slice->data(), slice->dataSize()}; + } + } + + return {nullptr, 0}; +} + SliceDataPtr OwnedImpl::extractMutableFrontSlice() { RELEASE_ASSERT(length_ > 0, "Extract called on empty buffer"); // Remove zero byte fragments from the front of the queue to ensure diff --git a/source/common/buffer/buffer_impl.h b/source/common/buffer/buffer_impl.h index cfbaadd823233..1801068867323 100644 --- a/source/common/buffer/buffer_impl.h +++ b/source/common/buffer/buffer_impl.h @@ -564,6 +564,7 @@ class OwnedImpl : public LibEventInstance { void copyOut(size_t start, uint64_t size, void* data) const override; void drain(uint64_t size) override; RawSliceVector getRawSlices(absl::optional max_slices = absl::nullopt) const override; + RawSlice frontSlice() const override; SliceDataPtr extractMutableFrontSlice() override; uint64_t length() const override; void* linearize(uint32_t size) override; diff --git a/source/common/buffer/zero_copy_input_stream_impl.cc b/source/common/buffer/zero_copy_input_stream_impl.cc index 6b805eaf01a02..bfd0e4794c0a3 100644 --- a/source/common/buffer/zero_copy_input_stream_impl.cc +++ b/source/common/buffer/zero_copy_input_stream_impl.cc @@ -29,10 +29,9 @@ void ZeroCopyInputStreamImpl::drainLastSlice() { bool ZeroCopyInputStreamImpl::Next(const void** data, int* size) { drainLastSlice(); - Buffer::RawSliceVector slices = buffer_->getRawSlices(1); + Buffer::RawSlice slice = buffer_->frontSlice(); - if (!slices.empty() && slices[0].len_ > 0) { - auto& slice = slices[0]; + if (slice.len_ > 0) { *data = slice.mem_; *size = slice.len_; position_ = slice.len_; diff --git a/source/common/common/assert.cc b/source/common/common/assert.cc index 1daf69b9abb90..5eab3ef608758 100644 --- a/source/common/common/assert.cc +++ b/source/common/common/assert.cc @@ -83,7 +83,7 @@ class EnvoyBugRegistrationImpl : public ActionRegistration { using EnvoyBugMap = absl::flat_hash_map; static absl::Mutex mutex_; - static EnvoyBugMap counters_ GUARDED_BY(mutex_); + static EnvoyBugMap counters_ ABSL_GUARDED_BY(mutex_); }; std::function ActionRegistrationImpl::debug_assertion_failure_record_action_; diff --git a/source/common/common/perf_annotation.h b/source/common/common/perf_annotation.h index 7187244322d08..7fba5aec0321f 100644 --- a/source/common/common/perf_annotation.h +++ b/source/common/common/perf_annotation.h @@ -42,6 +42,32 @@ perf.record(category, description); \ } while (false) +/** + * Declares a storage member for a performance operation inside an owner class. + * A perf_var can then be instantiated in one of the owner's methods with + * PERF_OWNED_OPERATION(perf_var) and reported multiple times in any method with + * PERF_OWNED_RECORD(perf_var, category, description). + */ +#define PERF_OWNER(perf_var) std::unique_ptr perf_var + +/** + * Instantiates a performance operation, initiates and stores it in the owner annotated with + * PERF_OWNER. + */ +#define PERF_OWNED_OPERATION(perf_var) \ + do { \ + perf_var = std::make_unique(); \ + } while (false) + +/** + * Records performance data initiated with PERF_OWNED_OPERATION. The category + * and descriptions have the same meaning as in PERF_RECORD. + */ +#define PERF_OWNED_RECORD(perf_var, category, description) \ + do { \ + perf_var->record(category, description); \ + } while (false) + /** * Dumps recorded performance data to stdout. Expands to nothing if not enabled. */ @@ -190,6 +216,12 @@ class PerfOperation { #define PERF_RECORD(perf, category, description) \ do { \ } while (false) +#define PERF_OWNED_OPERATION(perf_var) \ + do { \ + } while (false) +#define PERF_OWNED_RECORD(perf, category, description) \ + do { \ + } while (false) #define PERF_DUMP() \ do { \ } while (false) @@ -198,4 +230,7 @@ class PerfOperation { do { \ } while (false) +// Empty declaration used when performance collection is disabled. +#define PERF_OWNER(perf_var) + #endif diff --git a/source/common/common/regex.h b/source/common/common/regex.h index 68cb7ff8074d1..2fdcd52ebc1ce 100644 --- a/source/common/common/regex.h +++ b/source/common/common/regex.h @@ -9,6 +9,8 @@ namespace Envoy { namespace Regex { +enum class Type { Re2, StdRegex }; + /** * Utilities for constructing regular expressions. */ diff --git a/source/common/common/utility.cc b/source/common/common/utility.cc index 0c72f30c816e3..2ed40659314c0 100644 --- a/source/common/common/utility.cc +++ b/source/common/common/utility.cc @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include #include @@ -221,6 +223,19 @@ std::string DateFormatter::now(TimeSource& time_source) { return fromTime(time_source.systemTime()); } +MutableMemoryStreamBuffer::MutableMemoryStreamBuffer(char* base, size_t size) { + this->setp(base, base + size); +} + +OutputBufferStream::OutputBufferStream(char* data, size_t size) + : MutableMemoryStreamBuffer{data, size}, std::ostream{static_cast(this)} {} + +int OutputBufferStream::bytesWritten() const { return pptr() - pbase(); } + +absl::string_view OutputBufferStream::contents() const { + return absl::string_view(pbase(), bytesWritten()); +} + ConstMemoryStreamBuffer::ConstMemoryStreamBuffer(const char* data, size_t size) { // std::streambuf won't modify `data`, but the interface still requires a char* for convenience, // so we need to const_cast. diff --git a/source/common/common/utility.h b/source/common/common/utility.h index f91d74832b60e..e4eba5b371177 100644 --- a/source/common/common/utility.h +++ b/source/common/common/utility.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -110,6 +111,32 @@ class RealTimeSource : public TimeSource { MonotonicTime monotonicTime() override { return std::chrono::steady_clock::now(); } }; +/** + * Class used for creating non-memory allocating std::ostream. + */ +class MutableMemoryStreamBuffer : public std::streambuf { +public: + MutableMemoryStreamBuffer(char* base, size_t size); +}; + +/** + * std::ostream class that serializes writes into the provided buffer. + */ +class OutputBufferStream : private MutableMemoryStreamBuffer, public std::ostream { +public: + OutputBufferStream(char* data, size_t size); + + /** + * @return the number of bytes written prior to the "put" pointer into the buffer. + */ + int bytesWritten() const; + + /** + * @return a string view of the written bytes. + */ + absl::string_view contents() const; +}; + /** * Class used for creating non-copying std::istream's. See InputConstMemoryStream below. */ diff --git a/source/common/config/BUILD b/source/common/config/BUILD index cf1ac31142ffb..baf4f851e9980 100644 --- a/source/common/config/BUILD +++ b/source/common/config/BUILD @@ -444,12 +444,24 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "watched_directory_lib", + srcs = ["watched_directory.cc"], + hdrs = ["watched_directory.h"], + deps = [ + "//include/envoy/event:dispatcher_interface", + "//include/envoy/filesystem:watcher_interface", + "@envoy_api//envoy/config/core/v3:pkg_cc_proto", + ], +) + envoy_cc_library( name = "well_known_names", srcs = ["well_known_names.cc"], hdrs = ["well_known_names.h"], deps = [ "//source/common/common:assert_lib", + "//source/common/common:regex_lib", "//source/common/singleton:const_singleton", ], ) diff --git a/source/common/config/version_converter.cc b/source/common/config/version_converter.cc index db2bd1cfc2162..0477c29bcf861 100644 --- a/source/common/config/version_converter.cc +++ b/source/common/config/version_converter.cc @@ -78,20 +78,28 @@ void VersionConverter::annotateWithOriginalType(const Protobuf::Descriptor& prev void onMessage(Protobuf::Message& message, const void* ctxt) override { const Protobuf::Descriptor* descriptor = message.GetDescriptor(); const Protobuf::Reflection* reflection = message.GetReflection(); - const Protobuf::Descriptor& prev_descriptor = *static_cast(ctxt); + const Protobuf::Descriptor* prev_descriptor = static_cast(ctxt); + // If there is no previous descriptor for this message, we don't need to annotate anything. + if (prev_descriptor == nullptr) { + return; + } // If they are the same type, there's no possibility of any different type // further down, so we're done. - if (descriptor->full_name() == prev_descriptor.full_name()) { + if (descriptor->full_name() == prev_descriptor->full_name()) { return; } auto* unknown_field_set = reflection->MutableUnknownFields(&message); unknown_field_set->AddLengthDelimited(ProtobufWellKnown::OriginalTypeFieldNumber, - prev_descriptor.full_name()); + prev_descriptor->full_name()); } const void* onField(Protobuf::Message&, const Protobuf::FieldDescriptor& field, const void* ctxt) override { - const Protobuf::Descriptor& prev_descriptor = *static_cast(ctxt); + const Protobuf::Descriptor* prev_descriptor = static_cast(ctxt); + // If there is no previous descriptor for this field, we don't need to annotate anything. + if (prev_descriptor == nullptr) { + return nullptr; + } // TODO(htuch): This is a terrible hack, there should be no per-resource // business logic in this file. The reason this is required is that // endpoints, when captured in configuration such as inlined hosts in @@ -101,13 +109,13 @@ void VersionConverter::annotateWithOriginalType(const Protobuf::Descriptor& prev // In theory, we should be able to just clean up these annotations in // ClusterManagerImpl with type erasure, but protobuf doesn't free up memory // as expected, we probably need some arena level trick to address this. - if (prev_descriptor.full_name() == "envoy.api.v2.Cluster" && + if (prev_descriptor->full_name() == "envoy.api.v2.Cluster" && (field.name() == "hidden_envoy_deprecated_hosts" || field.name() == "load_assignment")) { // This will cause the sub-message visit to abort early. return field.message_type(); } const Protobuf::FieldDescriptor* prev_field = - prev_descriptor.FindFieldByNumber(field.number()); + prev_descriptor->FindFieldByNumber(field.number()); return prev_field != nullptr ? prev_field->message_type() : nullptr; } }; diff --git a/source/common/config/watched_directory.cc b/source/common/config/watched_directory.cc new file mode 100644 index 0000000000000..c3843ee3f71c7 --- /dev/null +++ b/source/common/config/watched_directory.cc @@ -0,0 +1,14 @@ +#include "common/config/watched_directory.h" + +namespace Envoy { +namespace Config { + +WatchedDirectory::WatchedDirectory(const envoy::config::core::v3::WatchedDirectory& config, + Event::Dispatcher& dispatcher) { + watcher_ = dispatcher.createFilesystemWatcher(); + watcher_->addWatch(absl::StrCat(config.path(), "/"), Filesystem::Watcher::Events::MovedTo, + [this](uint32_t) { cb_(); }); +} + +} // namespace Config +} // namespace Envoy diff --git a/source/common/config/watched_directory.h b/source/common/config/watched_directory.h new file mode 100644 index 0000000000000..34e965a0b4df0 --- /dev/null +++ b/source/common/config/watched_directory.h @@ -0,0 +1,28 @@ +#pragma once + +#include "envoy/config/core/v3/base.pb.h" +#include "envoy/event/dispatcher.h" +#include "envoy/filesystem/watcher.h" + +namespace Envoy { +namespace Config { + +// Implement the common functionality of envoy::config::core::v3::WatchedDirectory. +class WatchedDirectory { +public: + using Callback = std::function; + + WatchedDirectory(const envoy::config::core::v3::WatchedDirectory& config, + Event::Dispatcher& dispatcher); + + void setCallback(Callback cb) { cb_ = cb; } + +private: + std::unique_ptr watcher_; + Callback cb_; +}; + +using WatchedDirectoryPtr = std::unique_ptr; + +} // namespace Config +} // namespace Envoy diff --git a/source/common/config/well_known_names.cc b/source/common/config/well_known_names.cc index e2677cb742a49..e8fc767c41a3b 100644 --- a/source/common/config/well_known_names.cc +++ b/source/common/config/well_known_names.cc @@ -92,7 +92,7 @@ TagNameValues::TagNameValues() { addRegex(RATELIMIT_PREFIX, R"(^ratelimit\.((.*?)\.)\w+?$)"); // cluster.(.)* - addRegex(CLUSTER_NAME, "^cluster\\.((.*?)\\.)"); + addRe2(CLUSTER_NAME, "^cluster\\.(([^\\.]+)\\.).*"); // listener.[
.]http.(.)* addRegex(HTTP_CONN_MANAGER_PREFIX, R"(^listener(?=\.).*?\.http\.((.*?)\.))", ".http."); @@ -119,7 +119,12 @@ TagNameValues::TagNameValues() { void TagNameValues::addRegex(const std::string& name, const std::string& regex, const std::string& substr) { - descriptor_vec_.emplace_back(Descriptor(name, regex, substr)); + descriptor_vec_.emplace_back(Descriptor{name, regex, substr, Regex::Type::StdRegex}); +} + +void TagNameValues::addRe2(const std::string& name, const std::string& regex, + const std::string& substr) { + descriptor_vec_.emplace_back(Descriptor{name, regex, substr, Regex::Type::Re2}); } } // namespace Config diff --git a/source/common/config/well_known_names.h b/source/common/config/well_known_names.h index 1d3cd09c51d80..97ce58fd7265c 100644 --- a/source/common/config/well_known_names.h +++ b/source/common/config/well_known_names.h @@ -6,6 +6,7 @@ #include "envoy/common/exception.h" #include "common/common/assert.h" +#include "common/common/regex.h" #include "common/singleton/const_singleton.h" namespace Envoy { @@ -62,11 +63,10 @@ class TagNameValues { * tags, such as "_rq_(\\d)xx$", will probably stay as regexes. */ struct Descriptor { - Descriptor(const std::string& name, const std::string& regex, const std::string& substr = "") - : name_(name), regex_(regex), substr_(substr) {} const std::string name_; const std::string regex_; const std::string substr_; + const Regex::Type re_type_; }; // Cluster name tag @@ -130,6 +130,7 @@ class TagNameValues { private: void addRegex(const std::string& name, const std::string& regex, const std::string& substr = ""); + void addRe2(const std::string& name, const std::string& regex, const std::string& substr = ""); // Collection of tag descriptors. std::vector descriptor_vec_; diff --git a/source/common/conn_pool/conn_pool_base.cc b/source/common/conn_pool/conn_pool_base.cc index bc5293e99318e..daec20bc40fc0 100644 --- a/source/common/conn_pool/conn_pool_base.cc +++ b/source/common/conn_pool/conn_pool_base.cc @@ -12,9 +12,10 @@ namespace ConnectionPool { ConnPoolImplBase::ConnPoolImplBase( Upstream::HostConstSharedPtr host, Upstream::ResourcePriority priority, Event::Dispatcher& dispatcher, const Network::ConnectionSocket::OptionsSharedPtr& options, - const Network::TransportSocketOptionsSharedPtr& transport_socket_options) - : host_(host), priority_(priority), dispatcher_(dispatcher), socket_options_(options), - transport_socket_options_(transport_socket_options) {} + const Network::TransportSocketOptionsSharedPtr& transport_socket_options, + Upstream::ClusterConnectivityState& state) + : state_(state), host_(host), priority_(priority), dispatcher_(dispatcher), + socket_options_(options), transport_socket_options_(transport_socket_options) {} ConnPoolImplBase::~ConnPoolImplBase() { ASSERT(ready_clients_.empty()); @@ -107,6 +108,8 @@ bool ConnPoolImplBase::tryCreateNewConnection(float global_prefetch_ratio) { ASSERT(std::numeric_limits::max() - connecting_stream_capacity_ >= client->effectiveConcurrentStreamLimit()); ASSERT(client->real_host_description_); + // Increase the connecting capacity to reflect the streams this connection can serve. + state_.incrConnectingStreamCapacity(client->effectiveConcurrentStreamLimit()); connecting_stream_capacity_ += client->effectiveConcurrentStreamLimit(); LinkedList::moveIntoList(std::move(client), owningList(client->state_)); } @@ -135,6 +138,10 @@ void ConnPoolImplBase::attachStreamToClient(Envoy::ConnectionPool::ActiveClient& transitionActiveClientState(client, Envoy::ConnectionPool::ActiveClient::State::BUSY); } + // Decrement the capacity, as there's one less stream available for serving. + state_.decrConnectingStreamCapacity(1); + // Track the new active stream. + state_.incrActiveStreams(1); num_active_streams_++; host_->stats().rq_total_.inc(); host_->stats().rq_active_.inc(); @@ -150,10 +157,18 @@ void ConnPoolImplBase::onStreamClosed(Envoy::ConnectionPool::ActiveClient& clien bool delay_attaching_stream) { ENVOY_CONN_LOG(debug, "destroying stream: {} remaining", client, client.numActiveStreams()); ASSERT(num_active_streams_ > 0); + // Reflect there's one less stream in flight. + state_.decrActiveStreams(1); num_active_streams_--; host_->stats().rq_active_.dec(); host_->cluster().stats().upstream_rq_active_.dec(); host_->cluster().resourceManager(priority_).requests().dec(); + // If the effective client capacity was limited by concurrency, increase connecting capacity. + // If the effective client capacity was limited by max total streams, this will not result in an + // increment as no capacity is freed up. + if (client.remaining_streams_ > client.concurrent_stream_limit_ - client.numActiveStreams() - 1) { + state_.incrConnectingStreamCapacity(1); + } if (client.state_ == ActiveClient::State::DRAINING && client.numActiveStreams() == 0) { // Close out the draining client if we no longer have active streams. client.close(); @@ -205,6 +220,7 @@ void ConnPoolImplBase::onUpstreamReady() { ENVOY_CONN_LOG(debug, "attaching to next stream", *client); // Pending streams are pushed onto the front, so pull from the back. attachStreamToClient(*client, pending_streams_.back()->context()); + state_.decrPendingStreams(1); pending_streams_.pop_back(); } } @@ -310,6 +326,9 @@ void ConnPoolImplBase::onConnectionEvent(ActiveClient& client, absl::string_view if (event == Network::ConnectionEvent::RemoteClose || event == Network::ConnectionEvent::LocalClose) { + state_.decrConnectingStreamCapacity(client.currentUnusedCapacity()); + // Make sure that onStreamClosed won't double count. + client.remaining_streams_ = 0; // The client died. ENVOY_CONN_LOG(debug, "client disconnected, failure reason: {}", client, failure_reason); @@ -397,6 +416,7 @@ void ConnPoolImplBase::purgePendingStreams( absl::string_view failure_reason, ConnectionPool::PoolFailureReason reason) { // NOTE: We move the existing pending streams to a temporary list. This is done so that // if retry logic submits a new stream to the pool, we don't fail it inline. + state_.decrPendingStreams(pending_streams_.size()); pending_streams_to_purge_ = std::move(pending_streams_); while (!pending_streams_to_purge_.empty()) { PendingStreamPtr stream = @@ -431,6 +451,7 @@ void ConnPoolImplBase::onPendingStreamCancel(PendingStream& stream, // and there is no need to call its onPoolFailure callback. stream.removeFromList(pending_streams_to_purge_); } else { + state_.decrPendingStreams(1); stream.removeFromList(pending_streams_); } if (policy == Envoy::ConnectionPool::CancelPolicy::CloseExcess && !connecting_clients_.empty() && @@ -447,13 +468,13 @@ void ConnPoolImplBase::onPendingStreamCancel(PendingStream& stream, namespace { // Translate zero to UINT64_MAX so that the zero/unlimited case doesn't // have to be handled specially. -uint64_t translateZeroToUnlimited(uint64_t limit) { - return (limit != 0) ? limit : std::numeric_limits::max(); +uint32_t translateZeroToUnlimited(uint32_t limit) { + return (limit != 0) ? limit : std::numeric_limits::max(); } } // namespace -ActiveClient::ActiveClient(ConnPoolImplBase& parent, uint64_t lifetime_stream_limit, - uint64_t concurrent_stream_limit) +ActiveClient::ActiveClient(ConnPoolImplBase& parent, uint32_t lifetime_stream_limit, + uint32_t concurrent_stream_limit) : parent_(parent), remaining_streams_(translateZeroToUnlimited(lifetime_stream_limit)), concurrent_stream_limit_(translateZeroToUnlimited(concurrent_stream_limit)), connect_timer_(parent_.dispatcher().createTimer([this]() -> void { onConnectTimeout(); })) { diff --git a/source/common/conn_pool/conn_pool_base.h b/source/common/conn_pool/conn_pool_base.h index 83265bd23ced9..3cc2c2d089536 100644 --- a/source/common/conn_pool/conn_pool_base.h +++ b/source/common/conn_pool/conn_pool_base.h @@ -4,6 +4,7 @@ #include "envoy/event/dispatcher.h" #include "envoy/network/connection.h" #include "envoy/stats/timespan.h" +#include "envoy/upstream/cluster_manager.h" #include "common/common/linked_object.h" @@ -28,8 +29,8 @@ class ActiveClient : public LinkedObject, public Event::DeferredDeletable, protected Logger::Loggable { public: - ActiveClient(ConnPoolImplBase& parent, uint64_t lifetime_stream_limit, - uint64_t concurrent_stream_limit); + ActiveClient(ConnPoolImplBase& parent, uint32_t lifetime_stream_limit, + uint32_t concurrent_stream_limit); ~ActiveClient() override; void releaseResources(); @@ -44,10 +45,14 @@ class ActiveClient : public LinkedObject, // Returns the concurrent stream limit, accounting for if the total stream limit // is less than the concurrent stream limit. - uint64_t effectiveConcurrentStreamLimit() const { + uint32_t effectiveConcurrentStreamLimit() const { return std::min(remaining_streams_, concurrent_stream_limit_); } + uint32_t currentUnusedCapacity() const { + return std::min(remaining_streams_, concurrent_stream_limit_ - numActiveStreams()); + } + // Closes the underlying connection. virtual void close() PURE; // Returns the ID of the underlying connection. @@ -55,7 +60,7 @@ class ActiveClient : public LinkedObject, // Returns true if this closed with an incomplete stream, for stats tracking/ purposes. virtual bool closingWithIncompleteStream() const PURE; // Returns the number of active streams on this connection. - virtual size_t numActiveStreams() const PURE; + virtual uint32_t numActiveStreams() const PURE; enum class State { CONNECTING, // Connection is not yet established. @@ -67,8 +72,8 @@ class ActiveClient : public LinkedObject, }; ConnPoolImplBase& parent_; - uint64_t remaining_streams_; - const uint64_t concurrent_stream_limit_; + uint32_t remaining_streams_; + const uint32_t concurrent_stream_limit_; State state_{State::CONNECTING}; Upstream::HostDescriptionConstSharedPtr real_host_description_; Stats::TimespanPtr conn_connect_ms_; @@ -105,7 +110,8 @@ class ConnPoolImplBase : protected Logger::Loggable { ConnPoolImplBase(Upstream::HostConstSharedPtr host, Upstream::ResourcePriority priority, Event::Dispatcher& dispatcher, const Network::ConnectionSocket::OptionsSharedPtr& options, - const Network::TransportSocketOptionsSharedPtr& transport_socket_options); + const Network::TransportSocketOptionsSharedPtr& transport_socket_options, + Upstream::ClusterConnectivityState& state); virtual ~ConnPoolImplBase(); // A helper function to get the specific context type from the base class context. @@ -196,6 +202,22 @@ class ConnPoolImplBase : protected Logger::Loggable { float perUpstreamPrefetchRatio() const; + ConnectionPool::Cancellable* + addPendingStream(Envoy::ConnectionPool::PendingStreamPtr&& pending_stream) { + LinkedList::moveIntoList(std::move(pending_stream), pending_streams_); + state_.incrPendingStreams(1); + return pending_streams_.front().get(); + } + + bool hasActiveStreams() const { return num_active_streams_ > 0; } + + void decrConnectingStreamCapacity(int32_t delta) { + state_.decrConnectingStreamCapacity(delta); + connecting_stream_capacity_ -= delta; + } + + Upstream::ClusterConnectivityState& state_; + const Upstream::HostConstSharedPtr host_; const Upstream::ResourcePriority priority_; @@ -204,7 +226,6 @@ class ConnPoolImplBase : protected Logger::Loggable { const Network::TransportSocketOptionsSharedPtr transport_socket_options_; std::list drained_callbacks_; - std::list pending_streams_; // When calling purgePendingStreams, this list will be used to hold the streams we are about // to purge. We need this if one cancelled streams cancels a different pending stream @@ -220,12 +241,15 @@ class ConnPoolImplBase : protected Logger::Loggable { // Clients that are not ready to handle additional streams because they are CONNECTING. std::list connecting_clients_; +private: + std::list pending_streams_; + // The number of streams currently attached to clients. - uint64_t num_active_streams_{0}; + uint32_t num_active_streams_{0}; // The number of streams that can be immediately dispatched // if all CONNECTING connections become connected. - uint64_t connecting_stream_capacity_{0}; + uint32_t connecting_stream_capacity_{0}; }; } // namespace ConnectionPool diff --git a/source/common/event/BUILD b/source/common/event/BUILD index 5e538bc52cf67..99c30f683fc67 100644 --- a/source/common/event/BUILD +++ b/source/common/event/BUILD @@ -33,7 +33,6 @@ envoy_cc_library( "//source/common/network:dns_lib", "//source/common/network:connection_lib", "//source/common/network:listener_lib", - "//source/common/runtime:runtime_features_lib", ] + select({ "//bazel:apple": ["//source/common/network:apple_dns_lib"], "//conditions:default": [], diff --git a/source/common/event/dispatcher_impl.cc b/source/common/event/dispatcher_impl.cc index d615e5986f5d6..382ea30f1d665 100644 --- a/source/common/event/dispatcher_impl.cc +++ b/source/common/event/dispatcher_impl.cc @@ -278,6 +278,19 @@ void DispatcherImpl::runPostCallbacks() { } } +void DispatcherImpl::runFatalActionsOnTrackedObject( + const FatalAction::FatalActionPtrList& actions) const { + // Only run if this is the dispatcher of the current thread and + // DispatcherImpl::Run has been called. + if (run_tid_.isEmpty() || (run_tid_ != api_.threadFactory().currentThreadId())) { + return; + } + + for (const auto& action : actions) { + action->run(current_object_); + } +} + void DispatcherImpl::touchWatchdog() { if (watchdog_registration_) { watchdog_registration_->touchWatchdog(); diff --git a/source/common/event/dispatcher_impl.h b/source/common/event/dispatcher_impl.h index 62c10920d7fea..46de3a8b50f7d 100644 --- a/source/common/event/dispatcher_impl.h +++ b/source/common/event/dispatcher_impl.h @@ -94,6 +94,9 @@ class DispatcherImpl : Logger::Loggable, } } + void + runFatalActionsOnTrackedObject(const FatalAction::FatalActionPtrList& actions) const override; + private: // Holds a reference to the watchdog registered with this dispatcher and the timer used to ensure // that the dog is touched periodically. diff --git a/source/common/event/file_event_impl.cc b/source/common/event/file_event_impl.cc index 028bd18cfdf0e..ac99c7ad47e71 100644 --- a/source/common/event/file_event_impl.cc +++ b/source/common/event/file_event_impl.cc @@ -4,7 +4,6 @@ #include "common/common/assert.h" #include "common/event/dispatcher_impl.h" -#include "common/runtime/runtime_features.h" #include "event2/event.h" @@ -13,32 +12,24 @@ namespace Event { FileEventImpl::FileEventImpl(DispatcherImpl& dispatcher, os_fd_t fd, FileReadyCb cb, FileTriggerType trigger, uint32_t events) - : cb_(cb), fd_(fd), trigger_(trigger), - activate_fd_events_next_event_loop_( - // Only read the runtime feature if the runtime loader singleton has already been created. - // Attempts to access runtime features too early in the initialization sequence triggers - // some spurious, scary-looking logs about not being able to read runtime feature config - // from the singleton. These warnings are caused by creation of filesystem watchers as - // part of the process of loading the runtime configuration from disk. - Runtime::LoaderSingleton::getExisting() - ? Runtime::runtimeFeatureEnabled( - "envoy.reloadable_features.activate_fds_next_event_loop") - : true) { + : cb_(cb), fd_(fd), trigger_(trigger), enabled_events_(events), + activation_cb_(dispatcher.createSchedulableCallback([this]() { + ASSERT(injected_activation_events_ != 0); + mergeInjectedEventsAndRunCb(0); + })) { // Treat the lack of a valid fd (which in practice should only happen if we run out of FDs) as // an OOM condition and just crash. RELEASE_ASSERT(SOCKET_VALID(fd), ""); #ifdef WIN32 - RELEASE_ASSERT(trigger_ == FileTriggerType::Level, - "libevent does not support edge triggers on Windows"); + ASSERT(trigger_ != FileTriggerType::Edge, "libevent does not support edge triggers on Windows"); #endif + if constexpr (PlatformDefaultTriggerType != FileTriggerType::EmulatedEdge) { + ASSERT(trigger_ != FileTriggerType::EmulatedEdge, + "Cannot use EmulatedEdge events if they are not the default platform type"); + } + assignEvents(events, &dispatcher.base()); event_add(&raw_event_, nullptr); - if (activate_fd_events_next_event_loop_) { - activation_cb_ = dispatcher.createSchedulableCallback([this]() { - ASSERT(injected_activation_events_ != 0); - mergeInjectedEventsAndRunCb(0); - }); - } } void FileEventImpl::activate(uint32_t events) { @@ -47,26 +38,6 @@ void FileEventImpl::activate(uint32_t events) { // Only supported event types are set. ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == events); - if (!activate_fd_events_next_event_loop_) { - // Legacy implementation - int libevent_events = 0; - if (events & FileReadyType::Read) { - libevent_events |= EV_READ; - } - - if (events & FileReadyType::Write) { - libevent_events |= EV_WRITE; - } - - if (events & FileReadyType::Closed) { - libevent_events |= EV_CLOSED; - } - - ASSERT(libevent_events); - event_active(&raw_event_, libevent_events, 0); - return; - } - // Schedule the activation callback so it runs as part of the next loop iteration if it is not // already scheduled. if (injected_activation_events_ == 0) { @@ -81,9 +52,10 @@ void FileEventImpl::activate(uint32_t events) { void FileEventImpl::assignEvents(uint32_t events, event_base* base) { ASSERT(base != nullptr); + enabled_events_ = events; event_assign( &raw_event_, base, fd_, - EV_PERSIST | (trigger_ == FileTriggerType::Level ? 0 : EV_ET) | + EV_PERSIST | (trigger_ == FileTriggerType::Edge ? EV_ET : 0) | (events & FileReadyType::Read ? EV_READ : 0) | (events & FileReadyType::Write ? EV_WRITE : 0) | (events & FileReadyType::Closed ? EV_CLOSED : 0), @@ -108,8 +80,18 @@ void FileEventImpl::assignEvents(uint32_t events, event_base* base) { this); } +void FileEventImpl::updateEvents(uint32_t events) { + if (events == enabled_events_) { + return; + } + auto* base = event_get_base(&raw_event_); + event_del(&raw_event_); + assignEvents(events, base); + event_add(&raw_event_, nullptr); +} + void FileEventImpl::setEnabled(uint32_t events) { - if (activate_fd_events_next_event_loop_ && injected_activation_events_ != 0) { + if (injected_activation_events_ != 0) { // Clear pending events on updates to the fd event mask to avoid delivering events that are no // longer relevant. Updating the event mask will reset the fd edge trigger state so the proxy // will be able to determine the fd read/write state without need for the injected activation @@ -117,19 +99,62 @@ void FileEventImpl::setEnabled(uint32_t events) { injected_activation_events_ = 0; activation_cb_->cancel(); } + updateEvents(events); +} - auto* base = event_get_base(&raw_event_); - event_del(&raw_event_); - assignEvents(events, base); - event_add(&raw_event_, nullptr); +void FileEventImpl::unregisterEventIfEmulatedEdge(uint32_t event) { + // This constexpr if allows the compiler to optimize away the function on POSIX + if constexpr (PlatformDefaultTriggerType == FileTriggerType::EmulatedEdge) { + ASSERT((event & (FileReadyType::Read | FileReadyType::Write)) == event); + if (trigger_ == FileTriggerType::EmulatedEdge) { + auto new_event_mask = enabled_events_ & ~event; + updateEvents(new_event_mask); + } + } +} + +void FileEventImpl::registerEventIfEmulatedEdge(uint32_t event) { + // This constexpr if allows the compiler to optimize away the function on POSIX + if constexpr (PlatformDefaultTriggerType == FileTriggerType::EmulatedEdge) { + ASSERT((event & (FileReadyType::Read | FileReadyType::Write)) == event); + if (trigger_ == FileTriggerType::EmulatedEdge) { + auto new_event_mask = enabled_events_ | event; + if (event & FileReadyType::Read && (enabled_events_ & FileReadyType::Closed)) { + // We never ask for both early close and read at the same time. + new_event_mask = new_event_mask & ~FileReadyType::Read; + } + updateEvents(new_event_mask); + } + } } void FileEventImpl::mergeInjectedEventsAndRunCb(uint32_t events) { - if (activate_fd_events_next_event_loop_ && injected_activation_events_ != 0) { + if (injected_activation_events_ != 0) { + // TODO(antoniovicente) remove this adjustment to activation events once ConnectionImpl can + // handle Read and Close events delivered together. + if constexpr (PlatformDefaultTriggerType == FileTriggerType::EmulatedEdge) { + if (events & FileReadyType::Closed && injected_activation_events_ & FileReadyType::Read) { + // We never ask for both early close and read at the same time. If close is requested + // keep that instead. + injected_activation_events_ = injected_activation_events_ & ~FileReadyType::Read; + } + } + events |= injected_activation_events_; injected_activation_events_ = 0; activation_cb_->cancel(); } + + // TODO(davinci26): This can be optimized further in (w)epoll backends using the `EPOLLONESHOT` + // flag. With this flag `EPOLLIN`/`EPOLLOUT` are automatically disabled when the event is + // activated. + if constexpr (PlatformDefaultTriggerType == FileTriggerType::EmulatedEdge) { + if (trigger_ == FileTriggerType::EmulatedEdge) { + unregisterEventIfEmulatedEdge(events & + (Event::FileReadyType::Write | Event::FileReadyType::Read)); + } + } + cb_(events); } diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index cc3e505d788bb..dabfadd1b6910 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -22,24 +22,25 @@ class FileEventImpl : public FileEvent, ImplBase { // Event::FileEvent void activate(uint32_t events) override; void setEnabled(uint32_t events) override; + void unregisterEventIfEmulatedEdge(uint32_t event) override; + void registerEventIfEmulatedEdge(uint32_t event) override; private: void assignEvents(uint32_t events, event_base* base); void mergeInjectedEventsAndRunCb(uint32_t events); + void updateEvents(uint32_t events); FileReadyCb cb_; os_fd_t fd_; FileTriggerType trigger_; + // Enabled events for this fd. + uint32_t enabled_events_; // Injected FileReadyType events that were scheduled by recent calls to activate() and are pending // delivery. uint32_t injected_activation_events_{}; // Used to schedule delayed event activation. Armed iff pending_activation_events_ != 0. SchedulableCallbackPtr activation_cb_; - // Latched "envoy.reloadable_features.activate_fds_next_event_loop" runtime feature. If true, fd - // events scheduled via activate are evaluated in the next iteration of the event loop after - // polling and activating new fd events. - const bool activate_fd_events_next_event_loop_; }; } // namespace Event } // namespace Envoy diff --git a/source/common/event/libevent_scheduler.h b/source/common/event/libevent_scheduler.h index ab076cbabd887..d9aeecd387ad9 100644 --- a/source/common/event/libevent_scheduler.h +++ b/source/common/event/libevent_scheduler.h @@ -43,8 +43,6 @@ namespace Event { // The same mechanism implements both of these operations, so they are invoked as a group. // - Event::SchedulableCallback::scheduleCallbackCurrentIteration(). Each of these callbacks is // scheduled and invoked independently. -// - Event::FileEvent::activate() if "envoy.reloadable_features.activate_fds_next_event_loop" -// runtime feature is disabled. // - Event::Timer::enableTimer(0) if "envoy.reloadable_features.activate_timers_next_event_loop" // runtime feature is disabled. // @@ -110,10 +108,9 @@ class LibeventScheduler : public Scheduler, public CallbackScheduler { static constexpr int flagsBasedOnEventType() { if constexpr (Event::PlatformDefaultTriggerType == FileTriggerType::Level) { - // On Windows, EVLOOP_NONBLOCK will cause the libevent event_base_loop to run forever. - // This is because libevent only supports level triggering on Windows, and so the write - // event callbacks will trigger every time through the loop. Adding EVLOOP_ONCE ensures the - // loop will run at most once + // With level events, EVLOOP_NONBLOCK will cause the libevent event_base_loop to run + // forever. This is because the write event callbacks will trigger every time through the + // loop. Adding EVLOOP_ONCE ensures the loop will run at most once return EVLOOP_NONBLOCK | EVLOOP_ONCE; } return EVLOOP_NONBLOCK; diff --git a/source/common/grpc/async_client_manager_impl.cc b/source/common/grpc/async_client_manager_impl.cc index dc039473395cc..5f809755f89d1 100644 --- a/source/common/grpc/async_client_manager_impl.cc +++ b/source/common/grpc/async_client_manager_impl.cc @@ -21,9 +21,9 @@ AsyncClientFactoryImpl::AsyncClientFactoryImpl(Upstream::ClusterManager& cm, } const std::string& cluster_name = config.envoy_grpc().cluster_name(); - auto clusters = cm_.clusters(); - const auto& it = clusters.find(cluster_name); - if (it == clusters.end()) { + auto all_clusters = cm_.clusters(); + const auto& it = all_clusters.active_clusters_.find(cluster_name); + if (it == all_clusters.active_clusters_.end()) { throw EnvoyException(fmt::format("Unknown gRPC client cluster '{}'", cluster_name)); } if (it->second.get().info()->addedViaApi()) { diff --git a/source/common/http/codec_client.cc b/source/common/http/codec_client.cc index 0da14ae6992ae..3c5c16aed654c 100644 --- a/source/common/http/codec_client.cc +++ b/source/common/http/codec_client.cc @@ -105,8 +105,11 @@ void CodecClient::onEvent(Network::ConnectionEvent event) { } } -void CodecClient::responseDecodeComplete(ActiveRequest& request) { +void CodecClient::responsePreDecodeComplete(ActiveRequest& request) { ENVOY_CONN_LOG(debug, "response complete", *connection_); + if (codec_client_callbacks_) { + codec_client_callbacks_->onStreamPreDecodeComplete(); + } deleteRequest(request); // HTTP/2 can send us a reset after a complete response if the request was not complete. Users @@ -138,6 +141,10 @@ void CodecClient::onData(Buffer::Instance& data) { host_->cluster().stats().upstream_cx_protocol_error_.inc(); } } + + // All data should be consumed at this point if the connection remains open. + ASSERT(data.length() == 0 || connection_->state() != Network::Connection::State::Open, + absl::StrCat("extraneous bytes after response complete: ", data.length())); } CodecClientProd::CodecClientProd(Type type, Network::ClientConnectionPtr&& connection, diff --git a/source/common/http/codec_client.h b/source/common/http/codec_client.h index 5d74eb114ec88..2e14b112a6851 100644 --- a/source/common/http/codec_client.h +++ b/source/common/http/codec_client.h @@ -28,6 +28,9 @@ class CodecClientCallbacks { public: virtual ~CodecClientCallbacks() = default; + // Called in onPreDecodeComplete + virtual void onStreamPreDecodeComplete() {} + /** * Called every time an owned stream is destroyed, whether complete or not. */ @@ -63,6 +66,11 @@ class CodecClient : Logger::Loggable, connection_->addConnectionCallbacks(cb); } + /** + * Return if half-close semantics are enabled on the underlying connection. + */ + bool isHalfCloseEnabled() { return connection_->isHalfCloseEnabled(); } + /** * Close the underlying network connection. This is immediate and will not attempt to flush any * pending write data. @@ -173,8 +181,14 @@ class CodecClient : Logger::Loggable, CodecReadFilter(CodecClient& parent) : parent_(parent) {} // Network::ReadFilter - Network::FilterStatus onData(Buffer::Instance& data, bool) override { + Network::FilterStatus onData(Buffer::Instance& data, bool end_stream) override { parent_.onData(data); + if (end_stream && parent_.isHalfCloseEnabled()) { + // Note that this results in the connection closed as if it was closed + // locally, it would be more correct to convey the end stream to the + // response decoder, but it would require some refactoring. + parent_.close(); + } return Network::FilterStatus::StopIteration; } @@ -201,7 +215,7 @@ class CodecClient : Logger::Loggable, void onBelowWriteBufferLowWatermark() override {} // StreamDecoderWrapper - void onPreDecodeComplete() override { parent_.responseDecodeComplete(*this); } + void onPreDecodeComplete() override { parent_.responsePreDecodeComplete(*this); } void onDecodeComplete() override {} RequestEncoder* encoder_{}; @@ -214,7 +228,7 @@ class CodecClient : Logger::Loggable, * Called when a response finishes decoding. This is called *before* forwarding on to the * wrapped decoder. */ - void responseDecodeComplete(ActiveRequest& request); + void responsePreDecodeComplete(ActiveRequest& request); void deleteRequest(ActiveRequest& request); void onReset(ActiveRequest& request, StreamResetReason reason); diff --git a/source/common/http/conn_pool_base.cc b/source/common/http/conn_pool_base.cc index 4fbd6cbd588bf..ff577eff49016 100644 --- a/source/common/http/conn_pool_base.cc +++ b/source/common/http/conn_pool_base.cc @@ -50,10 +50,11 @@ HttpConnPoolImplBase::HttpConnPoolImplBase( Upstream::HostConstSharedPtr host, Upstream::ResourcePriority priority, Event::Dispatcher& dispatcher, const Network::ConnectionSocket::OptionsSharedPtr& options, const Network::TransportSocketOptionsSharedPtr& transport_socket_options, - Random::RandomGenerator& random_generator, std::vector protocols) + Random::RandomGenerator& random_generator, Upstream::ClusterConnectivityState& state, + std::vector protocols) : Envoy::ConnectionPool::ConnPoolImplBase( host, priority, dispatcher, options, - wrapTransportSocketOptions(transport_socket_options, protocols)), + wrapTransportSocketOptions(transport_socket_options, protocols), state), random_generator_(random_generator) { ASSERT(!protocols.empty()); // TODO(alyssawilk) the protocol function should probably be an optional and @@ -73,7 +74,7 @@ HttpConnPoolImplBase::newStream(Http::ResponseDecoder& response_decoder, } bool HttpConnPoolImplBase::hasActiveConnections() const { - return (!pending_streams_.empty() || (num_active_streams_ > 0)); + return (hasPendingStreams() || (hasActiveStreams())); } ConnectionPool::Cancellable* @@ -83,8 +84,7 @@ HttpConnPoolImplBase::newPendingStream(Envoy::ConnectionPool::AttachContext& con ENVOY_LOG(debug, "queueing stream due to no available connections"); Envoy::ConnectionPool::PendingStreamPtr pending_stream( new HttpPendingStream(*this, decoder, callbacks)); - LinkedList::moveIntoList(std::move(pending_stream), pending_streams_); - return pending_streams_.front().get(); + return addPendingStream(std::move(pending_stream)); } void HttpConnPoolImplBase::onPoolReady(Envoy::ConnectionPool::ActiveClient& client, diff --git a/source/common/http/conn_pool_base.h b/source/common/http/conn_pool_base.h index aad2d57ee3f12..29c48af1127d7 100644 --- a/source/common/http/conn_pool_base.h +++ b/source/common/http/conn_pool_base.h @@ -51,6 +51,7 @@ class HttpConnPoolImplBase : public Envoy::ConnectionPool::ConnPoolImplBase, const Network::ConnectionSocket::OptionsSharedPtr& options, const Network::TransportSocketOptionsSharedPtr& transport_socket_options, Random::RandomGenerator& random_generator, + Upstream::ClusterConnectivityState& state, std::vector protocol); ~HttpConnPoolImplBase() override; @@ -90,8 +91,8 @@ class HttpConnPoolImplBase : public Envoy::ConnectionPool::ConnPoolImplBase, // An implementation of Envoy::ConnectionPool::ActiveClient for HTTP/1.1 and HTTP/2 class ActiveClient : public Envoy::ConnectionPool::ActiveClient { public: - ActiveClient(HttpConnPoolImplBase& parent, uint64_t lifetime_stream_limit, - uint64_t concurrent_stream_limit) + ActiveClient(HttpConnPoolImplBase& parent, uint32_t lifetime_stream_limit, + uint32_t concurrent_stream_limit) : Envoy::ConnectionPool::ActiveClient(parent, lifetime_stream_limit, concurrent_stream_limit) { // The static cast makes sure we call the base class host() and not @@ -119,7 +120,7 @@ class ActiveClient : public Envoy::ConnectionPool::ActiveClient { void onEvent(Network::ConnectionEvent event) override { parent_.onConnectionEvent(*this, codec_client_->connectionFailureReason(), event); } - size_t numActiveStreams() const override { return codec_client_->numActiveRequests(); } + uint32_t numActiveStreams() const override { return codec_client_->numActiveRequests(); } uint64_t id() const override { return codec_client_->id(); } HttpConnPoolImplBase& parent() { return *static_cast(&parent_); } @@ -139,10 +140,11 @@ class FixedHttpConnPoolImpl : public HttpConnPoolImplBase { Event::Dispatcher& dispatcher, const Network::ConnectionSocket::OptionsSharedPtr& options, const Network::TransportSocketOptionsSharedPtr& transport_socket_options, - Random::RandomGenerator& random_generator, CreateClientFn client_fn, + Random::RandomGenerator& random_generator, + Upstream::ClusterConnectivityState& state, CreateClientFn client_fn, CreateCodecFn codec_fn, std::vector protocol) : HttpConnPoolImplBase(host, priority, dispatcher, options, transport_socket_options, - random_generator, protocol), + random_generator, state, protocol), codec_fn_(codec_fn), client_fn_(client_fn) {} CodecClientPtr createCodecClient(Upstream::Host::CreateConnectionData& data) override { diff --git a/source/common/http/http1/codec_impl.cc b/source/common/http/http1/codec_impl.cc index 6a803cca1e6cb..466dfd8879989 100644 --- a/source/common/http/http1/codec_impl.cc +++ b/source/common/http/http1/codec_impl.cc @@ -77,8 +77,8 @@ const std::string StreamEncoderImpl::LAST_CHUNK = "0\r\n"; StreamEncoderImpl::StreamEncoderImpl(ConnectionImpl& connection, HeaderKeyFormatter* header_key_formatter) : connection_(connection), disable_chunk_encoding_(false), chunk_encoding_(true), - is_response_to_head_request_(false), is_response_to_connect_request_(false), - header_key_formatter_(header_key_formatter) { + connect_request_(false), is_response_to_head_request_(false), + is_response_to_connect_request_(false), header_key_formatter_(header_key_formatter) { if (connection_.connection().aboveHighWatermark()) { runHighWatermarkCallbacks(); } @@ -261,6 +261,10 @@ void StreamEncoderImpl::endEncode() { connection_.flushOutput(true); connection_.onEncodeComplete(); + // With CONNECT, half-closing the connection is used to signal end stream. + if (connect_request_) { + connection_.connection().close(Network::ConnectionCloseType::FlushWriteAndDelay); + } } void ServerConnectionImpl::maybeAddSentinelBufferFragment(Buffer::WatermarkBuffer& output_buffer) { @@ -380,6 +384,7 @@ Status RequestEncoderImpl::encodeHeaders(const RequestHeaderMap& headers, bool e head_request_ = true; } else if (method->value() == Headers::get().MethodValues.Connect) { disableChunkEncoding(); + connection_.connection().enableHalfClose(true); connect_request_ = true; } if (Utility::isUpgrade(headers)) { @@ -552,6 +557,16 @@ Http::Status ConnectionImpl::dispatch(Buffer::Instance& data) { [&](Buffer::Instance& data) -> Http::Status { return innerDispatch(data); }, data); } +Http::Status ClientConnectionImpl::dispatch(Buffer::Instance& data) { + Http::Status status = ConnectionImpl::dispatch(data); + if (status.ok() && data.length() > 0) { + // The HTTP/1.1 codec pauses dispatch after a single response is complete. Extraneous data + // after a response is complete indicates an error. + return codecProtocolError("http/1.1 protocol error: extraneous data after response complete"); + } + return status; +} + Http::Status ConnectionImpl::innerDispatch(Buffer::Instance& data) { ENVOY_CONN_LOG(trace, "parsing {} bytes", connection_, data.length()); // Make sure that dispatching_ is set to false after dispatching, even when @@ -1285,6 +1300,9 @@ void ClientConnectionImpl::onMessageComplete() { pending_response_.reset(); headers_or_trailers_.emplace(nullptr); } + + // Pause the parser after a response is complete. Any remaining data indicates an error. + http_parser_pause(&parser_, 1); } void ClientConnectionImpl::onResetStream(StreamResetReason reason) { diff --git a/source/common/http/http1/codec_impl.h b/source/common/http/http1/codec_impl.h index 867cd603f57ad..5e38b6c243657 100644 --- a/source/common/http/http1/codec_impl.h +++ b/source/common/http/http1/codec_impl.h @@ -87,6 +87,7 @@ class StreamEncoderImpl : public virtual StreamEncoder, uint32_t read_disable_calls_{}; bool disable_chunk_encoding_ : 1; bool chunk_encoding_ : 1; + bool connect_request_ : 1; bool is_response_to_head_request_ : 1; bool is_response_to_connect_request_ : 1; @@ -162,7 +163,6 @@ class RequestEncoderImpl : public StreamEncoderImpl, public RequestEncoder { private: bool upgrade_request_{}; bool head_request_{}; - bool connect_request_{}; }; /** @@ -580,6 +580,7 @@ class ClientConnectionImpl : public ClientConnection, public ConnectionImpl { bool cannotHaveBody(); // ConnectionImpl + Http::Status dispatch(Buffer::Instance& data) override; void onEncodeComplete() override {} Status onMessageBegin() override { return okStatus(); } Status onUrl(const char*, size_t) override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } diff --git a/source/common/http/http1/codec_impl_legacy.cc b/source/common/http/http1/codec_impl_legacy.cc index 474fd7ce1b0ca..ff5fdee9eb206 100644 --- a/source/common/http/http1/codec_impl_legacy.cc +++ b/source/common/http/http1/codec_impl_legacy.cc @@ -78,8 +78,8 @@ const std::string StreamEncoderImpl::LAST_CHUNK = "0\r\n"; StreamEncoderImpl::StreamEncoderImpl(ConnectionImpl& connection, HeaderKeyFormatter* header_key_formatter) : connection_(connection), disable_chunk_encoding_(false), chunk_encoding_(true), - is_response_to_head_request_(false), is_response_to_connect_request_(false), - header_key_formatter_(header_key_formatter) { + connect_request_(false), is_response_to_head_request_(false), + is_response_to_connect_request_(false), header_key_formatter_(header_key_formatter) { if (connection_.connection().aboveHighWatermark()) { runHighWatermarkCallbacks(); } @@ -262,6 +262,10 @@ void StreamEncoderImpl::endEncode() { connection_.flushOutput(true); connection_.onEncodeComplete(); + // With CONNECT half-closing the connection is used to signal end stream. + if (connect_request_) { + connection_.connection().close(Network::ConnectionCloseType::FlushWriteAndDelay); + } } void ServerConnectionImpl::maybeAddSentinelBufferFragment(Buffer::WatermarkBuffer& output_buffer) { @@ -381,6 +385,7 @@ Status RequestEncoderImpl::encodeHeaders(const RequestHeaderMap& headers, bool e head_request_ = true; } else if (method->value() == Headers::get().MethodValues.Connect) { disableChunkEncoding(); + connection_.connection().enableHalfClose(true); connect_request_ = true; } if (Utility::isUpgrade(headers)) { @@ -526,6 +531,16 @@ Http::Status ConnectionImpl::dispatch(Buffer::Instance& data) { [&](Buffer::Instance& data) -> Http::Status { return innerDispatch(data); }, data); } +Http::Status ClientConnectionImpl::dispatch(Buffer::Instance& data) { + Http::Status status = ConnectionImpl::dispatch(data); + if (status.ok() && data.length() > 0) { + // The HTTP/1.1 codec pauses dispatch after a single response is complete. Extraneous data + // after a response is complete indicates an error. + return codecProtocolError("http/1.1 protocol error: extraneous data after response complete"); + } + return status; +} + Http::Status ConnectionImpl::innerDispatch(Buffer::Instance& data) { ENVOY_CONN_LOG(trace, "parsing {} bytes", connection_, data.length()); ASSERT(buffered_body_.length() == 0); diff --git a/source/common/http/http1/codec_impl_legacy.h b/source/common/http/http1/codec_impl_legacy.h index 48382473f0bdd..b68e069dd0c4b 100644 --- a/source/common/http/http1/codec_impl_legacy.h +++ b/source/common/http/http1/codec_impl_legacy.h @@ -89,6 +89,7 @@ class StreamEncoderImpl : public virtual StreamEncoder, uint32_t read_disable_calls_{}; bool disable_chunk_encoding_ : 1; bool chunk_encoding_ : 1; + bool connect_request_ : 1; bool is_response_to_head_request_ : 1; bool is_response_to_connect_request_ : 1; @@ -166,7 +167,6 @@ class RequestEncoderImpl : public StreamEncoderImpl, public RequestEncoder { private: bool upgrade_request_{}; bool head_request_{}; - bool connect_request_{}; }; /** @@ -555,6 +555,7 @@ class ClientConnectionImpl : public ClientConnection, public ConnectionImpl { bool cannotHaveBody(); // ConnectionImpl + Http::Status dispatch(Buffer::Instance& data) override; void onEncodeComplete() override {} void onMessageBegin() override {} void onUrl(const char*, size_t) override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } diff --git a/source/common/http/http1/conn_pool.cc b/source/common/http/http1/conn_pool.cc index c37e2f8e8635f..cc69ab976c0e1 100644 --- a/source/common/http/http1/conn_pool.cc +++ b/source/common/http/http1/conn_pool.cc @@ -66,7 +66,6 @@ void ActiveClient::StreamWrapper::decodeHeaders(ResponseHeaderMapPtr&& headers, void ActiveClient::StreamWrapper::onDecodeComplete() { ASSERT(!decode_complete_); decode_complete_ = encode_complete_; - ENVOY_CONN_LOG(debug, "response complete", *parent_.codec_client_); if (!parent_.stream_wrapper_->encode_complete_) { @@ -110,10 +109,11 @@ ConnectionPool::InstancePtr allocateConnPool(Event::Dispatcher& dispatcher, Random::RandomGenerator& random_generator, Upstream::HostConstSharedPtr host, Upstream::ResourcePriority priority, const Network::ConnectionSocket::OptionsSharedPtr& options, - const Network::TransportSocketOptionsSharedPtr& transport_socket_options) { + const Network::TransportSocketOptionsSharedPtr& transport_socket_options, + Upstream::ClusterConnectivityState& state) { return std::make_unique( std::move(host), std::move(priority), dispatcher, options, transport_socket_options, - random_generator, + random_generator, state, [](HttpConnPoolImplBase* pool) { return std::make_unique(*pool); }, [](Upstream::Host::CreateConnectionData& data, HttpConnPoolImplBase* pool) { CodecClientPtr codec{new CodecClientProd( diff --git a/source/common/http/http1/conn_pool.h b/source/common/http/http1/conn_pool.h index 5b37d855e52f2..e8c5b07055879 100644 --- a/source/common/http/http1/conn_pool.h +++ b/source/common/http/http1/conn_pool.h @@ -22,6 +22,14 @@ class ActiveClient : public Envoy::Http::ActiveClient { bool closingWithIncompleteStream() const override; RequestEncoder& newStreamEncoder(ResponseDecoder& response_decoder) override; + uint32_t numActiveStreams() const override { + // Override the parent class using the codec for numActiveStreams. + // Unfortunately for the HTTP/1 codec, the stream is destroyed before decode + // is complete, and we must make sure the connection pool does not observe available + // capacity and assign a new stream before decode is complete. + return stream_wrapper_.get() ? 1 : 0; + } + struct StreamWrapper : public RequestEncoderWrapper, public ResponseDecoderWrapper, public StreamCallbacks, @@ -42,10 +50,13 @@ class ActiveClient : public Envoy::Http::ActiveClient { void onAboveWriteBufferHighWatermark() override {} void onBelowWriteBufferLowWatermark() override {} + void onStreamDestroy(); + ActiveClient& parent_; + bool stream_incomplete_{}; bool encode_complete_{}; - bool close_connection_{}; bool decode_complete_{}; + bool close_connection_{}; }; using StreamWrapperPtr = std::unique_ptr; @@ -56,7 +67,8 @@ ConnectionPool::InstancePtr allocateConnPool(Event::Dispatcher& dispatcher, Random::RandomGenerator& random_generator, Upstream::HostConstSharedPtr host, Upstream::ResourcePriority priority, const Network::ConnectionSocket::OptionsSharedPtr& options, - const Network::TransportSocketOptionsSharedPtr& transport_socket_options); + const Network::TransportSocketOptionsSharedPtr& transport_socket_options, + Upstream::ClusterConnectivityState& state); } // namespace Http1 } // namespace Http diff --git a/source/common/http/http2/codec_impl.cc b/source/common/http/http2/codec_impl.cc index fc5cc2349171d..74a565b279164 100644 --- a/source/common/http/http2/codec_impl.cc +++ b/source/common/http/http2/codec_impl.cc @@ -1007,7 +1007,7 @@ int ConnectionImpl::onMetadataReceived(int32_t stream_id, const uint8_t* data, s ENVOY_CONN_LOG(trace, "recv {} bytes METADATA", connection_, len); StreamImpl* stream = getStream(stream_id); - if (!stream) { + if (!stream || stream->remote_end_stream_) { return 0; } @@ -1020,7 +1020,7 @@ int ConnectionImpl::onMetadataFrameComplete(int32_t stream_id, bool end_metadata stream_id, end_metadata); StreamImpl* stream = getStream(stream_id); - if (stream == nullptr) { + if (!stream || stream->remote_end_stream_) { return 0; } diff --git a/source/common/http/http2/codec_impl_legacy.cc b/source/common/http/http2/codec_impl_legacy.cc index 75719d625e01d..794885e475262 100644 --- a/source/common/http/http2/codec_impl_legacy.cc +++ b/source/common/http/http2/codec_impl_legacy.cc @@ -993,7 +993,7 @@ int ConnectionImpl::onMetadataReceived(int32_t stream_id, const uint8_t* data, s ENVOY_CONN_LOG(trace, "recv {} bytes METADATA", connection_, len); StreamImpl* stream = getStream(stream_id); - if (!stream) { + if (!stream || stream->remote_end_stream_) { return 0; } @@ -1006,7 +1006,7 @@ int ConnectionImpl::onMetadataFrameComplete(int32_t stream_id, bool end_metadata stream_id, end_metadata); StreamImpl* stream = getStream(stream_id); - if (stream == nullptr) { + if (!stream || stream->remote_end_stream_) { return 0; } diff --git a/source/common/http/http2/conn_pool.cc b/source/common/http/http2/conn_pool.cc index c9c901f466d39..492ebb62e4f62 100644 --- a/source/common/http/http2/conn_pool.cc +++ b/source/common/http/http2/conn_pool.cc @@ -74,9 +74,10 @@ ConnectionPool::InstancePtr allocateConnPool(Event::Dispatcher& dispatcher, Random::RandomGenerator& random_generator, Upstream::HostConstSharedPtr host, Upstream::ResourcePriority priority, const Network::ConnectionSocket::OptionsSharedPtr& options, - const Network::TransportSocketOptionsSharedPtr& transport_socket_options) { + const Network::TransportSocketOptionsSharedPtr& transport_socket_options, + Upstream::ClusterConnectivityState& state) { return std::make_unique( - host, priority, dispatcher, options, transport_socket_options, random_generator, + host, priority, dispatcher, options, transport_socket_options, random_generator, state, [](HttpConnPoolImplBase* pool) { return std::make_unique(*pool); }, [](Upstream::Host::CreateConnectionData& data, HttpConnPoolImplBase* pool) { CodecClientPtr codec{new CodecClientProd( diff --git a/source/common/http/http2/conn_pool.h b/source/common/http/http2/conn_pool.h index cc5c335e38bef..2a277a55ea6c8 100644 --- a/source/common/http/http2/conn_pool.h +++ b/source/common/http/http2/conn_pool.h @@ -39,7 +39,8 @@ ConnectionPool::InstancePtr allocateConnPool(Event::Dispatcher& dispatcher, Random::RandomGenerator& random_generator, Upstream::HostConstSharedPtr host, Upstream::ResourcePriority priority, const Network::ConnectionSocket::OptionsSharedPtr& options, - const Network::TransportSocketOptionsSharedPtr& transport_socket_options); + const Network::TransportSocketOptionsSharedPtr& transport_socket_options, + Upstream::ClusterConnectivityState& state); } // namespace Http2 } // namespace Http diff --git a/source/common/network/connection_impl.cc b/source/common/network/connection_impl.cc index 1a265cf10287b..4c52ee2fc516f 100644 --- a/source/common/network/connection_impl.cc +++ b/source/common/network/connection_impl.cc @@ -375,6 +375,7 @@ void ConnectionImpl::readDisable(bool disable) { } void ConnectionImpl::raiseEvent(ConnectionEvent event) { + ENVOY_CONN_LOG(trace, "raising connection event {}", *this, event); ConnectionImplBase::raiseConnectionEvent(event); // We may have pending data in the write buffer on transport handshake // completion, which may also have completed in the context of onReadReady(), diff --git a/source/common/network/connection_impl.h b/source/common/network/connection_impl.h index 0203754142658..3ede8c59839b4 100644 --- a/source/common/network/connection_impl.h +++ b/source/common/network/connection_impl.h @@ -61,6 +61,7 @@ class ConnectionImpl : public ConnectionImplBase, public TransportSocketCallback // Network::Connection void addBytesSentCallback(BytesSentCb cb) override; void enableHalfClose(bool enabled) override; + bool isHalfCloseEnabled() override { return enable_half_close_; } void close(ConnectionCloseType type) final; std::string nextProtocol() const override { return transport_socket_->protocol(); } void noDelay(bool enable) override; diff --git a/source/common/network/io_socket_handle_impl.cc b/source/common/network/io_socket_handle_impl.cc index fb1c2e120ec58..508ce6400aac4 100644 --- a/source/common/network/io_socket_handle_impl.cc +++ b/source/common/network/io_socket_handle_impl.cc @@ -48,6 +48,16 @@ in_addr addressFromMessage(const cmsghdr& cmsg) { #endif } +constexpr int messageTruncatedOption() { +#if defined(__APPLE__) + // OSX does not support passing `MSG_TRUNC` to recvmsg and recvmmsg. This does not effect + // functionality and it primarily used for logging. + return 0; +#else + return MSG_TRUNC; +#endif +} + } // namespace namespace Network { @@ -84,8 +94,18 @@ Api::IoCallUint64Result IoSocketHandleImpl::readv(uint64_t max_length, Buffer::R num_bytes_to_read += slice_length; } ASSERT(num_bytes_to_read <= max_length); - return sysCallResultToIoCallResult(Api::OsSysCallsSingleton::get().readv( + auto result = sysCallResultToIoCallResult(Api::OsSysCallsSingleton::get().readv( fd_, iov.begin(), static_cast(num_slices_to_read))); + + // Emulated edge events need to registered if the socket operation did not complete + // because the socket would block. + if constexpr (Event::PlatformDefaultTriggerType == Event::FileTriggerType::EmulatedEdge) { + // Some tests try to read without initializing the file_event. + if (result.wouldBlock() && file_event_) { + file_event_->registerEventIfEmulatedEdge(Event::FileReadyType::Read); + } + } + return result; } Api::IoCallUint64Result IoSocketHandleImpl::read(Buffer::Instance& buffer, uint64_t max_length) { @@ -103,6 +123,15 @@ Api::IoCallUint64Result IoSocketHandleImpl::read(Buffer::Instance& buffer, uint6 bytes_to_commit -= slices[i].len_; } buffer.commit(slices, num_slices); + + // Emulated edge events need to registered if the socket operation did not complete + // because the socket would block. + if constexpr (Event::PlatformDefaultTriggerType == Event::FileTriggerType::EmulatedEdge) { + // Some tests try to read without initializing the file_event. + if (result.wouldBlock() && file_event_) { + file_event_->registerEventIfEmulatedEdge(Event::FileReadyType::Read); + } + } return result; } @@ -120,8 +149,18 @@ Api::IoCallUint64Result IoSocketHandleImpl::writev(const Buffer::RawSlice* slice if (num_slices_to_write == 0) { return Api::ioCallUint64ResultNoError(); } - return sysCallResultToIoCallResult( + auto result = sysCallResultToIoCallResult( Api::OsSysCallsSingleton::get().writev(fd_, iov.begin(), num_slices_to_write)); + + // Emulated edge events need to registered if the socket operation did not complete + // because the socket would block. + if constexpr (Event::PlatformDefaultTriggerType == Event::FileTriggerType::EmulatedEdge) { + // Some tests try to write without initializing the file_event. + if (result.wouldBlock() && file_event_) { + file_event_->registerEventIfEmulatedEdge(Event::FileReadyType::Write); + } + } + return result; } Api::IoCallUint64Result IoSocketHandleImpl::write(Buffer::Instance& buffer) { @@ -131,6 +170,15 @@ Api::IoCallUint64Result IoSocketHandleImpl::write(Buffer::Instance& buffer) { if (result.ok() && result.rc_ > 0) { buffer.drain(static_cast(result.rc_)); } + + // Emulated edge events need to registered if the socket operation did not complete + // because the socket would block. + if constexpr (Event::PlatformDefaultTriggerType == Event::FileTriggerType::EmulatedEdge) { + // Some tests try to read without initializing the file_event. + if (result.wouldBlock() && file_event_) { + file_event_->registerEventIfEmulatedEdge(Event::FileReadyType::Write); + } + } return result; } @@ -168,7 +216,15 @@ Api::IoCallUint64Result IoSocketHandleImpl::sendmsg(const Buffer::RawSlice* slic message.msg_control = nullptr; message.msg_controllen = 0; const Api::SysCallSizeResult result = os_syscalls.sendmsg(fd_, &message, flags); - return sysCallResultToIoCallResult(result); + auto io_result = sysCallResultToIoCallResult(result); + // Emulated edge events need to registered if the socket operation did not complete + // because the socket would block. + if constexpr (Event::PlatformDefaultTriggerType == Event::FileTriggerType::EmulatedEdge) { + if (io_result.wouldBlock() && file_event_) { + file_event_->registerEventIfEmulatedEdge(Event::FileReadyType::Write); + } + } + return io_result; } else { const size_t space_v6 = CMSG_SPACE(sizeof(in6_pktinfo)); const size_t space_v4 = CMSG_SPACE(sizeof(in_pktinfo)); @@ -210,7 +266,15 @@ Api::IoCallUint64Result IoSocketHandleImpl::sendmsg(const Buffer::RawSlice* slic *(reinterpret_cast(pktinfo->ipi6_addr.s6_addr)) = self_ip->ipv6()->address(); } const Api::SysCallSizeResult result = os_syscalls.sendmsg(fd_, &message, flags); - return sysCallResultToIoCallResult(result); + auto io_result = sysCallResultToIoCallResult(result); + // Emulated edge events need to registered if the socket operation did not complete + // because the socket would block. + if constexpr (Event::PlatformDefaultTriggerType == Event::FileTriggerType::EmulatedEdge) { + if (io_result.wouldBlock() && file_event_) { + file_event_->registerEventIfEmulatedEdge(Event::FileReadyType::Write); + } + } + return io_result; } } @@ -296,8 +360,24 @@ Api::IoCallUint64Result IoSocketHandleImpl::recvmsg(Buffer::RawSlice* slices, hdr.msg_flags = 0; hdr.msg_control = cbuf.begin(); hdr.msg_controllen = cmsg_space_; - const Api::SysCallSizeResult result = Api::OsSysCallsSingleton::get().recvmsg(fd_, &hdr, 0); + Api::SysCallSizeResult result = + Api::OsSysCallsSingleton::get().recvmsg(fd_, &hdr, messageTruncatedOption()); if (result.rc_ < 0) { + auto io_result = sysCallResultToIoCallResult(result); + // Emulated edge events need to registered if the socket operation did not complete + // because the socket would block. + if constexpr (Event::PlatformDefaultTriggerType == Event::FileTriggerType::EmulatedEdge) { + if (io_result.wouldBlock() && file_event_) { + file_event_->registerEventIfEmulatedEdge(Event::FileReadyType::Read); + } + } + return io_result; + } + if ((hdr.msg_flags & MSG_TRUNC) != 0) { + ENVOY_LOG_MISC(debug, "Dropping truncated UDP packet with size: {}.", result.rc_); + result.rc_ = 0; + (*output.dropped_packets_)++; + output.msg_[0].truncated_and_dropped_ = true; return sysCallResultToIoCallResult(result); } @@ -324,7 +404,7 @@ Api::IoCallUint64Result IoSocketHandleImpl::recvmsg(Buffer::RawSlice* slices, if (output.dropped_packets_ != nullptr) { absl::optional maybe_dropped = maybeGetPacketsDroppedFromHeader(*cmsg); if (maybe_dropped) { - *output.dropped_packets_ = *maybe_dropped; + *output.dropped_packets_ += *maybe_dropped; continue; } } @@ -377,28 +457,37 @@ Api::IoCallUint64Result IoSocketHandleImpl::recvmmsg(RawSliceArrays& slices, uin // Set MSG_WAITFORONE so that recvmmsg will not waiting for // |num_packets_per_mmsg_call| packets to arrive before returning when the // socket is a blocking socket. - const Api::SysCallIntResult result = Api::OsSysCallsSingleton::get().recvmmsg( - fd_, mmsg_hdr.data(), num_packets_per_mmsg_call, MSG_TRUNC | MSG_WAITFORONE, nullptr); + const Api::SysCallIntResult result = + Api::OsSysCallsSingleton::get().recvmmsg(fd_, mmsg_hdr.data(), num_packets_per_mmsg_call, + messageTruncatedOption() | MSG_WAITFORONE, nullptr); if (result.rc_ <= 0) { - return sysCallResultToIoCallResult(result); + auto io_result = sysCallResultToIoCallResult(result); + // Emulated edge events need to registered if the socket operation did not complete + // because the socket would block. + if constexpr (Event::PlatformDefaultTriggerType == Event::FileTriggerType::EmulatedEdge) { + if (io_result.wouldBlock() && file_event_) { + file_event_->registerEventIfEmulatedEdge(Event::FileReadyType::Read); + } + } + return io_result; } int num_packets_read = result.rc_; for (int i = 0; i < num_packets_read; ++i) { - if (mmsg_hdr[i].msg_len == 0) { + msghdr& hdr = mmsg_hdr[i].msg_hdr; + if ((hdr.msg_flags & MSG_TRUNC) != 0) { + ENVOY_LOG_MISC(debug, "Dropping truncated UDP packet with size: {}.", mmsg_hdr[i].msg_len); + (*output.dropped_packets_)++; + output.msg_[i].truncated_and_dropped_ = true; continue; } - msghdr& hdr = mmsg_hdr[i].msg_hdr; + RELEASE_ASSERT((hdr.msg_flags & MSG_CTRUNC) == 0, fmt::format("Incorrectly set control message length: {}", hdr.msg_controllen)); RELEASE_ASSERT(hdr.msg_namelen > 0, fmt::format("Unable to get remote address from recvmmsg() for fd: {}", fd_)); - if ((hdr.msg_flags & MSG_TRUNC) != 0) { - ENVOY_LOG_MISC(warn, "Dropping truncated UDP packet with size: {}.", mmsg_hdr[i].msg_len); - continue; - } output.msg_[i].msg_len_ = mmsg_hdr[i].msg_len; // Get local and peer addresses for each packet. @@ -424,7 +513,7 @@ Api::IoCallUint64Result IoSocketHandleImpl::recvmmsg(RawSliceArrays& slices, uin for (cmsg = CMSG_FIRSTHDR(&hdr); cmsg != nullptr; cmsg = CMSG_NXTHDR(&hdr, cmsg)) { absl::optional maybe_dropped = maybeGetPacketsDroppedFromHeader(*cmsg); if (maybe_dropped) { - *output.dropped_packets_ = *maybe_dropped; + *output.dropped_packets_ += *maybe_dropped; } } } @@ -435,7 +524,15 @@ Api::IoCallUint64Result IoSocketHandleImpl::recvmmsg(RawSliceArrays& slices, uin Api::IoCallUint64Result IoSocketHandleImpl::recv(void* buffer, size_t length, int flags) { const Api::SysCallSizeResult result = Api::OsSysCallsSingleton::get().recv(fd_, buffer, length, flags); - return sysCallResultToIoCallResult(result); + auto io_result = sysCallResultToIoCallResult(result); + // Emulated edge events need to registered if the socket operation did not complete + // because the socket would block. + if constexpr (Event::PlatformDefaultTriggerType == Event::FileTriggerType::EmulatedEdge) { + if (io_result.wouldBlock() && file_event_) { + file_event_->registerEventIfEmulatedEdge(Event::FileReadyType::Read); + } + } + return io_result; } bool IoSocketHandleImpl::supportsMmsg() const { diff --git a/source/common/network/udp_listener_impl.h b/source/common/network/udp_listener_impl.h index 99db6dca4ac01..a6b2852b39904 100644 --- a/source/common/network/udp_listener_impl.h +++ b/source/common/network/udp_listener_impl.h @@ -24,8 +24,8 @@ class UdpListenerImpl : public BaseListenerImpl, public: UdpListenerImpl(Event::DispatcherImpl& dispatcher, SocketSharedPtr socket, UdpListenerCallbacks& cb, TimeSource& time_source); - ~UdpListenerImpl() override; + uint32_t packetsDropped() { return packets_dropped_; } // Network::Listener Interface void disable() override; diff --git a/source/common/network/utility.cc b/source/common/network/utility.cc index 426598ace9562..0574c040a1d16 100644 --- a/source/common/network/utility.cc +++ b/source/common/network/utility.cc @@ -629,6 +629,10 @@ Api::IoCallUint64Result Utility::readFromSocket(IoHandle& handle, uint64_t packets_read = result.rc_; ENVOY_LOG_MISC(trace, "recvmmsg read {} packets", packets_read); for (uint64_t i = 0; i < packets_read; ++i) { + if (output.msg_[i].truncated_and_dropped_) { + continue; + } + Buffer::RawSlice* slice = slices[i].data(); const uint64_t msg_len = output.msg_[i].msg_len_; ASSERT(msg_len <= slice->len_); @@ -651,7 +655,7 @@ Api::IoCallUint64Result Utility::readFromSocket(IoHandle& handle, Api::IoCallUint64Result result = receiveMessage(udp_packet_processor.maxPacketSize(), buffer, output, handle, local_address); - if (!result.ok()) { + if (!result.ok() || output.msg_[0].truncated_and_dropped_) { return result; } @@ -678,12 +682,6 @@ Api::IoErrorPtr Utility::readPacketsFromSocket(IoHandle& handle, return std::move(result.err_); } - if (result.rc_ == 0) { - // TODO(conqerAtapple): Is zero length packet interesting? If so add stats - // for it. Otherwise remove the warning log below. - ENVOY_LOG_MISC(trace, "received 0-length packet"); - } - if (packets_dropped != old_packets_dropped) { // The kernel tracks SO_RXQ_OVFL as a uint32 which can overflow to a smaller // value. So as long as this count differs from previously recorded value, diff --git a/source/common/runtime/runtime_features.cc b/source/common/runtime/runtime_features.cc index a961c25eaebbe..fd9907cbef752 100644 --- a/source/common/runtime/runtime_features.cc +++ b/source/common/runtime/runtime_features.cc @@ -57,7 +57,6 @@ constexpr const char* runtime_features[] = { // Begin alphabetically sorted section. "envoy.deprecated_features.allow_deprecated_extension_names", "envoy.reloadable_features.always_apply_route_header_rules", - "envoy.reloadable_features.activate_fds_next_event_loop", "envoy.reloadable_features.activate_timers_next_event_loop", "envoy.reloadable_features.allow_500_after_100", "envoy.reloadable_features.allow_prefetch", diff --git a/source/common/secret/BUILD b/source/common/secret/BUILD index f486c2f7ce8ed..84defb7ef88bd 100644 --- a/source/common/secret/BUILD +++ b/source/common/secret/BUILD @@ -58,6 +58,7 @@ envoy_cc_library( "//source/common/config:api_version_lib", "//source/common/config:subscription_base_interface", "//source/common/config:utility_lib", + "//source/common/config:watched_directory_lib", "//source/common/init:target_lib", "//source/common/protobuf:utility_lib", "//source/common/ssl:certificate_validation_context_config_impl_lib", diff --git a/source/common/secret/sds_api.cc b/source/common/secret/sds_api.cc index 163b91a13a316..3f319f03e638b 100644 --- a/source/common/secret/sds_api.cc +++ b/source/common/secret/sds_api.cc @@ -12,6 +12,10 @@ namespace Envoy { namespace Secret { +SdsApiStats SdsApi::generateStats(Stats::Scope& scope) { + return {ALL_SDS_API_STATS(POOL_COUNTER(scope))}; +} + SdsApi::SdsApi(envoy::config::core::v3::ConfigSource sds_config, absl::string_view sds_config_name, Config::SubscriptionFactory& subscription_factory, TimeSource& time_source, ProtobufMessage::ValidationVisitor& validation_visitor, Stats::Store& stats, @@ -19,16 +23,17 @@ SdsApi::SdsApi(envoy::config::core::v3::ConfigSource sds_config, absl::string_vi : Envoy::Config::SubscriptionBase( sds_config.resource_api_version(), validation_visitor, "name"), init_target_(fmt::format("SdsApi {}", sds_config_name), [this] { initialize(); }), - stats_(stats), sds_config_(std::move(sds_config)), sds_config_name_(sds_config_name), - secret_hash_(0), clean_up_(std::move(destructor_cb)), + dispatcher_(dispatcher), api_(api), + scope_(stats.createScope(absl::StrCat("sds.", sds_config_name, "."))), + sds_api_stats_(generateStats(*scope_)), sds_config_(std::move(sds_config)), + sds_config_name_(sds_config_name), secret_hash_(0), clean_up_(std::move(destructor_cb)), subscription_factory_(subscription_factory), time_source_(time_source), secret_data_{sds_config_name_, "uninitialized", - time_source_.systemTime()}, - dispatcher_(dispatcher), api_(api) { + time_source_.systemTime()} { const auto resource_name = getResourceName(); // This has to happen here (rather than in initialize()) as it can throw exceptions. subscription_ = subscription_factory_.subscriptionFromConfigSource( - sds_config_, Grpc::Common::typeUrl(resource_name), stats_, *this, resource_decoder_); + sds_config_, Grpc::Common::typeUrl(resource_name), *scope_, *this, resource_decoder_); // TODO(JimmyCYJ): Implement chained_init_manager, so that multiple init_manager // can be chained together to behave as one init_manager. In that way, we let @@ -36,6 +41,48 @@ SdsApi::SdsApi(envoy::config::core::v3::ConfigSource sds_config, absl::string_vi // each init manager has a chance to initialize its targets. } +void SdsApi::resolveDataSource(const FileContentMap& files, + envoy::config::core::v3::DataSource& data_source) { + if (data_source.specifier_case() == + envoy::config::core::v3::DataSource::SpecifierCase::kFilename) { + const std::string& content = files.at(data_source.filename()); + data_source.set_inline_bytes(content); + } +} + +void SdsApi::onWatchUpdate() { + // Filesystem reads and update callbacks can fail if the key material is missing or bad. We're not + // under an onConfigUpdate() context, so we need to catch these cases explicitly here. + try { + // Obtain a stable set of files. If a rotation happens while we're reading, + // then we need to try again. + uint64_t prev_hash = 0; + FileContentMap files = loadFiles(); + uint64_t next_hash = getHashForFiles(files); + const uint64_t MaxBoundedRetries = 5; + for (uint64_t bounded_retries = MaxBoundedRetries; + next_hash != prev_hash && bounded_retries > 0; --bounded_retries) { + files = loadFiles(); + prev_hash = next_hash; + next_hash = getHashForFiles(files); + } + if (next_hash != prev_hash) { + ENVOY_LOG_MISC( + warn, "Unable to atomically refresh secrets due to > {} non-atomic rotations observed", + MaxBoundedRetries); + } + const uint64_t new_hash = next_hash; + if (new_hash != files_hash_) { + resolveSecret(files); + update_callback_manager_.runCallbacks(); + files_hash_ = new_hash; + } + } catch (const EnvoyException& e) { + ENVOY_LOG_MISC(warn, fmt::format("Failed to reload certificates: {}", e.what())); + sds_api_stats_.key_rotation_failed_.inc(); + } +} + void SdsApi::onConfigUpdate(const std::vector& resources, const std::string& version_info) { validateUpdateSize(resources.size()); @@ -47,35 +94,40 @@ void SdsApi::onConfigUpdate(const std::vector& resou fmt::format("Unexpected SDS secret (expecting {}): {}", sds_config_name_, secret.name())); } - uint64_t new_hash = MessageUtil::hash(secret); + const uint64_t new_hash = MessageUtil::hash(secret); if (new_hash != secret_hash_) { validateConfig(secret); secret_hash_ = new_hash; setSecret(secret); + const auto files = loadFiles(); + files_hash_ = getHashForFiles(files); + resolveSecret(files); update_callback_manager_.runCallbacks(); - // List DataSources that refer to files - auto files = getDataSourceFilenames(); - if (!files.empty()) { - // Create new watch, also destroys the old watch if any. - watcher_ = dispatcher_.createFilesystemWatcher(); - files_hash_ = getHashForFiles(); - for (auto const& filename : files) { - // Watch for directory instead of file. This allows users to do atomic renames - // on directory level (e.g. Kubernetes secret update). - const auto result = api_.fileSystem().splitPathFromFilename(filename); - watcher_->addWatch(absl::StrCat(result.directory_, "/"), - Filesystem::Watcher::Events::MovedTo, [this](uint32_t) { - uint64_t new_hash = getHashForFiles(); - if (new_hash != files_hash_) { - update_callback_manager_.runCallbacks(); - files_hash_ = new_hash; - } - }); - } + auto* watched_directory = getWatchedDirectory(); + // Either we have a watched path and can defer the watch monitoring to a + // WatchedDirectory object, or we need to implement per-file watches in the else + // clause. + if (watched_directory != nullptr) { + watched_directory->setCallback([this]() { onWatchUpdate(); }); } else { - watcher_.reset(); // Destroy the old watch if any + // List DataSources that refer to files + auto files = getDataSourceFilenames(); + if (!files.empty()) { + // Create new watch, also destroys the old watch if any. + watcher_ = dispatcher_.createFilesystemWatcher(); + for (auto const& filename : files) { + // Watch for directory instead of file. This allows users to do atomic renames + // on directory level (e.g. Kubernetes secret update). + const auto result = api_.fileSystem().splitPathFromFilename(filename); + watcher_->addWatch(absl::StrCat(result.directory_, "/"), + Filesystem::Watcher::Events::MovedTo, + [this](uint32_t) { onWatchUpdate(); }); + } + } else { + watcher_.reset(); // Destroy the old watch if any + } } } secret_data_.last_updated_ = time_source_.systemTime(); @@ -114,36 +166,44 @@ void SdsApi::initialize() { SdsApi::SecretData SdsApi::secretData() { return secret_data_; } -uint64_t SdsApi::getHashForFiles() { - uint64_t hash = 0; +SdsApi::FileContentMap SdsApi::loadFiles() { + FileContentMap files; for (auto const& filename : getDataSourceFilenames()) { - hash = HashUtil::xxHash64(api_.fileSystem().fileReadToEnd(filename), hash); + files[filename] = api_.fileSystem().fileReadToEnd(filename); + } + return files; +} + +uint64_t SdsApi::getHashForFiles(const FileContentMap& files) { + uint64_t hash = 0; + for (const auto& it : files) { + hash = HashUtil::xxHash64(it.second, hash); } return hash; } std::vector TlsCertificateSdsApi::getDataSourceFilenames() { std::vector files; - if (tls_certificate_secrets_ && tls_certificate_secrets_->has_certificate_chain() && - tls_certificate_secrets_->certificate_chain().specifier_case() == + if (sds_tls_certificate_secrets_ && sds_tls_certificate_secrets_->has_certificate_chain() && + sds_tls_certificate_secrets_->certificate_chain().specifier_case() == envoy::config::core::v3::DataSource::SpecifierCase::kFilename) { - files.push_back(tls_certificate_secrets_->certificate_chain().filename()); + files.push_back(sds_tls_certificate_secrets_->certificate_chain().filename()); } - if (tls_certificate_secrets_ && tls_certificate_secrets_->has_private_key() && - tls_certificate_secrets_->private_key().specifier_case() == + if (sds_tls_certificate_secrets_ && sds_tls_certificate_secrets_->has_private_key() && + sds_tls_certificate_secrets_->private_key().specifier_case() == envoy::config::core::v3::DataSource::SpecifierCase::kFilename) { - files.push_back(tls_certificate_secrets_->private_key().filename()); + files.push_back(sds_tls_certificate_secrets_->private_key().filename()); } return files; } std::vector CertificateValidationContextSdsApi::getDataSourceFilenames() { std::vector files; - if (certificate_validation_context_secrets_ && - certificate_validation_context_secrets_->has_trusted_ca() && - certificate_validation_context_secrets_->trusted_ca().specifier_case() == + if (sds_certificate_validation_context_secrets_ && + sds_certificate_validation_context_secrets_->has_trusted_ca() && + sds_certificate_validation_context_secrets_->trusted_ca().specifier_case() == envoy::config::core::v3::DataSource::SpecifierCase::kFilename) { - files.push_back(certificate_validation_context_secrets_->trusted_ca().filename()); + files.push_back(sds_certificate_validation_context_secrets_->trusted_ca().filename()); } return files; } diff --git a/source/common/secret/sds_api.h b/source/common/secret/sds_api.h index 52b78a37a49ba..1c58feb6c5bc3 100644 --- a/source/common/secret/sds_api.h +++ b/source/common/secret/sds_api.h @@ -23,6 +23,7 @@ #include "common/common/cleanup.h" #include "common/config/subscription_base.h" #include "common/config/utility.h" +#include "common/config/watched_directory.h" #include "common/init/target_impl.h" #include "common/ssl/certificate_validation_context_config_impl.h" #include "common/ssl/tls_certificate_config_impl.h" @@ -30,6 +31,18 @@ namespace Envoy { namespace Secret { +/** + * All SDS API. @see stats_macros.h + */ +#define ALL_SDS_API_STATS(COUNTER) COUNTER(key_rotation_failed) + +/** + * Struct definition for all SDS API stats. @see stats_macros.h + */ +struct SdsApiStats { + ALL_SDS_API_STATS(GENERATE_COUNTER_STRUCT) +}; + /** * SDS API implementation that fetches secrets from SDS server via Subscription. */ @@ -60,8 +73,13 @@ class SdsApi : public Envoy::Config::SubscriptionBase< } protected: + // Ordered for hash stability. + using FileContentMap = std::map; + // Creates new secrets. virtual void setSecret(const envoy::extensions::transport_sockets::tls::v3::Secret&) PURE; + // Refresh secrets, e.g. re-resolve symlinks in secret paths. + virtual void resolveSecret(const FileContentMap& /*files*/){}; virtual void validateConfig(const envoy::extensions::transport_sockets::tls::v3::Secret&) PURE; Common::CallbackManager<> update_callback_manager_; @@ -74,15 +92,26 @@ class SdsApi : public Envoy::Config::SubscriptionBase< void onConfigUpdateFailed(Envoy::Config::ConfigUpdateFailureReason reason, const EnvoyException* e) override; virtual std::vector getDataSourceFilenames() PURE; + virtual Config::WatchedDirectory* getWatchedDirectory() PURE; + + void resolveDataSource(const FileContentMap& files, + envoy::config::core::v3::DataSource& data_source); Init::TargetImpl init_target_; + Event::Dispatcher& dispatcher_; + Api::Api& api_; private: void validateUpdateSize(int num_resources); void initialize(); - uint64_t getHashForFiles(); + FileContentMap loadFiles(); + uint64_t getHashForFiles(const FileContentMap& files); + // Invoked for filesystem watches on update. + void onWatchUpdate(); + SdsApiStats generateStats(Stats::Scope& scope); - Stats::Store& stats_; + Stats::ScopePtr scope_; + SdsApiStats sds_api_stats_; const envoy::config::core::v3::ConfigSource sds_config_; Config::SubscriptionPtr subscription_; @@ -94,8 +123,6 @@ class SdsApi : public Envoy::Config::SubscriptionBase< Config::SubscriptionFactory& subscription_factory_; TimeSource& time_source_; SecretData secret_data_; - Event::Dispatcher& dispatcher_; - Api::Api& api_; std::unique_ptr watcher_; bool registered_init_target_{false}; }; @@ -142,7 +169,7 @@ class TlsCertificateSdsApi : public SdsApi, public TlsCertificateConfigProvider // SecretProvider const envoy::extensions::transport_sockets::tls::v3::TlsCertificate* secret() const override { - return tls_certificate_secrets_.get(); + return resolved_tls_certificate_secrets_.get(); } Common::CallbackHandle* addValidationCallback( std::function) @@ -158,15 +185,37 @@ class TlsCertificateSdsApi : public SdsApi, public TlsCertificateConfigProvider protected: void setSecret(const envoy::extensions::transport_sockets::tls::v3::Secret& secret) override { - tls_certificate_secrets_ = + sds_tls_certificate_secrets_ = std::make_unique( secret.tls_certificate()); + resolved_tls_certificate_secrets_ = nullptr; + if (secret.tls_certificate().has_watched_directory()) { + watched_directory_ = std::make_unique( + secret.tls_certificate().watched_directory(), dispatcher_); + } else { + watched_directory_.reset(); + } + } + void resolveSecret(const FileContentMap& files) override { + resolved_tls_certificate_secrets_ = + std::make_unique( + *sds_tls_certificate_secrets_); + // We replace path based secrets with inlined secrets on update. + resolveDataSource(files, *resolved_tls_certificate_secrets_->mutable_certificate_chain()); + resolveDataSource(files, *resolved_tls_certificate_secrets_->mutable_private_key()); } void validateConfig(const envoy::extensions::transport_sockets::tls::v3::Secret&) override {} std::vector getDataSourceFilenames() override; + Config::WatchedDirectory* getWatchedDirectory() override { return watched_directory_.get(); } private: - TlsCertificatePtr tls_certificate_secrets_; + // Path to watch for rotation. + Config::WatchedDirectoryPtr watched_directory_; + // TlsCertificate according to SDS source. + TlsCertificatePtr sds_tls_certificate_secrets_; + // TlsCertificate after reloading. Path based certificates are inlined for + // future read consistency. + TlsCertificatePtr resolved_tls_certificate_secrets_; }; /** @@ -205,7 +254,7 @@ class CertificateValidationContextSdsApi : public SdsApi, // SecretProvider const envoy::extensions::transport_sockets::tls::v3::CertificateValidationContext* secret() const override { - return certificate_validation_context_secrets_.get(); + return resolved_certificate_validation_context_secrets_.get(); } Common::CallbackHandle* addUpdateCallback(std::function callback) override { if (secret()) { @@ -223,9 +272,26 @@ class CertificateValidationContextSdsApi : public SdsApi, protected: void setSecret(const envoy::extensions::transport_sockets::tls::v3::Secret& secret) override { - certificate_validation_context_secrets_ = std::make_unique< + sds_certificate_validation_context_secrets_ = std::make_unique< envoy::extensions::transport_sockets::tls::v3::CertificateValidationContext>( secret.validation_context()); + resolved_certificate_validation_context_secrets_ = nullptr; + if (secret.validation_context().has_watched_directory()) { + watched_directory_ = std::make_unique( + secret.validation_context().watched_directory(), dispatcher_); + } else { + watched_directory_.reset(); + } + } + + void resolveSecret(const FileContentMap& files) override { + // Copy existing CertificateValidationContext. + resolved_certificate_validation_context_secrets_ = std::make_unique< + envoy::extensions::transport_sockets::tls::v3::CertificateValidationContext>( + *sds_certificate_validation_context_secrets_); + // We replace path based secrets with inlined secrets on update. + resolveDataSource(files, + *resolved_certificate_validation_context_secrets_->mutable_trusted_ca()); } void @@ -233,9 +299,16 @@ class CertificateValidationContextSdsApi : public SdsApi, validation_callback_manager_.runCallbacks(secret.validation_context()); } std::vector getDataSourceFilenames() override; + Config::WatchedDirectory* getWatchedDirectory() override { return watched_directory_.get(); } private: - CertificateValidationContextPtr certificate_validation_context_secrets_; + // Directory to watch for rotation. + Config::WatchedDirectoryPtr watched_directory_; + // CertificateValidationContext according to SDS source; + CertificateValidationContextPtr sds_certificate_validation_context_secrets_; + // CertificateValidationContext after resolving paths via watched_directory_. + CertificateValidationContextPtr resolved_certificate_validation_context_secrets_; + // Path based certificates are inlined for future read consistency. Common::CallbackManager< const envoy::extensions::transport_sockets::tls::v3::CertificateValidationContext&> validation_callback_manager_; @@ -306,6 +379,7 @@ class TlsSessionTicketKeysSdsApi : public SdsApi, public TlsSessionTicketKeysCon validation_callback_manager_.runCallbacks(secret.session_ticket_keys()); } std::vector getDataSourceFilenames() override; + Config::WatchedDirectory* getWatchedDirectory() override { return nullptr; } private: Secret::TlsSessionTicketKeysPtr tls_session_ticket_keys_; @@ -346,7 +420,7 @@ class GenericSecretSdsApi : public SdsApi, public GenericSecretConfigProvider { // SecretProvider const envoy::extensions::transport_sockets::tls::v3::GenericSecret* secret() const override { - return generic_secret.get(); + return generic_secret_.get(); } Common::CallbackHandle* addUpdateCallback(std::function callback) override { return update_callback_manager_.add(callback); @@ -359,17 +433,19 @@ class GenericSecretSdsApi : public SdsApi, public GenericSecretConfigProvider { protected: void setSecret(const envoy::extensions::transport_sockets::tls::v3::Secret& secret) override { - generic_secret = std::make_unique( - secret.generic_secret()); + generic_secret_ = + std::make_unique( + secret.generic_secret()); } void validateConfig(const envoy::extensions::transport_sockets::tls::v3::Secret& secret) override { validation_callback_manager_.runCallbacks(secret.generic_secret()); } std::vector getDataSourceFilenames() override; + Config::WatchedDirectory* getWatchedDirectory() override { return nullptr; } private: - GenericSecretPtr generic_secret; + GenericSecretPtr generic_secret_; Common::CallbackManager validation_callback_manager_; }; diff --git a/source/common/signal/BUILD b/source/common/signal/BUILD index 2a18144c87dbf..893f2fa78454b 100644 --- a/source/common/signal/BUILD +++ b/source/common/signal/BUILD @@ -13,6 +13,8 @@ envoy_cc_library( srcs = ["fatal_error_handler.cc"], hdrs = ["fatal_error_handler.h"], deps = [ + ":fatal_action_lib", + "//include/envoy/event:dispatcher_interface", "//source/common/common:macros", ], ) @@ -30,3 +32,12 @@ envoy_cc_library( "//source/server:backtrace_lib", ], ) + +envoy_cc_library( + name = "fatal_action_lib", + hdrs = ["fatal_action.h"], + deps = [ + "//include/envoy/server:fatal_action_interface", + "//include/envoy/thread:thread_interface", + ], +) diff --git a/source/common/signal/fatal_action.h b/source/common/signal/fatal_action.h new file mode 100644 index 0000000000000..4ecaf1461635f --- /dev/null +++ b/source/common/signal/fatal_action.h @@ -0,0 +1,49 @@ +#pragma once + +#include + +#include "envoy/common/pure.h" +#include "envoy/server/fatal_action_config.h" +#include "envoy/thread/thread.h" + +namespace Envoy { +namespace FatalAction { + +using FatalActionPtrList = std::list; + +// Status when trying to run the Fatal Actions. +enum class Status { + Success, + + // We either haven't set up the Fatal Action manager, or we unregistered it + // as the server terminated. + ActionManangerUnset, + + // Another thread beat us to running the Fatal Actions. + RunningOnAnotherThread, + + // We have already ran those actions on this thread. + AlreadyRanOnThisThread, +}; + +// A simple class which manages the Fatal Actions registered via the +// extension point. +class FatalActionManager { +public: + FatalActionManager(FatalActionPtrList safe_actions, FatalActionPtrList unsafe_actions, + Thread::ThreadFactory& thread_factory) + : safe_actions_(std::move(safe_actions)), unsafe_actions_(std::move(unsafe_actions)), + thread_factory_(thread_factory) {} + + const FatalActionPtrList& getSafeActions() const { return safe_actions_; } + const FatalActionPtrList& getUnsafeActions() const { return unsafe_actions_; } + Thread::ThreadFactory& getThreadFactory() const { return thread_factory_; } + +private: + FatalActionPtrList safe_actions_; + FatalActionPtrList unsafe_actions_; + Thread::ThreadFactory& thread_factory_; +}; + +} // namespace FatalAction +} // namespace Envoy diff --git a/source/common/signal/fatal_error_handler.cc b/source/common/signal/fatal_error_handler.cc index 125093e3c589a..e7099e6f02544 100644 --- a/source/common/signal/fatal_error_handler.cc +++ b/source/common/signal/fatal_error_handler.cc @@ -1,8 +1,13 @@ #include "common/signal/fatal_error_handler.h" +#include #include +#include "envoy/event/dispatcher.h" + +#include "common/common/assert.h" #include "common/common/macros.h" +#include "common/signal/fatal_action.h" #include "absl/base/attributes.h" #include "absl/synchronization/mutex.h" @@ -12,6 +17,12 @@ namespace FatalErrorHandler { namespace { +// The type of Fatal Actions. +enum class FatalActionType { + Safe, + Unsafe, +}; + ABSL_CONST_INIT static absl::Mutex failure_mutex(absl::kConstInit); // Since we can't grab the failure mutex on fatal error (snagging locks under // fatal crash causing potential deadlocks) access the handler list as an atomic @@ -22,17 +33,84 @@ ABSL_CONST_INIT static absl::Mutex failure_mutex(absl::kConstInit); using FailureFunctionList = std::list; ABSL_CONST_INIT std::atomic fatal_error_handlers{nullptr}; +// Use an atomic operation since on fatal error we'll consume the +// fatal_action_manager and don't want to have any locks as they aren't +// async-signal-safe. +ABSL_CONST_INIT std::atomic fatal_action_manager{nullptr}; +ABSL_CONST_INIT std::atomic failure_tid{-1}; + +// Executes the Fatal Actions provided. +void runFatalActionsInternal(const FatalAction::FatalActionPtrList& actions) { + // Exchange the fatal_error_handlers pointer so other functions cannot + // concurrently access the list. + FailureFunctionList* list = fatal_error_handlers.exchange(nullptr); + if (list == nullptr) { + return; + } + + // Get the dispatcher and its tracked object. + for (auto* handler : *list) { + handler->runFatalActionsOnTrackedObject(actions); + } + + // Restore the fatal_error_handlers pointer so subsequent calls using the list + // can succeed. + fatal_error_handlers.store(list); +} + +// Helper function to run exclusively either safe or unsafe actions depending on +// the provided action_type. +// Returns a FatalAction status corresponding to our attempt to run the +// action_type. +FatalAction::Status runFatalActions(FatalActionType action_type) { + // Check that registerFatalActions has already been called. + FatalAction::FatalActionManager* action_manager = fatal_action_manager.load(); + + if (action_manager == nullptr) { + return FatalAction::Status::ActionManangerUnset; + } + + int64_t my_tid = action_manager->getThreadFactory().currentThreadId().getId(); + + if (action_type == FatalActionType::Safe) { + // Try to run safe actions + int64_t expected_tid = -1; + + if (failure_tid.compare_exchange_strong(expected_tid, my_tid)) { + // Run the actions + runFatalActionsInternal(action_manager->getSafeActions()); + return FatalAction::Status::Success; + } else if (expected_tid == my_tid) { + return FatalAction::Status::AlreadyRanOnThisThread; + } + + } else { + // Try to run unsafe actions + int64_t failing_tid = failure_tid.load(); + + ASSERT(failing_tid != -1); + + if (my_tid == failing_tid) { + runFatalActionsInternal(action_manager->getUnsafeActions()); + return FatalAction::Status::Success; + } + } + + return FatalAction::Status::RunningOnAnotherThread; +} + } // namespace void registerFatalErrorHandler(const FatalErrorHandlerInterface& handler) { #ifdef ENVOY_OBJECT_TRACE_ON_DUMP absl::MutexLock l(&failure_mutex); - FailureFunctionList* list = fatal_error_handlers.exchange(nullptr, std::memory_order_relaxed); + FailureFunctionList* list = fatal_error_handlers.exchange(nullptr); if (list == nullptr) { list = new FailureFunctionList; } list->push_back(&handler); - fatal_error_handlers.store(list, std::memory_order_release); + // Store the fatal_error_handlers pointer now that the list is updated. + fatal_error_handlers.store(list); #else UNREFERENCED_PARAMETER(handler); #endif @@ -41,7 +119,7 @@ void registerFatalErrorHandler(const FatalErrorHandlerInterface& handler) { void removeFatalErrorHandler(const FatalErrorHandlerInterface& handler) { #ifdef ENVOY_OBJECT_TRACE_ON_DUMP absl::MutexLock l(&failure_mutex); - FailureFunctionList* list = fatal_error_handlers.exchange(nullptr, std::memory_order_relaxed); + FailureFunctionList* list = fatal_error_handlers.exchange(nullptr); if (list == nullptr) { // removeFatalErrorHandler() may see an empty list of fatal error handlers // if it's called at the same time as callFatalErrorHandlers(). In that case @@ -53,7 +131,7 @@ void removeFatalErrorHandler(const FatalErrorHandlerInterface& handler) { if (list->empty()) { delete list; } else { - fatal_error_handlers.store(list, std::memory_order_release); + fatal_error_handlers.store(list); } #else UNREFERENCED_PARAMETER(handler); @@ -61,13 +139,50 @@ void removeFatalErrorHandler(const FatalErrorHandlerInterface& handler) { } void callFatalErrorHandlers(std::ostream& os) { - FailureFunctionList* list = fatal_error_handlers.exchange(nullptr, std::memory_order_relaxed); + FailureFunctionList* list = fatal_error_handlers.exchange(nullptr); if (list != nullptr) { for (const auto* handler : *list) { handler->onFatalError(os); } - delete list; + + fatal_error_handlers.store(list); + } +} + +void registerFatalActions(FatalAction::FatalActionPtrList safe_actions, + FatalAction::FatalActionPtrList unsafe_actions, + Thread::ThreadFactory& thread_factory) { + // Create a FatalActionManager and store it. + FatalAction::FatalActionManager* previous_manager = + fatal_action_manager.exchange(new FatalAction::FatalActionManager( + std::move(safe_actions), std::move(unsafe_actions), thread_factory)); + + // Previous manager should be NULL. + ASSERT(!previous_manager); +} + +FatalAction::Status runSafeActions() { return runFatalActions(FatalActionType::Safe); } + +FatalAction::Status runUnsafeActions() { return runFatalActions(FatalActionType::Unsafe); } + +void clearFatalActionsOnTerminate() { + auto* raw_ptr = fatal_action_manager.exchange(nullptr); + if (raw_ptr != nullptr) { + delete raw_ptr; + } +} + +// This resets the internal state of Fatal Action for the module. +// This is necessary as it allows us to have multiple test cases invoke the +// fatal actions without state from other tests leaking in. +void resetFatalActionStateForTest() { + // Free the memory of the Fatal Action, since it's not managed by a smart + // pointer. This prevents memory leaks in tests. + auto* raw_ptr = fatal_action_manager.exchange(nullptr); + if (raw_ptr != nullptr) { + delete raw_ptr; } + failure_tid.store(-1); } } // namespace FatalErrorHandler diff --git a/source/common/signal/fatal_error_handler.h b/source/common/signal/fatal_error_handler.h index b06997af7e815..d7d25013432d0 100644 --- a/source/common/signal/fatal_error_handler.h +++ b/source/common/signal/fatal_error_handler.h @@ -4,6 +4,8 @@ #include "envoy/common/pure.h" +#include "common/signal/fatal_action.h" + namespace Envoy { // A simple class which allows registering functions to be called when Envoy @@ -14,6 +16,9 @@ class FatalErrorHandlerInterface { // Called when Envoy receives a fatal signal. Must be async-signal-safe: in // particular, it can't allocate memory. virtual void onFatalError(std::ostream& os) const PURE; + + virtual void + runFatalActionsOnTrackedObject(const FatalAction::FatalActionPtrList& actions) const PURE; }; namespace FatalErrorHandler { @@ -35,5 +40,37 @@ void removeFatalErrorHandler(const FatalErrorHandlerInterface& handler); * called from a fatal signal handler. */ void callFatalErrorHandlers(std::ostream& os); + +/** + * Creates the singleton FatalActionManager if not already created and + * registers the specified actions to run on failure. + */ +void registerFatalActions(FatalAction::FatalActionPtrList safe_actions, + FatalAction::FatalActionPtrList unsafe_actions, + Thread::ThreadFactory& thread_factory); + +/** + * Tries to run all of the safe fatal actions. Only one thread will + * be allowed to run the fatal functions. + * + * Returns a FatalAction::Status which the caller should use to + * determine how to proceed. + */ +FatalAction::Status runSafeActions(); + +/** + * Tries to run all of the unsafe fatal actions. Call this only + * after calling runSafeActions. + * + * Returns a FatalAction::Status which the caller should use to determine + * how to proceed. + */ +FatalAction::Status runUnsafeActions(); + +/** + * Clear the Fatal Actions at the end of the server's call to terminate(). + * We should clean up the Fatal Action to prevent the memory from leaking. + */ +void clearFatalActionsOnTerminate(); } // namespace FatalErrorHandler } // namespace Envoy diff --git a/source/common/signal/signal_action.cc b/source/common/signal/signal_action.cc index c3a53c19da701..143b95a81f6c0 100644 --- a/source/common/signal/signal_action.cc +++ b/source/common/signal/signal_action.cc @@ -5,6 +5,7 @@ #include #include "common/common/assert.h" +#include "common/signal/fatal_action.h" #include "common/version/version.h" namespace Envoy { @@ -22,8 +23,31 @@ void SignalAction::sigHandler(int sig, siginfo_t* info, void* context) { } tracer.logTrace(); - // Finally after logging the stack trace, call any registered crash handlers. - FatalErrorHandler::callFatalErrorHandlers(std::cerr); + // Finally after logging the stack trace, call the crash handlers + // in order from safe to unsafe. + auto status = FatalErrorHandler::runSafeActions(); + + switch (status) { + case FatalAction::Status::Success: + FatalErrorHandler::callFatalErrorHandlers(std::cerr); + FatalErrorHandler::runUnsafeActions(); + break; + case FatalAction::Status::ActionManangerUnset: + FatalErrorHandler::callFatalErrorHandlers(std::cerr); + break; + case FatalAction::Status::RunningOnAnotherThread: { + // We should wait for some duration for the other thread to finish + // running. We should add support for this scenario, even though the + // probability of it occurring is low. + // TODO(kbaichoo): Implement a configurable call to sleep + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; + break; + } + case FatalAction::Status::AlreadyRanOnThisThread: + // We caused another fatal signal to be raised. + std::cerr << "Our FatalActions triggered a fatal signal.\n"; + break; + } signal(sig, SIG_DFL); raise(sig); diff --git a/source/common/stats/BUILD b/source/common/stats/BUILD index fb85280639340..edc68f4774e7b 100644 --- a/source/common/stats/BUILD +++ b/source/common/stats/BUILD @@ -195,6 +195,7 @@ envoy_cc_library( hdrs = ["tag_extractor_impl.h"], deps = [ "//include/envoy/stats:stats_interface", + "//source/common/common:assert_lib", "//source/common/common:perf_annotation_lib", "//source/common/common:regex_lib", ], diff --git a/source/common/stats/tag_extractor_impl.cc b/source/common/stats/tag_extractor_impl.cc index 3c666a13e105c..6aefbdf6cd258 100644 --- a/source/common/stats/tag_extractor_impl.cc +++ b/source/common/stats/tag_extractor_impl.cc @@ -5,6 +5,7 @@ #include "envoy/common/exception.h" +#include "common/common/assert.h" #include "common/common/fmt.h" #include "common/common/perf_annotation.h" #include "common/common/regex.h" @@ -23,12 +24,11 @@ bool regexStartsWithDot(absl::string_view regex) { } // namespace -TagExtractorImpl::TagExtractorImpl(const std::string& name, const std::string& regex, - const std::string& substr) - : name_(name), prefix_(std::string(extractRegexPrefix(regex))), substr_(substr), - regex_(Regex::Utility::parseStdRegex(regex)) {} +TagExtractorImplBase::TagExtractorImplBase(absl::string_view name, absl::string_view regex, + absl::string_view substr) + : name_(name), prefix_(std::string(extractRegexPrefix(regex))), substr_(substr) {} -std::string TagExtractorImpl::extractRegexPrefix(absl::string_view regex) { +std::string TagExtractorImplBase::extractRegexPrefix(absl::string_view regex) { std::string prefix; if (absl::StartsWith(regex, "^")) { for (absl::string_view::size_type i = 1; i < regex.size(); ++i) { @@ -47,10 +47,10 @@ std::string TagExtractorImpl::extractRegexPrefix(absl::string_view regex) { return prefix; } -TagExtractorPtr TagExtractorImpl::createTagExtractor(const std::string& name, - const std::string& regex, - const std::string& substr) { - +TagExtractorPtr TagExtractorImplBase::createTagExtractor(absl::string_view name, + absl::string_view regex, + absl::string_view substr, + Regex::Type re_type) { if (name.empty()) { throw EnvoyException("tag_name cannot be empty"); } @@ -59,19 +59,37 @@ TagExtractorPtr TagExtractorImpl::createTagExtractor(const std::string& name, throw EnvoyException(fmt::format( "No regex specified for tag specifier and no default regex for name: '{}'", name)); } - return TagExtractorPtr{new TagExtractorImpl(name, regex, substr)}; + switch (re_type) { + case Regex::Type::Re2: + return std::make_unique(name, regex, substr); + case Regex::Type::StdRegex: + return std::make_unique(name, regex, substr); + } + NOT_REACHED_GCOVR_EXCL_LINE; } -bool TagExtractorImpl::substrMismatch(absl::string_view stat_name) const { +bool TagExtractorImplBase::substrMismatch(absl::string_view stat_name) const { return !substr_.empty() && stat_name.find(substr_) == absl::string_view::npos; } -bool TagExtractorImpl::extractTag(absl::string_view stat_name, TagVector& tags, - IntervalSet& remove_characters) const { +TagExtractorStdRegexImpl::TagExtractorStdRegexImpl(absl::string_view name, absl::string_view regex, + absl::string_view substr) + : TagExtractorImplBase(name, regex, substr), + regex_(Regex::Utility::parseStdRegex(std::string(regex))) {} + +std::string& TagExtractorImplBase::addTag(std::vector& tags) const { + tags.emplace_back(); + Tag& tag = tags.back(); + tag.name_ = name_; + return tag.value_; +} + +bool TagExtractorStdRegexImpl::extractTag(absl::string_view stat_name, std::vector& tags, + IntervalSet& remove_characters) const { PERF_OPERATION(perf); if (substrMismatch(stat_name)) { - PERF_RECORD(perf, "re-skip-substr", name_); + PERF_RECORD(perf, "re-skip", name_); return false; } @@ -88,11 +106,7 @@ bool TagExtractorImpl::extractTag(absl::string_view stat_name, TagVector& tags, // from the string but also not necessary in the tag value ("." for example). If there is no // second submatch, then the value_subexpr is the same as the remove_subexpr. const auto& value_subexpr = match.size() > 2 ? match[2] : remove_subexpr; - - tags.emplace_back(); - Tag& tag = tags.back(); - tag.name_ = name_; - tag.value_ = value_subexpr.str(); + addTag(tags) = value_subexpr.str(); // Determines which characters to remove from stat_name to elide remove_subexpr. std::string::size_type start = remove_subexpr.first - stat_name.begin(); @@ -105,5 +119,47 @@ bool TagExtractorImpl::extractTag(absl::string_view stat_name, TagVector& tags, return false; } +TagExtractorRe2Impl::TagExtractorRe2Impl(absl::string_view name, absl::string_view regex, + absl::string_view substr) + : TagExtractorImplBase(name, regex, substr), regex_(regex) {} + +bool TagExtractorRe2Impl::extractTag(absl::string_view stat_name, std::vector& tags, + IntervalSet& remove_characters) const { + PERF_OPERATION(perf); + + if (substrMismatch(stat_name)) { + PERF_RECORD(perf, "re2-skip", name_); + return false; + } + + // remove_subexpr is the first submatch. It represents the portion of the string to be removed. + re2::StringPiece remove_subexpr, value_subexpr; + + // The regex must match and contain one or more subexpressions (all after the first are ignored). + if (re2::RE2::FullMatch(re2::StringPiece(stat_name.data(), stat_name.size()), regex_, + &remove_subexpr, &value_subexpr) && + !remove_subexpr.empty()) { + + // value_subexpr is the optional second submatch. It is usually inside the first submatch + // (remove_subexpr) to allow the expression to strip off extra characters that should be removed + // from the string but also not necessary in the tag value ("." for example). If there is no + // second submatch, then the value_subexpr is the same as the remove_subexpr. + if (value_subexpr.empty()) { + value_subexpr = remove_subexpr; + } + addTag(tags) = std::string(value_subexpr); + + // Determines which characters to remove from stat_name to elide remove_subexpr. + std::string::size_type start = remove_subexpr.data() - stat_name.data(); + std::string::size_type end = remove_subexpr.data() + remove_subexpr.size() - stat_name.data(); + remove_characters.insert(start, end); + + PERF_RECORD(perf, "re2-match", name_); + return true; + } + PERF_RECORD(perf, "re2-miss", name_); + return false; +} + } // namespace Stats } // namespace Envoy diff --git a/source/common/stats/tag_extractor_impl.h b/source/common/stats/tag_extractor_impl.h index a63c7e1e46261..f909868eb2362 100644 --- a/source/common/stats/tag_extractor_impl.h +++ b/source/common/stats/tag_extractor_impl.h @@ -6,12 +6,15 @@ #include "envoy/stats/tag_extractor.h" +#include "common/common/regex.h" + #include "absl/strings/string_view.h" +#include "re2/re2.h" namespace Envoy { namespace Stats { -class TagExtractorImpl : public TagExtractor { +class TagExtractorImplBase : public TagExtractor { public: /** * Creates a tag extractor from the regex provided. name and regex must be non-empty. @@ -20,16 +23,16 @@ class TagExtractorImpl : public TagExtractor { * @param substr a substring that -- if provided -- must be present in a stat name * in order to match the regex. This is an optional performance tweak * to avoid large numbers of failed regex lookups. + * @param re_type the regular expression syntax used (Regex::Type::StdRegex or Regex::Type::Re2). * @return TagExtractorPtr newly constructed TagExtractor. */ - static TagExtractorPtr createTagExtractor(const std::string& name, const std::string& regex, - const std::string& substr = ""); + static TagExtractorPtr createTagExtractor(absl::string_view name, absl::string_view regex, + absl::string_view substr = "", + Regex::Type re_type = Regex::Type::StdRegex); - TagExtractorImpl(const std::string& name, const std::string& regex, - const std::string& substr = ""); + TagExtractorImplBase(absl::string_view name, absl::string_view regex, + absl::string_view substr = ""); std::string name() const override { return name_; } - bool extractTag(absl::string_view tag_extracted_name, TagVector& tags, - IntervalSet& remove_characters) const override; absl::string_view prefixToken() const override { return prefix_; } /** @@ -39,7 +42,7 @@ class TagExtractorImpl : public TagExtractor { */ bool substrMismatch(absl::string_view stat_name) const; -private: +protected: /** * Examines a regex string, looking for the pattern: ^alphanumerics_with_underscores\. * Returns "alphanumerics_with_underscores" if that pattern is found, empty-string otherwise. @@ -47,11 +50,43 @@ class TagExtractorImpl : public TagExtractor { * @return std::string the prefix, or "" if no prefix found. */ static std::string extractRegexPrefix(absl::string_view regex); + + /** + * Adds a new tag for the current name, returning a reference to the tag value. + * + * @param tags the list of tags + * @return a reference to the value of the tag that was added. + */ + std::string& addTag(std::vector& tags) const; + const std::string name_; const std::string prefix_; const std::string substr_; +}; + +class TagExtractorStdRegexImpl : public TagExtractorImplBase { +public: + TagExtractorStdRegexImpl(absl::string_view name, absl::string_view regex, + absl::string_view substr = ""); + + bool extractTag(absl::string_view tag_extracted_name, std::vector& tags, + IntervalSet& remove_characters) const override; + +private: const std::regex regex_; }; +class TagExtractorRe2Impl : public TagExtractorImplBase { +public: + TagExtractorRe2Impl(absl::string_view name, absl::string_view regex, + absl::string_view substr = ""); + + bool extractTag(absl::string_view tag_extracted_name, std::vector& tags, + IntervalSet& remove_characters) const override; + +private: + const re2::RE2 regex_; +}; + } // namespace Stats } // namespace Envoy diff --git a/source/common/stats/tag_producer_impl.cc b/source/common/stats/tag_producer_impl.cc index 255dfcaeed39b..bfc35b52e40ae 100644 --- a/source/common/stats/tag_producer_impl.cc +++ b/source/common/stats/tag_producer_impl.cc @@ -34,11 +34,11 @@ TagProducerImpl::TagProducerImpl(const envoy::config::metrics::v3::StatsConfig& "No regex specified for tag specifier and no default regex for name: '{}'", name)); } } else { - addExtractor(Stats::TagExtractorImpl::createTagExtractor(name, tag_specifier.regex())); + addExtractor(TagExtractorImplBase::createTagExtractor(name, tag_specifier.regex())); } } else if (tag_specifier.tag_value_case() == envoy::config::metrics::v3::TagSpecifier::TagValueCase::kFixedValue) { - default_tags_.emplace_back(Stats::Tag{name, tag_specifier.fixed_value()}); + default_tags_.emplace_back(Tag{name, tag_specifier.fixed_value()}); } } } @@ -47,8 +47,8 @@ int TagProducerImpl::addExtractorsMatching(absl::string_view name) { int num_found = 0; for (const auto& desc : Config::TagNames::get().descriptorVec()) { if (desc.name_ == name) { - addExtractor( - Stats::TagExtractorImpl::createTagExtractor(desc.name_, desc.regex_, desc.substr_)); + addExtractor(TagExtractorImplBase::createTagExtractor(desc.name_, desc.regex_, desc.substr_, + desc.re_type_)); ++num_found; } } @@ -103,8 +103,8 @@ TagProducerImpl::addDefaultExtractors(const envoy::config::metrics::v3::StatsCon if (!config.has_use_all_default_tags() || config.use_all_default_tags().value()) { for (const auto& desc : Config::TagNames::get().descriptorVec()) { names.emplace(desc.name_); - addExtractor( - Stats::TagExtractorImpl::createTagExtractor(desc.name_, desc.regex_, desc.substr_)); + addExtractor(TagExtractorImplBase::createTagExtractor(desc.name_, desc.regex_, desc.substr_, + desc.re_type_)); } } return names; diff --git a/source/common/tcp/conn_pool.h b/source/common/tcp/conn_pool.h index a3637b8a43cdb..15fa4bd9aca47 100644 --- a/source/common/tcp/conn_pool.h +++ b/source/common/tcp/conn_pool.h @@ -95,7 +95,7 @@ class ActiveTcpClient : public Envoy::ConnectionPool::ActiveClient { void onBelowWriteBufferLowWatermark() override { callbacks_->onBelowWriteBufferLowWatermark(); } void close() override { connection_->close(Network::ConnectionCloseType::NoFlush); } - size_t numActiveStreams() const override { return callbacks_ ? 1 : 0; } + uint32_t numActiveStreams() const override { return callbacks_ ? 1 : 0; } bool closingWithIncompleteStream() const override { return false; } uint64_t id() const override { return connection_->id(); } @@ -121,9 +121,10 @@ class ConnPoolImpl : public Envoy::ConnectionPool::ConnPoolImplBase, ConnPoolImpl(Event::Dispatcher& dispatcher, Upstream::HostConstSharedPtr host, Upstream::ResourcePriority priority, const Network::ConnectionSocket::OptionsSharedPtr& options, - Network::TransportSocketOptionsSharedPtr transport_socket_options) + Network::TransportSocketOptionsSharedPtr transport_socket_options, + Upstream::ClusterConnectivityState& state) : Envoy::ConnectionPool::ConnPoolImplBase(host, priority, dispatcher, options, - transport_socket_options) {} + transport_socket_options, state) {} ~ConnPoolImpl() override { destructAllConnections(); } void addDrainedCallback(DrainedCb cb) override { addDrainedCallbackImpl(cb); } @@ -136,8 +137,8 @@ class ConnPoolImpl : public Envoy::ConnectionPool::ConnPoolImplBase, uint64_t old_limit = connecting_client->effectiveConcurrentStreamLimit(); connecting_client->remaining_streams_ = 1; if (connecting_client->effectiveConcurrentStreamLimit() < old_limit) { - connecting_stream_capacity_ -= - (old_limit - connecting_client->effectiveConcurrentStreamLimit()); + decrConnectingStreamCapacity(old_limit - + connecting_client->effectiveConcurrentStreamLimit()); } } } @@ -162,8 +163,7 @@ class ConnPoolImpl : public Envoy::ConnectionPool::ConnPoolImplBase, newPendingStream(Envoy::ConnectionPool::AttachContext& context) override { Envoy::ConnectionPool::PendingStreamPtr pending_stream = std::make_unique(*this, typedContext(context)); - LinkedList::moveIntoList(std::move(pending_stream), pending_streams_); - return pending_streams_.front().get(); + return addPendingStream(std::move(pending_stream)); } Upstream::HostDescriptionConstSharedPtr host() const override { diff --git a/source/common/tcp_proxy/BUILD b/source/common/tcp_proxy/BUILD index 401b8c3e87944..df1b7b2224470 100644 --- a/source/common/tcp_proxy/BUILD +++ b/source/common/tcp_proxy/BUILD @@ -21,6 +21,7 @@ envoy_cc_library( "//include/envoy/tcp:upstream_interface", "//include/envoy/upstream:cluster_manager_interface", "//include/envoy/upstream:load_balancer_interface", + "//source/common/http:codec_client_lib", "//source/common/http:header_map_lib", "//source/common/http:headers_lib", "//source/common/http:utility_lib", @@ -58,6 +59,7 @@ envoy_cc_library( "//source/common/common:empty_string", "//source/common/common:macros", "//source/common/common:minimal_logger_lib", + "//source/common/http:codec_client_lib", "//source/common/network:application_protocol_lib", "//source/common/network:cidr_range_lib", "//source/common/network:filter_lib", diff --git a/source/common/tcp_proxy/upstream.cc b/source/common/tcp_proxy/upstream.cc index 3f3d73c6add4d..128a7f769039b 100644 --- a/source/common/tcp_proxy/upstream.cc +++ b/source/common/tcp_proxy/upstream.cc @@ -2,6 +2,8 @@ #include "envoy/upstream/cluster_manager.h" +#include "common/http/codec_client.h" +#include "common/http/codes.h" #include "common/http/header_map_impl.h" #include "common/http/headers.h" #include "common/http/utility.h" @@ -54,17 +56,10 @@ TcpUpstream::onDownstreamEvent(Network::ConnectionEvent event) { HttpUpstream::HttpUpstream(Tcp::ConnectionPool::UpstreamCallbacks& callbacks, const std::string& hostname) - : upstream_callbacks_(callbacks), response_decoder_(*this), hostname_(hostname) {} + : hostname_(hostname), response_decoder_(*this), upstream_callbacks_(callbacks) {} HttpUpstream::~HttpUpstream() { resetEncoder(Network::ConnectionEvent::LocalClose); } -bool HttpUpstream::isValidBytestreamResponse(const Http::ResponseHeaderMap& headers) { - if (Http::Utility::getResponseStatus(headers) != 200) { - return false; - } - return true; -} - bool HttpUpstream::readDisable(bool disable) { if (!request_encoder_) { return false; @@ -112,22 +107,6 @@ void HttpUpstream::onBelowWriteBufferLowWatermark() { upstream_callbacks_.onBelowWriteBufferLowWatermark(); } -void HttpUpstream::setRequestEncoder(Http::RequestEncoder& request_encoder, bool is_ssl) { - request_encoder_ = &request_encoder; - request_encoder_->getStream().addCallbacks(*this); - const std::string& scheme = - is_ssl ? Http::Headers::get().SchemeValues.Https : Http::Headers::get().SchemeValues.Http; - auto headers = Http::createHeaderMap( - {{Http::Headers::get().Method, "CONNECT"}, - {Http::Headers::get().Protocol, Http::Headers::get().ProtocolValues.Bytestream}, - {Http::Headers::get().Scheme, scheme}, - {Http::Headers::get().Path, "/"}, - {Http::Headers::get().Host, hostname_}}); - const auto status = request_encoder_->encodeHeaders(*headers, false); - // Encoding can only fail on missing required request headers. - ASSERT(status.ok()); -} - void HttpUpstream::resetEncoder(Network::ConnectionEvent event, bool inform_downstream) { if (!request_encoder_) { return; @@ -204,8 +183,9 @@ void TcpConnPool::onPoolReady(Tcp::ConnectionPool::ConnectionDataPtr&& conn_data HttpConnPool::HttpConnPool(const std::string& cluster_name, Upstream::ClusterManager& cluster_manager, Upstream::LoadBalancerContext* context, const TunnelingConfig& config, - Tcp::ConnectionPool::UpstreamCallbacks& upstream_callbacks) - : hostname_(config.hostname()), upstream_callbacks_(upstream_callbacks) { + Tcp::ConnectionPool::UpstreamCallbacks& upstream_callbacks, + Http::CodecClient::Type type) + : hostname_(config.hostname()), type_(type), upstream_callbacks_(upstream_callbacks) { conn_pool_ = cluster_manager.httpConnPoolForCluster( cluster_name, Upstream::ResourcePriority::Default, absl::nullopt, context); } @@ -220,7 +200,11 @@ HttpConnPool::~HttpConnPool() { void HttpConnPool::newStream(GenericConnectionPoolCallbacks& callbacks) { callbacks_ = &callbacks; - upstream_ = std::make_unique(upstream_callbacks_, hostname_); + if (type_ == Http::CodecClient::Type::HTTP1) { + upstream_ = std::make_unique(upstream_callbacks_, hostname_); + } else { + upstream_ = std::make_unique(upstream_callbacks_, hostname_); + } Tcp::ConnectionPool::Cancellable* handle = conn_pool_->newStream(upstream_->responseDecoder(), *this); if (handle != nullptr) { @@ -246,5 +230,66 @@ void HttpConnPool::onPoolReady(Http::RequestEncoder& request_encoder, info.downstreamSslConnection()); } +Http2Upstream::Http2Upstream(Tcp::ConnectionPool::UpstreamCallbacks& callbacks, + const std::string& hostname) + : HttpUpstream(callbacks, hostname) {} + +bool Http2Upstream::isValidResponse(const Http::ResponseHeaderMap& headers) { + if (Http::Utility::getResponseStatus(headers) != 200) { + return false; + } + return true; +} + +void Http2Upstream::setRequestEncoder(Http::RequestEncoder& request_encoder, bool is_ssl) { + request_encoder_ = &request_encoder; + request_encoder_->getStream().addCallbacks(*this); + const std::string& scheme = + is_ssl ? Http::Headers::get().SchemeValues.Https : Http::Headers::get().SchemeValues.Http; + auto headers = Http::createHeaderMap( + {{Http::Headers::get().Method, "CONNECT"}, + {Http::Headers::get().Protocol, Http::Headers::get().ProtocolValues.Bytestream}, + {Http::Headers::get().Scheme, scheme}, + {Http::Headers::get().Path, "/"}, + {Http::Headers::get().Host, hostname_}}); + const auto status = request_encoder_->encodeHeaders(*headers, false); + // Encoding can only fail on missing required request headers. + ASSERT(status.ok()); +} + +Http1Upstream::Http1Upstream(Tcp::ConnectionPool::UpstreamCallbacks& callbacks, + const std::string& hostname) + : HttpUpstream(callbacks, hostname) {} + +void Http1Upstream::setRequestEncoder(Http::RequestEncoder& request_encoder, bool) { + request_encoder_ = &request_encoder; + request_encoder_->getStream().addCallbacks(*this); + + ASSERT(request_encoder_->http1StreamEncoderOptions() != absl::nullopt); + auto headers = Http::createHeaderMap({ + {Http::Headers::get().Method, "CONNECT"}, + {Http::Headers::get().Host, hostname_}, + }); + + const auto status = request_encoder_->encodeHeaders(*headers, false); + // Encoding can only fail on missing required request headers. + ASSERT(status.ok()); +} + +bool Http1Upstream::isValidResponse(const Http::ResponseHeaderMap& headers) { + // According to RFC7231 any 2xx response indicates that the connection is + // established. + // Any 'Content-Length' or 'Transfer-Encoding' header fields MUST be ignored. + // https://tools.ietf.org/html/rfc7231#section-4.3.6 + return Http::CodeUtility::is2xx(Http::Utility::getResponseStatus(headers)); +} + +void Http1Upstream::encodeData(Buffer::Instance& data, bool end_stream) { + if (!request_encoder_) { + return; + } + request_encoder_->encodeData(data, end_stream); +} + } // namespace TcpProxy } // namespace Envoy diff --git a/source/common/tcp_proxy/upstream.h b/source/common/tcp_proxy/upstream.h index e132b667e2ca5..7a4da879187af 100644 --- a/source/common/tcp_proxy/upstream.h +++ b/source/common/tcp_proxy/upstream.h @@ -7,6 +7,8 @@ #include "envoy/upstream/load_balancer.h" #include "envoy/upstream/upstream.h" +#include "common/http/codec_client.h" + namespace Envoy { namespace TcpProxy { @@ -44,10 +46,12 @@ class HttpConnPool : public GenericConnPool, public Http::ConnectionPool::Callba HttpConnPool(const std::string& cluster_name, Upstream::ClusterManager& cluster_manager, Upstream::LoadBalancerContext* context, const TunnelingConfig& config, - Tcp::ConnectionPool::UpstreamCallbacks& upstream_callbacks); + Tcp::ConnectionPool::UpstreamCallbacks& upstream_callbacks, + Http::CodecClient::Type type); ~HttpConnPool() override; - bool valid() const { return conn_pool_ != nullptr; } + // HTTP/3 upstreams are not supported at the moment. + bool valid() const { return conn_pool_ != nullptr && type_ <= Http::CodecClient::Type::HTTP2; } // GenericConnPool void newStream(GenericConnectionPoolCallbacks& callbacks) override; @@ -62,6 +66,7 @@ class HttpConnPool : public GenericConnPool, public Http::ConnectionPool::Callba private: const std::string hostname_; + Http::CodecClient::Type type_; Http::ConnectionPool::Instance* conn_pool_{}; Http::ConnectionPool::Cancellable* upstream_handle_{}; GenericConnectionPoolCallbacks* callbacks_{}; @@ -84,15 +89,15 @@ class TcpUpstream : public GenericUpstream { Tcp::ConnectionPool::ConnectionDataPtr upstream_conn_data_; }; -class HttpUpstream : public GenericUpstream, Http::StreamCallbacks { +class HttpUpstream : public GenericUpstream, protected Http::StreamCallbacks { public: - HttpUpstream(Tcp::ConnectionPool::UpstreamCallbacks& callbacks, const std::string& hostname); ~HttpUpstream() override; - static bool isValidBytestreamResponse(const Http::ResponseHeaderMap& headers); + virtual bool isValidResponse(const Http::ResponseHeaderMap&) PURE; void doneReading(); void doneWriting(); + Http::ResponseDecoder& responseDecoder() { return response_decoder_; } // GenericUpstream bool readDisable(bool disable) override; @@ -106,20 +111,23 @@ class HttpUpstream : public GenericUpstream, Http::StreamCallbacks { void onAboveWriteBufferHighWatermark() override; void onBelowWriteBufferLowWatermark() override; - virtual void setRequestEncoder(Http::RequestEncoder& request_encoder, bool is_ssl); + virtual void setRequestEncoder(Http::RequestEncoder& request_encoder, bool is_ssl) PURE; - Http::ResponseDecoder& responseDecoder() { return response_decoder_; } - -private: +protected: + HttpUpstream(Tcp::ConnectionPool::UpstreamCallbacks& callbacks, const std::string& hostname); void resetEncoder(Network::ConnectionEvent event, bool inform_downstream = true); + Http::RequestEncoder* request_encoder_{}; + const std::string hostname_; + +private: class DecoderShim : public Http::ResponseDecoder { public: DecoderShim(HttpUpstream& parent) : parent_(parent) {} // Http::ResponseDecoder void decode100ContinueHeaders(Http::ResponseHeaderMapPtr&&) override {} void decodeHeaders(Http::ResponseHeaderMapPtr&& headers, bool end_stream) override { - if (!isValidBytestreamResponse(*headers) || end_stream) { + if (!parent_.isValidResponse(*headers) || end_stream) { parent_.resetEncoder(Network::ConnectionEvent::LocalClose); } } @@ -135,14 +143,28 @@ class HttpUpstream : public GenericUpstream, Http::StreamCallbacks { private: HttpUpstream& parent_; }; - - Tcp::ConnectionPool::UpstreamCallbacks& upstream_callbacks_; DecoderShim response_decoder_; - Http::RequestEncoder* request_encoder_{}; - const std::string hostname_; + Tcp::ConnectionPool::UpstreamCallbacks& upstream_callbacks_; bool read_half_closed_{}; bool write_half_closed_{}; }; +class Http1Upstream : public HttpUpstream { +public: + Http1Upstream(Tcp::ConnectionPool::UpstreamCallbacks& callbacks, const std::string& hostname); + + void encodeData(Buffer::Instance& data, bool end_stream) override; + void setRequestEncoder(Http::RequestEncoder& request_encoder, bool is_ssl) override; + bool isValidResponse(const Http::ResponseHeaderMap& headers) override; +}; + +class Http2Upstream : public HttpUpstream { +public: + Http2Upstream(Tcp::ConnectionPool::UpstreamCallbacks& callbacks, const std::string& hostname); + + void setRequestEncoder(Http::RequestEncoder& request_encoder, bool is_ssl) override; + bool isValidResponse(const Http::ResponseHeaderMap& headers) override; +}; + } // namespace TcpProxy } // namespace Envoy diff --git a/source/common/upstream/cds_api_impl.cc b/source/common/upstream/cds_api_impl.cc index 0ca7d5763d5a9..4568bf84b8f3d 100644 --- a/source/common/upstream/cds_api_impl.cc +++ b/source/common/upstream/cds_api_impl.cc @@ -38,15 +38,22 @@ CdsApiImpl::CdsApiImpl(const envoy::config::core::v3::ConfigSource& cds_config, void CdsApiImpl::onConfigUpdate(const std::vector& resources, const std::string& version_info) { - ClusterManager::ClusterInfoMap clusters_to_remove = cm_.clusters(); - std::vector clusters; + auto all_existing_clusters = cm_.clusters(); + // Exclude the clusters which CDS wants to add. for (const auto& resource : resources) { - clusters_to_remove.erase(resource.get().name()); + all_existing_clusters.active_clusters_.erase(resource.get().name()); + all_existing_clusters.warming_clusters_.erase(resource.get().name()); } Protobuf::RepeatedPtrField to_remove_repeated; - for (const auto& [cluster_name, _] : clusters_to_remove) { + for (const auto& [cluster_name, _] : all_existing_clusters.active_clusters_) { *to_remove_repeated.Add() = cluster_name; } + for (const auto& [cluster_name, _] : all_existing_clusters.warming_clusters_) { + // Do not add the cluster twice when the cluster is both active and warming. + if (all_existing_clusters.active_clusters_.count(cluster_name) == 0) { + *to_remove_repeated.Add() = cluster_name; + } + } onConfigUpdate(resources, to_remove_repeated, version_info); } @@ -64,7 +71,7 @@ void CdsApiImpl::onConfigUpdate(const std::vector& a removed_resources.size()); std::vector exception_msgs; - absl::node_hash_set cluster_names; + absl::flat_hash_set cluster_names(added_resources.size()); bool any_applied = false; for (const auto& resource : added_resources) { envoy::config::cluster::v3::Cluster cluster; diff --git a/source/common/upstream/cluster_manager_impl.cc b/source/common/upstream/cluster_manager_impl.cc index 3e816fc6e1605..a4d53e9d6bab5 100644 --- a/source/common/upstream/cluster_manager_impl.cc +++ b/source/common/upstream/cluster_manager_impl.cc @@ -1450,7 +1450,8 @@ ClusterManagerImpl::ThreadLocalClusterManagerImpl::ClusterEntry::connPool( return parent_.parent_.factory_.allocateConnPool( parent_.thread_local_dispatcher_, host, priority, upstream_protocol, !upstream_options->empty() ? upstream_options : nullptr, - have_transport_socket_options ? context->upstreamTransportSocketOptions() : nullptr); + have_transport_socket_options ? context->upstreamTransportSocketOptions() : nullptr, + parent_.cluster_manager_state_); }); if (pool.has_value()) { @@ -1499,7 +1500,8 @@ ClusterManagerImpl::ThreadLocalClusterManagerImpl::ClusterEntry::tcpConnPool( container.pools_[hash_key] = parent_.parent_.factory_.allocateTcpConnPool( parent_.thread_local_dispatcher_, host, priority, have_options ? context->downstreamConnection()->socketOptions() : nullptr, - have_transport_socket_options ? context->upstreamTransportSocketOptions() : nullptr); + have_transport_socket_options ? context->upstreamTransportSocketOptions() : nullptr, + parent_.cluster_manager_state_); } return container.pools_[hash_key].get(); @@ -1515,27 +1517,29 @@ ClusterManagerPtr ProdClusterManagerFactory::clusterManagerFromProto( Http::ConnectionPool::InstancePtr ProdClusterManagerFactory::allocateConnPool( Event::Dispatcher& dispatcher, HostConstSharedPtr host, ResourcePriority priority, Http::Protocol protocol, const Network::ConnectionSocket::OptionsSharedPtr& options, - const Network::TransportSocketOptionsSharedPtr& transport_socket_options) { + const Network::TransportSocketOptionsSharedPtr& transport_socket_options, + ClusterConnectivityState& state) { if (protocol == Http::Protocol::Http2 && runtime_.snapshot().featureEnabled("upstream.use_http2", 100)) { return Http::Http2::allocateConnPool(dispatcher, api_.randomGenerator(), host, priority, - options, transport_socket_options); + options, transport_socket_options, state); } else if (protocol == Http::Protocol::Http3) { // Quic connection pool is not implemented. NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } else { return Http::Http1::allocateConnPool(dispatcher, api_.randomGenerator(), host, priority, - options, transport_socket_options); + options, transport_socket_options, state); } } Tcp::ConnectionPool::InstancePtr ProdClusterManagerFactory::allocateTcpConnPool( Event::Dispatcher& dispatcher, HostConstSharedPtr host, ResourcePriority priority, const Network::ConnectionSocket::OptionsSharedPtr& options, - Network::TransportSocketOptionsSharedPtr transport_socket_options) { + Network::TransportSocketOptionsSharedPtr transport_socket_options, + ClusterConnectivityState& state) { if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.new_tcp_connection_pool")) { return std::make_unique(dispatcher, host, priority, options, - transport_socket_options); + transport_socket_options, state); } else { return Tcp::ConnectionPool::InstancePtr{new Tcp::OriginalConnPoolImpl( dispatcher, host, priority, options, transport_socket_options)}; diff --git a/source/common/upstream/cluster_manager_impl.h b/source/common/upstream/cluster_manager_impl.h index 63a5e701e9d60..0efef83108f74 100644 --- a/source/common/upstream/cluster_manager_impl.h +++ b/source/common/upstream/cluster_manager_impl.h @@ -60,15 +60,18 @@ class ProdClusterManagerFactory : public ClusterManagerFactory { // Upstream::ClusterManagerFactory ClusterManagerPtr clusterManagerFromProto(const envoy::config::bootstrap::v3::Bootstrap& bootstrap) override; - Http::ConnectionPool::InstancePtr allocateConnPool( - Event::Dispatcher& dispatcher, HostConstSharedPtr host, ResourcePriority priority, - Http::Protocol protocol, const Network::ConnectionSocket::OptionsSharedPtr& options, - const Network::TransportSocketOptionsSharedPtr& transport_socket_options) override; + Http::ConnectionPool::InstancePtr + allocateConnPool(Event::Dispatcher& dispatcher, HostConstSharedPtr host, + ResourcePriority priority, Http::Protocol protocol, + const Network::ConnectionSocket::OptionsSharedPtr& options, + const Network::TransportSocketOptionsSharedPtr& transport_socket_options, + ClusterConnectivityState& state) override; Tcp::ConnectionPool::InstancePtr allocateTcpConnPool(Event::Dispatcher& dispatcher, HostConstSharedPtr host, ResourcePriority priority, const Network::ConnectionSocket::OptionsSharedPtr& options, - Network::TransportSocketOptionsSharedPtr transport_socket_options) override; + Network::TransportSocketOptionsSharedPtr transport_socket_options, + ClusterConnectivityState& state) override; std::pair clusterFromProto(const envoy::config::cluster::v3::Cluster& cluster, ClusterManager& cm, Outlier::EventLoggerSharedPtr outlier_event_logger, bool added_via_api) override; @@ -236,15 +239,17 @@ class ClusterManagerImpl : public ClusterManager, Logger::Loggablecluster_); + clusters_maps.active_clusters_.emplace(cluster.first, *cluster.second->cluster_); } - - return clusters_map; + for (auto& cluster : warming_clusters_) { + clusters_maps.warming_clusters_.emplace(cluster.first, *cluster.second->cluster_); + } + return clusters_maps; } + const ClusterSet& primaryClusters() override { return primary_clusters_; } ThreadLocalCluster* get(absl::string_view cluster) override; @@ -429,6 +434,8 @@ class ClusterManagerImpl : public ClusterManager, Logger::Loggable thread_local_clusters_; + ClusterConnectivityState cluster_manager_state_; + // These maps are owned by the ThreadLocalClusterManagerImpl instead of the ClusterEntry // to prevent lifetime/ownership issues when a cluster is dynamically removed. absl::node_hash_map host_http_conn_pool_map_; @@ -543,8 +550,8 @@ class ClusterManagerImpl : public ClusterManager, Logger::Loggable prefetch_pool); + static void maybePrefetch(ThreadLocalClusterManagerImpl::ClusterEntryPtr& cluster_entry, + std::function prefetch_pool); ClusterManagerFactory& factory_; Runtime::Loader& runtime_; diff --git a/source/common/upstream/load_balancer_impl.cc b/source/common/upstream/load_balancer_impl.cc index f12085eea88d1..da89730843f97 100644 --- a/source/common/upstream/load_balancer_impl.cc +++ b/source/common/upstream/load_balancer_impl.cc @@ -778,6 +778,7 @@ HostConstSharedPtr EdfLoadBalancerBase::peekAnotherHost(LoadBalancerContext* con if (!hosts_source) { return nullptr; } + auto scheduler_it = scheduler_.find(*hosts_source); // We should always have a scheduler for any return value from // hostSourceToUse() via the construction in refresh(); diff --git a/source/common/upstream/load_stats_reporter.cc b/source/common/upstream/load_stats_reporter.cc index fa5697e86fbd3..b7ff8e94b7c34 100644 --- a/source/common/upstream/load_stats_reporter.cc +++ b/source/common/upstream/load_stats_reporter.cc @@ -62,11 +62,11 @@ void LoadStatsReporter::sendLoadStatsRequest() { // added to the cluster manager. When we get the notification, we record the current time in // clusters_ as the start time for the load reporting window for that cluster. request_.mutable_cluster_stats()->Clear(); + auto all_clusters = cm_.clusters(); for (const auto& cluster_name_and_timestamp : clusters_) { const std::string& cluster_name = cluster_name_and_timestamp.first; - auto cluster_info_map = cm_.clusters(); - auto it = cluster_info_map.find(cluster_name); - if (it == cluster_info_map.end()) { + auto it = all_clusters.active_clusters_.find(cluster_name); + if (it == all_clusters.active_clusters_.end()) { ENVOY_LOG(debug, "Cluster {} does not exist", cluster_name); continue; } @@ -154,7 +154,8 @@ void LoadStatsReporter::startLoadReportPeriod() { // converge. absl::node_hash_map existing_clusters; if (message_->send_all_clusters()) { - for (const auto& p : cm_.clusters()) { + auto cluster_info_map = cm_.clusters(); + for (const auto& p : cluster_info_map.active_clusters_) { const std::string& cluster_name = p.first; if (clusters_.count(cluster_name) > 0) { existing_clusters.emplace(cluster_name, clusters_[cluster_name]); @@ -173,9 +174,10 @@ void LoadStatsReporter::startLoadReportPeriod() { clusters_.emplace(cluster_name, existing_clusters.count(cluster_name) > 0 ? existing_clusters[cluster_name] : time_source_.monotonicTime().time_since_epoch()); + // TODO(lambdai): Move the clusters() call out of this lambda. auto cluster_info_map = cm_.clusters(); - auto it = cluster_info_map.find(cluster_name); - if (it == cluster_info_map.end()) { + auto it = cluster_info_map.active_clusters_.find(cluster_name); + if (it == cluster_info_map.active_clusters_.end()) { return; } // Don't reset stats for existing tracked clusters. @@ -193,7 +195,8 @@ void LoadStatsReporter::startLoadReportPeriod() { cluster.info()->loadReportStats().upstream_rq_dropped_.latch(); }; if (message_->send_all_clusters()) { - for (const auto& p : cm_.clusters()) { + auto cluster_info_map = cm_.clusters(); + for (const auto& p : cluster_info_map.active_clusters_) { const std::string& cluster_name = p.first; handle_cluster_func(cluster_name); } diff --git a/source/extensions/all_extensions.bzl b/source/extensions/all_extensions.bzl index 5fde35e3c92bb..e6034c852503a 100644 --- a/source/extensions/all_extensions.bzl +++ b/source/extensions/all_extensions.bzl @@ -8,10 +8,15 @@ _required_extensions = { "envoy.transport_sockets.tls": "//source/extensions/transport_sockets/tls:config", } +_kill_request_http_filter = "envoy.filters.http.kill_request" + # Return all extensions to be compiled into Envoy. def envoy_all_extensions(denylist = []): all_extensions = dicts.add(_required_extensions, EXTENSIONS) + # !!! kill_request filter should not be built into Envoy. !!! + denylist = denylist + [_kill_request_http_filter] + # These extensions can be removed on a site specific basis. return [v for k, v in all_extensions.items() if not k in denylist] @@ -37,7 +42,8 @@ _http_filter_prefix = "envoy.filters.http" def envoy_all_http_filters(): all_extensions = dicts.add(_required_extensions, EXTENSIONS) - return [v for k, v in all_extensions.items() if k.startswith(_http_filter_prefix)] + # !!! kill_request filter should not be built into Envoy. !!! + return [v for k, v in all_extensions.items() if k.startswith(_http_filter_prefix) and k != _kill_request_http_filter] # All network-layer filters are extensions with names that have the following prefix. _network_filter_prefix = "envoy.filters.network" diff --git a/source/extensions/common/redis/cluster_refresh_manager_impl.cc b/source/extensions/common/redis/cluster_refresh_manager_impl.cc index 8da52d96665ca..c3caa96d9eec3 100644 --- a/source/extensions/common/redis/cluster_refresh_manager_impl.cc +++ b/source/extensions/common/redis/cluster_refresh_manager_impl.cc @@ -133,9 +133,9 @@ bool ClusterRefreshManagerImpl::onEvent(const std::string& cluster_name, EventTy if (post_callback) { main_thread_dispatcher_.post([this, cluster_name, info]() { // Ensure that cluster is still active before calling callback. - auto map = cm_.clusters(); - auto it = map.find(cluster_name); - if (it != map.end()) { + auto maps = cm_.clusters(); + auto it = maps.active_clusters_.find(cluster_name); + if (it != maps.active_clusters_.end()) { info->cb_(); } }); diff --git a/source/extensions/common/wasm/BUILD b/source/extensions/common/wasm/BUILD index e2a03e72fc0f4..0f351b56b5bd7 100644 --- a/source/extensions/common/wasm/BUILD +++ b/source/extensions/common/wasm/BUILD @@ -16,6 +16,16 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "wasm_runtime_factory_interface", + hdrs = [ + "wasm_runtime_factory.h", + ], + deps = [ + "@proxy_wasm_cpp_host//:include", + ], +) + # NB: Used to break the circular dependency between wasm_lib and null_plugin_lib. envoy_cc_library( name = "wasm_hdr", @@ -86,6 +96,7 @@ envoy_cc_library( deps = [ ":wasm_hdr", ":wasm_interoperation_lib", + ":wasm_runtime_factory_interface", "//external:abseil_base", "//external:abseil_node_hash_map", "//include/envoy/server:lifecycle_notifier_interface", @@ -107,7 +118,8 @@ envoy_cc_library( "@com_google_cel_cpp//eval/public:cel_value", "@com_google_cel_cpp//eval/public:value_export_util", "@envoy_api//envoy/extensions/wasm/v3:pkg_cc_proto", - "@proxy_wasm_cpp_host//:lib", + "@proxy_wasm_cpp_host//:common_lib", + "@proxy_wasm_cpp_host//:null_lib", ] + select( { "//bazel:windows_x86_64": [], diff --git a/source/extensions/common/wasm/context.cc b/source/extensions/common/wasm/context.cc index 006e7648c0e6c..250d523cc78cf 100644 --- a/source/extensions/common/wasm/context.cc +++ b/source/extensions/common/wasm/context.cc @@ -858,11 +858,7 @@ BufferInterface* Context::getBuffer(WasmBufferType type) { void Context::onDownstreamConnectionClose(CloseType close_type) { ContextBase::onDownstreamConnectionClose(close_type); downstream_closed_ = true; - // Call close on TCP connection, if upstream connection closed or there was a failure seen in - // this connection. - if (upstream_closed_ || getRequestStreamInfo()->hasAnyResponseFlag()) { - onCloseTCP(); - } + onCloseTCP(); } void Context::onUpstreamConnectionClose(CloseType close_type) { diff --git a/source/extensions/common/wasm/wasm_extension.h b/source/extensions/common/wasm/wasm_extension.h index 22ae373162f27..1061fd1cf1cf2 100644 --- a/source/extensions/common/wasm/wasm_extension.h +++ b/source/extensions/common/wasm/wasm_extension.h @@ -77,8 +77,8 @@ class WasmExtension : Logger::Loggable { virtual void onEvent(WasmEvent event, const PluginSharedPtr& plugin) = 0; virtual void onRemoteCacheEntriesChanged(int remote_cache_entries) = 0; virtual void createStats(const Stats::ScopeSharedPtr& scope, const PluginSharedPtr& plugin) - EXCLUSIVE_LOCKS_REQUIRED(mutex_) = 0; - virtual void resetStats() EXCLUSIVE_LOCKS_REQUIRED(mutex_) = 0; // Delete stats pointers + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_) = 0; + virtual void resetStats() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_) = 0; // Delete stats pointers // NB: the Scope can become invalid if, for example, the owning FilterChain is deleted. When that // happens the stats must be recreated. This hook verifies the Scope of any existing stats and if diff --git a/source/extensions/common/wasm/wasm_runtime_factory.h b/source/extensions/common/wasm/wasm_runtime_factory.h new file mode 100644 index 0000000000000..d0d589705f91e --- /dev/null +++ b/source/extensions/common/wasm/wasm_runtime_factory.h @@ -0,0 +1,29 @@ +#pragma once + +#include "envoy/common/pure.h" + +#include "absl/strings/string_view.h" +#include "include/proxy-wasm/wasm_vm.h" + +namespace Envoy { +namespace Extensions { +namespace Common { +namespace Wasm { + +using WasmVmPtr = std::unique_ptr; + +class WasmRuntimeFactory { +public: + virtual ~WasmRuntimeFactory() = default; + virtual WasmVmPtr createWasmVm() PURE; + + virtual absl::string_view name() PURE; + virtual absl::string_view shortName() PURE; + + std::string category() { return "envoy.wasm.runtime"; } +}; + +} // namespace Wasm +} // namespace Common +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/common/wasm/wasm_vm.cc b/source/extensions/common/wasm/wasm_vm.cc index 5b482e6bb8470..b7b8ec0c67349 100644 --- a/source/extensions/common/wasm/wasm_vm.cc +++ b/source/extensions/common/wasm/wasm_vm.cc @@ -6,21 +6,11 @@ #include "extensions/common/wasm/context.h" #include "extensions/common/wasm/ext/envoy_null_vm_wasm_api.h" #include "extensions/common/wasm/wasm_extension.h" +#include "extensions/common/wasm/wasm_runtime_factory.h" #include "extensions/common/wasm/well_known_names.h" -#include "include/proxy-wasm/null.h" #include "include/proxy-wasm/null_plugin.h" -#if defined(ENVOY_WASM_V8) -#include "include/proxy-wasm/v8.h" -#endif -#if defined(ENVOY_WASM_WAVM) -#include "include/proxy-wasm/wavm.h" -#endif -#if defined(ENVOY_WASM_WASMTIME) -#include "include/proxy-wasm/wasmtime.h" -#endif - using ContextBase = proxy_wasm::ContextBase; using Word = proxy_wasm::Word; @@ -70,36 +60,21 @@ WasmVmPtr createWasmVm(absl::string_view runtime, const Stats::ScopeSharedPtr& s ENVOY_LOG_TO_LOGGER(Envoy::Logger::Registry::getLog(Envoy::Logger::Id::wasm), warn, "Failed to create Wasm VM with unspecified runtime"); return nullptr; - } else if (runtime == WasmRuntimeNames::get().Null) { - auto wasm = proxy_wasm::createNullVm(); - wasm->integration() = getWasmExtension()->createEnvoyWasmVmIntegration(scope, runtime, "null"); - return wasm; -#if defined(ENVOY_WASM_V8) - } else if (runtime == WasmRuntimeNames::get().V8) { - auto wasm = proxy_wasm::createV8Vm(); - wasm->integration() = getWasmExtension()->createEnvoyWasmVmIntegration(scope, runtime, "v8"); - return wasm; -#endif -#if defined(ENVOY_WASM_WAVM) - } else if (runtime == WasmRuntimeNames::get().Wavm) { - auto wasm = proxy_wasm::createWavmVm(); - wasm->integration() = getWasmExtension()->createEnvoyWasmVmIntegration(scope, runtime, "wavm"); - return wasm; -#endif -#if defined(ENVOY_WASM_WASMTIME) - } else if (runtime == WasmRuntimeNames::get().Wasmtime) { - auto wasm = proxy_wasm::createWasmtimeVm(); - wasm->integration() = - getWasmExtension()->createEnvoyWasmVmIntegration(scope, runtime, "wasmtime"); - return wasm; -#endif - } else { + } + + auto runtime_factory = Registry::FactoryRegistry::getFactory(runtime); + if (runtime_factory == nullptr) { ENVOY_LOG_TO_LOGGER( Envoy::Logger::Registry::getLog(Envoy::Logger::Id::wasm), warn, "Failed to create Wasm VM using {} runtime. Envoy was compiled without support for it", runtime); return nullptr; } + + auto wasm = runtime_factory->createWasmVm(); + wasm->integration() = getWasmExtension()->createEnvoyWasmVmIntegration( + scope, runtime_factory->name(), runtime_factory->shortName()); + return wasm; } } // namespace Wasm diff --git a/source/extensions/extensions_build_config.bzl b/source/extensions/extensions_build_config.bzl index 664b561fb0d21..9530cc4c8192f 100644 --- a/source/extensions/extensions_build_config.bzl +++ b/source/extensions/extensions_build_config.bzl @@ -71,6 +71,7 @@ EXTENSIONS = { "envoy.filters.http.health_check": "//source/extensions/filters/http/health_check:config", "envoy.filters.http.ip_tagging": "//source/extensions/filters/http/ip_tagging:config", "envoy.filters.http.jwt_authn": "//source/extensions/filters/http/jwt_authn:config", + "envoy.filters.http.kill_request": "//source/extensions/filters/http/kill_request:kill_request_config", "envoy.filters.http.local_ratelimit": "//source/extensions/filters/http/local_ratelimit:config", "envoy.filters.http.lua": "//source/extensions/filters/http/lua:config", "envoy.filters.http.oauth2": "//source/extensions/filters/http/oauth2:config", @@ -214,8 +215,17 @@ EXTENSIONS = { # # Watchdog actions # + "envoy.watchdog.profile_action": "//source/extensions/watchdog/profile_action:config", + # + # WebAssembly runtimes + # + + "envoy.wasm.runtime.null": "//source/extensions/wasm_runtime/null:config", + "envoy.wasm.runtime.v8": "//source/extensions/wasm_runtime/v8:config", + "envoy.wasm.runtime.wavm": "//source/extensions/wasm_runtime/wavm:config", + "envoy.wasm.runtime.wasmtime": "//source/extensions/wasm_runtime/wasmtime:config", } # These can be changed to ["//visibility:public"], for downstream builds which diff --git a/source/extensions/fatal_actions/README.md b/source/extensions/fatal_actions/README.md new file mode 100644 index 0000000000000..d4ab098a4071a --- /dev/null +++ b/source/extensions/fatal_actions/README.md @@ -0,0 +1 @@ +Currently there are no fatal action extensions. diff --git a/source/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter.cc b/source/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter.cc index e2998a3f58661..d770b9feb51a9 100644 --- a/source/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter.cc +++ b/source/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter.cc @@ -188,6 +188,24 @@ JsonTranscoderConfig::JsonTranscoderConfig( } } + switch (proto_config.url_unescape_spec()) { + case envoy::extensions::filters::http::grpc_json_transcoder::v3::GrpcJsonTranscoder:: + ALL_CHARACTERS_EXCEPT_RESERVED: + pmb.SetUrlUnescapeSpec( + google::grpc::transcoding::UrlUnescapeSpec::kAllCharactersExceptReserved); + break; + case envoy::extensions::filters::http::grpc_json_transcoder::v3::GrpcJsonTranscoder:: + ALL_CHARACTERS_EXCEPT_SLASH: + pmb.SetUrlUnescapeSpec(google::grpc::transcoding::UrlUnescapeSpec::kAllCharactersExceptSlash); + break; + case envoy::extensions::filters::http::grpc_json_transcoder::v3::GrpcJsonTranscoder:: + ALL_CHARACTERS: + pmb.SetUrlUnescapeSpec(google::grpc::transcoding::UrlUnescapeSpec::kAllCharacters); + break; + default: + NOT_REACHED_GCOVR_EXCL_LINE; + } + path_matcher_ = pmb.Build(); const auto& print_config = proto_config.print_options(); diff --git a/source/extensions/filters/http/jwt_authn/authenticator.cc b/source/extensions/filters/http/jwt_authn/authenticator.cc index 1b73eeaf08b22..cf447f68bdaac 100644 --- a/source/extensions/filters/http/jwt_authn/authenticator.cc +++ b/source/extensions/filters/http/jwt_authn/authenticator.cc @@ -141,7 +141,7 @@ void AuthenticatorImpl::startVerify() { jwt_ = std::make_unique<::google::jwt_verify::Jwt>(); ENVOY_LOG(debug, "{}: Parse Jwt {}", name(), curr_token_->token()); - const Status status = jwt_->parseFromString(curr_token_->token()); + Status status = jwt_->parseFromString(curr_token_->token()); if (status != Status::Ok) { doneWithStatus(status); return; @@ -163,33 +163,23 @@ void AuthenticatorImpl::startVerify() { } } - // TODO(qiwzhang): Cross-platform-wise the below unix_timestamp code is wrong as the - // epoch is not guaranteed to be defined as the unix epoch. We should use - // the abseil time functionality instead or use the jwt_verify_lib to check - // the validity of a JWT. - // Check "exp" claim. - const uint64_t unix_timestamp = - std::chrono::duration_cast(timeSource().systemTime().time_since_epoch()) - .count(); - // If the nbf claim does *not* appear in the JWT, then the nbf field is defaulted - // to 0. - if (jwt_->nbf_ > unix_timestamp) { - doneWithStatus(Status::JwtNotYetValid); - return; - } - // If the exp claim does *not* appear in the JWT then the exp field is defaulted - // to 0. - if (jwt_->exp_ > 0 && jwt_->exp_ < unix_timestamp) { - doneWithStatus(Status::JwtExpired); - return; - } - // Check the issuer is configured or not. jwks_data_ = provider_ ? jwks_cache_.findByProvider(provider_.value()) : jwks_cache_.findByIssuer(jwt_->iss_); // isIssuerSpecified() check already make sure the issuer is in the cache. ASSERT(jwks_data_ != nullptr); + // Default is 60 seconds + uint64_t clock_skew_seconds = ::google::jwt_verify::kClockSkewInSecond; + if (jwks_data_->getJwtProvider().clock_skew_seconds() > 0) { + clock_skew_seconds = jwks_data_->getJwtProvider().clock_skew_seconds(); + } + status = jwt_->verifyTimeConstraint(absl::ToUnixSeconds(absl::Now()), clock_skew_seconds); + if (status != Status::Ok) { + doneWithStatus(status); + return; + } + // Check if audience is allowed bool is_allowed = check_audience_ ? check_audience_->areAudiencesAllowed(jwt_->audiences_) : jwks_data_->areAudiencesAllowed(jwt_->audiences_); @@ -247,7 +237,8 @@ void AuthenticatorImpl::onDestroy() { // Verify with a specific public key. void AuthenticatorImpl::verifyKey() { - const Status status = ::google::jwt_verify::verifyJwt(*jwt_, *jwks_data_->getJwksObj()); + const Status status = + ::google::jwt_verify::verifyJwtWithoutTimeChecking(*jwt_, *jwks_data_->getJwksObj()); if (status != Status::Ok) { doneWithStatus(status); return; diff --git a/source/extensions/filters/http/kill_request/BUILD b/source/extensions/filters/http/kill_request/BUILD new file mode 100644 index 0000000000000..aa37e09f6a70a --- /dev/null +++ b/source/extensions/filters/http/kill_request/BUILD @@ -0,0 +1,40 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_extension", + "envoy_cc_library", + "envoy_extension_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_extension_package() + +envoy_cc_library( + name = "kill_request_filter_lib", + srcs = ["kill_request_filter.cc"], + hdrs = ["kill_request_filter.h"], + deps = [ + "//include/envoy/common:random_generator_interface", + "//include/envoy/http:filter_interface", + "//include/envoy/http:header_map_interface", + "//source/common/http:header_map_lib", + "//source/common/http:header_utility_lib", + "//source/common/http:headers_lib", + "//source/common/protobuf:utility_lib", + "@envoy_api//envoy/extensions/filters/http/kill_request/v3:pkg_cc_proto", + ], +) + +envoy_cc_extension( + name = "kill_request_config", + srcs = ["kill_request_config.cc"], + hdrs = ["kill_request_config.h"], + security_posture = "robust_to_untrusted_downstream", + deps = [ + "//include/envoy/registry", + "//source/extensions/filters/http:well_known_names", + "//source/extensions/filters/http/common:factory_base_lib", + "//source/extensions/filters/http/kill_request:kill_request_filter_lib", + "@envoy_api//envoy/extensions/filters/http/kill_request/v3:pkg_cc_proto", + ], +) diff --git a/source/extensions/filters/http/kill_request/kill_request_config.cc b/source/extensions/filters/http/kill_request/kill_request_config.cc new file mode 100644 index 0000000000000..59a9ec7d44261 --- /dev/null +++ b/source/extensions/filters/http/kill_request/kill_request_config.cc @@ -0,0 +1,31 @@ +#include "extensions/filters/http/kill_request/kill_request_config.h" + +#include "envoy/extensions/filters/http/kill_request/v3/kill_request.pb.h" +#include "envoy/extensions/filters/http/kill_request/v3/kill_request.pb.validate.h" +#include "envoy/registry/registry.h" + +#include "extensions/filters/http/kill_request/kill_request_filter.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace KillRequest { + +Http::FilterFactoryCb KillRequestFilterFactory::createFilterFactoryFromProtoTyped( + const envoy::extensions::filters::http::kill_request::v3::KillRequest& proto_config, + const std::string&, Server::Configuration::FactoryContext& context) { + return [proto_config, &context](Http::FilterChainFactoryCallbacks& callbacks) -> void { + callbacks.addStreamFilter( + std::make_shared(proto_config, context.api().randomGenerator())); + }; +} + +/** + * Static registration for the KillRequest filter. @see RegisterFactory. + */ +REGISTER_FACTORY(KillRequestFilterFactory, Server::Configuration::NamedHttpFilterConfigFactory); + +} // namespace KillRequest +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/http/kill_request/kill_request_config.h b/source/extensions/filters/http/kill_request/kill_request_config.h new file mode 100644 index 0000000000000..d7a6120e6b824 --- /dev/null +++ b/source/extensions/filters/http/kill_request/kill_request_config.h @@ -0,0 +1,31 @@ +#pragma once + +#include "envoy/extensions/filters/http/kill_request/v3/kill_request.pb.h" +#include "envoy/extensions/filters/http/kill_request/v3/kill_request.pb.validate.h" + +#include "extensions/filters/http/common/factory_base.h" +#include "extensions/filters/http/well_known_names.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace KillRequest { + +/** + * Config registration for KillRequestFilter. @see NamedHttpFilterConfigFactory. + */ +class KillRequestFilterFactory + : public Common::FactoryBase { +public: + KillRequestFilterFactory() : FactoryBase(HttpFilterNames::get().KillRequest) {} + +private: + Http::FilterFactoryCb createFilterFactoryFromProtoTyped( + const envoy::extensions::filters::http::kill_request::v3::KillRequest& proto_config, + const std::string& stats_prefix, Server::Configuration::FactoryContext& context) override; +}; + +} // namespace KillRequest +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/http/kill_request/kill_request_filter.cc b/source/extensions/filters/http/kill_request/kill_request_filter.cc new file mode 100644 index 0000000000000..9c5c825a786a1 --- /dev/null +++ b/source/extensions/filters/http/kill_request/kill_request_filter.cc @@ -0,0 +1,38 @@ +#include "extensions/filters/http/kill_request/kill_request_filter.h" + +#include + +#include "common/protobuf/utility.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace KillRequest { + +bool KillRequestFilter::isKillRequestEnabled() { + return ProtobufPercentHelper::evaluateFractionalPercent(kill_request_.probability(), + random_generator_.random()); +} + +Http::FilterHeadersStatus KillRequestFilter::decodeHeaders(Http::RequestHeaderMap& headers, bool) { + const auto kill_request_header = headers.get(KillRequestHeaders::get().KillRequest); + bool is_kill_request = false; + // This is an implicitly untrusted header, so per the API documentation only + // the first value is used. + if (kill_request_header.empty() || + !absl::SimpleAtob(kill_request_header[0]->value().getStringView(), &is_kill_request)) { + return Http::FilterHeadersStatus::Continue; + } + + if (is_kill_request && isKillRequestEnabled()) { + // Crash Envoy. + raise(SIGABRT); + } + + return Http::FilterHeadersStatus::Continue; +} + +} // namespace KillRequest +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/http/kill_request/kill_request_filter.h b/source/extensions/filters/http/kill_request/kill_request_filter.h new file mode 100644 index 0000000000000..82243f819b7a8 --- /dev/null +++ b/source/extensions/filters/http/kill_request/kill_request_filter.h @@ -0,0 +1,92 @@ +#pragma once + +#include + +#include "envoy/common/random_generator.h" +#include "envoy/extensions/filters/http/kill_request/v3/kill_request.pb.h" +#include "envoy/http/filter.h" +#include "envoy/http/header_map.h" + +#include "common/http/headers.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace KillRequest { + +class KillRequestHeaderNameValues { +public: + const char* prefix() const { return ThreadSafeSingleton::get().prefix(); } + + const Http::LowerCaseString KillRequest{absl::StrCat(prefix(), "-kill-request")}; +}; + +using KillRequestHeaders = ConstSingleton; + +/** + * A filter that will crash Envoy if IsKillRequestEnabled() return true and + * incoming request contains HTTP KillRequest header with values in + * one of (case-insensitive) ["true", "t", "yes", "y", "1"]. + */ +class KillRequestFilter : public Http::StreamFilter, Logger::Loggable { +public: + KillRequestFilter( + const envoy::extensions::filters::http::kill_request::v3::KillRequest& kill_request, + Random::RandomGenerator& random_generator) + : kill_request_(kill_request), random_generator_(random_generator) {} + + ~KillRequestFilter() override = default; + + // Http::StreamFilterBase + void onDestroy() override {} + + // Http::StreamDecoderFilter + Http::FilterHeadersStatus decodeHeaders(Http::RequestHeaderMap& headers, + bool end_stream) override; + + Http::FilterDataStatus decodeData(Buffer::Instance&, bool) override { + return Http::FilterDataStatus::Continue; + } + + Http::FilterTrailersStatus decodeTrailers(Http::RequestTrailerMap&) override { + return Http::FilterTrailersStatus::Continue; + } + + void setDecoderFilterCallbacks(Http::StreamDecoderFilterCallbacks&) override {} + + // Http::StreamEncoderFilter + Http::FilterHeadersStatus encode100ContinueHeaders(Http::ResponseHeaderMap&) override { + return Http::FilterHeadersStatus::Continue; + } + + Http::FilterHeadersStatus encodeHeaders(Http::ResponseHeaderMap&, bool) override { + return Http::FilterHeadersStatus::Continue; + } + + Http::FilterDataStatus encodeData(Buffer::Instance&, bool) override { + return Http::FilterDataStatus::Continue; + } + + Http::FilterTrailersStatus encodeTrailers(Http::ResponseTrailerMap&) override { + return Http::FilterTrailersStatus::Continue; + } + + Http::FilterMetadataStatus encodeMetadata(Http::MetadataMap&) override { + return Http::FilterMetadataStatus::Continue; + } + + void setEncoderFilterCallbacks(Http::StreamEncoderFilterCallbacks&) override {} + +private: + // Return a random boolean value, with probability configured in KillRequest + // equaling true. + bool isKillRequestEnabled(); + + const envoy::extensions::filters::http::kill_request::v3::KillRequest kill_request_; + Random::RandomGenerator& random_generator_; +}; + +} // namespace KillRequest +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/http/lua/wrappers.h b/source/extensions/filters/http/lua/wrappers.h index bf19843dd8d19..ba4170dbfaaa9 100644 --- a/source/extensions/filters/http/lua/wrappers.h +++ b/source/extensions/filters/http/lua/wrappers.h @@ -222,7 +222,10 @@ class StreamInfoWrapper : public Filters::Common::Lua::BaseLuaObject dynamic_metadata_wrapper_; diff --git a/source/extensions/filters/http/well_known_names.h b/source/extensions/filters/http/well_known_names.h index e869e3fc9bbd3..6aade9fadbd82 100644 --- a/source/extensions/filters/http/well_known_names.h +++ b/source/extensions/filters/http/well_known_names.h @@ -82,6 +82,8 @@ class HttpFilterNameValues { const std::string AwsLambda = "envoy.filters.http.aws_lambda"; // OAuth filter const std::string OAuth = "envoy.filters.http.oauth2"; + // KillRequest filter + const std::string KillRequest = "envoy.filters.http.kill_request"; }; using HttpFilterNames = ConstSingleton; diff --git a/source/extensions/filters/network/mongo_proxy/proxy.cc b/source/extensions/filters/network/mongo_proxy/proxy.cc index b8ee760c910b7..789d6e8df91d0 100644 --- a/source/extensions/filters/network/mongo_proxy/proxy.cc +++ b/source/extensions/filters/network/mongo_proxy/proxy.cc @@ -366,11 +366,11 @@ void ProxyFilter::onEvent(Network::ConnectionEvent event) { } if (event == Network::ConnectionEvent::RemoteClose && !active_query_list_.empty()) { - stats_.cx_destroy_local_with_active_rq_.inc(); + stats_.cx_destroy_remote_with_active_rq_.inc(); } if (event == Network::ConnectionEvent::LocalClose && !active_query_list_.empty()) { - stats_.cx_destroy_remote_with_active_rq_.inc(); + stats_.cx_destroy_local_with_active_rq_.inc(); } } diff --git a/source/extensions/quic_listeners/quiche/BUILD b/source/extensions/quic_listeners/quiche/BUILD index 29eb78d155e11..a90cfde6ddc66 100644 --- a/source/extensions/quic_listeners/quiche/BUILD +++ b/source/extensions/quic_listeners/quiche/BUILD @@ -212,6 +212,7 @@ envoy_cc_library( "//source/common/buffer:buffer_lib", "//source/common/common:assert_lib", "//source/common/http:header_map_lib", + "//source/common/http:header_utility_lib", "//source/extensions/quic_listeners/quiche/platform:quic_platform_mem_slice_storage_impl_lib", "@com_googlesource_quiche//:quic_core_http_client_lib", ], diff --git a/source/extensions/quic_listeners/quiche/active_quic_listener.cc b/source/extensions/quic_listeners/quiche/active_quic_listener.cc index f4808adc52b0a..86bb75a2ed51d 100644 --- a/source/extensions/quic_listeners/quiche/active_quic_listener.cc +++ b/source/extensions/quic_listeners/quiche/active_quic_listener.cc @@ -55,7 +55,7 @@ ActiveQuicListener::ActiveQuicListener( quic::QuicRandom* const random = quic::QuicRandom::GetInstance(); random->RandBytes(random_seed_, sizeof(random_seed_)); crypto_config_ = std::make_unique( - quiche::QuicheStringPiece(reinterpret_cast(random_seed_), sizeof(random_seed_)), + absl::string_view(reinterpret_cast(random_seed_), sizeof(random_seed_)), quic::QuicRandom::GetInstance(), std::make_unique(listen_socket_, listener_config.filterChainManager(), stats_), @@ -110,11 +110,11 @@ void ActiveQuicListener::onDataWorker(Network::UdpRecvData&& data) { quic::QuicTime::Delta::FromMicroseconds(std::chrono::duration_cast( data.receive_time_.time_since_epoch()) .count()); - ASSERT(data.buffer_->getRawSlices().size() == 1); - Buffer::RawSliceVector slices = data.buffer_->getRawSlices(/*max_slices=*/1); + Buffer::RawSlice slice = data.buffer_->frontSlice(); + ASSERT(data.buffer_->length() == slice.len_); // TODO(danzh): pass in TTL and UDP header. - quic::QuicReceivedPacket packet(reinterpret_cast(slices[0].mem_), slices[0].len_, - timestamp, /*owns_buffer=*/false, /*ttl=*/0, /*ttl_valid=*/false, + quic::QuicReceivedPacket packet(reinterpret_cast(slice.mem_), slice.len_, timestamp, + /*owns_buffer=*/false, /*ttl=*/0, /*ttl_valid=*/false, /*packet_headers=*/nullptr, /*headers_length=*/0, /*owns_header_buffer*/ false); quic_dispatcher_->ProcessPacket(self_address, peer_address, packet); diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_client_connection.cc b/source/extensions/quic_listeners/quiche/envoy_quic_client_connection.cc index b92a77147e911..63783ee08e355 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_client_connection.cc +++ b/source/extensions/quic_listeners/quiche/envoy_quic_client_connection.cc @@ -43,7 +43,7 @@ EnvoyQuicClientConnection::EnvoyQuicClientConnection( const quic::ParsedQuicVersionVector& supported_versions, Event::Dispatcher& dispatcher, Network::ConnectionSocketPtr&& connection_socket) : EnvoyQuicConnection( - server_connection_id, + server_connection_id, quic::QuicSocketAddress(), envoyIpAddressToQuicSocketAddress(connection_socket->remoteAddress()->ip()), helper, alarm_factory, writer, owns_writer, quic::Perspective::IS_CLIENT, supported_versions, std::move(connection_socket)), @@ -62,9 +62,9 @@ void EnvoyQuicClientConnection::processPacket( std::chrono::duration_cast(receive_time.time_since_epoch()) .count()); ASSERT(buffer->getRawSlices().size() == 1); - Buffer::RawSliceVector slices = buffer->getRawSlices(/*max_slices=*/1); - quic::QuicReceivedPacket packet(reinterpret_cast(slices[0].mem_), slices[0].len_, - timestamp, /*owns_buffer=*/false, /*ttl=*/0, /*ttl_valid=*/false, + Buffer::RawSlice slice = buffer->frontSlice(); + quic::QuicReceivedPacket packet(reinterpret_cast(slice.mem_), slice.len_, timestamp, + /*owns_buffer=*/false, /*ttl=*/0, /*ttl_valid=*/false, /*packet_headers=*/nullptr, /*headers_length=*/0, /*owns_header_buffer*/ false); ProcessUdpPacket(envoyIpAddressToQuicSocketAddress(local_address->ip()), diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_client_stream.cc b/source/extensions/quic_listeners/quiche/envoy_quic_client_stream.cc index b52b411df7e75..79e442ea8628b 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_client_stream.cc +++ b/source/extensions/quic_listeners/quiche/envoy_quic_client_stream.cc @@ -20,6 +20,7 @@ #include "common/buffer/buffer_impl.h" #include "common/http/header_map_impl.h" +#include "common/http/header_utility.h" #include "common/common/assert.h" namespace Envoy { @@ -48,6 +49,10 @@ EnvoyQuicClientStream::EnvoyQuicClientStream(quic::PendingStream* pending, Http::Status EnvoyQuicClientStream::encodeHeaders(const Http::RequestHeaderMap& headers, bool end_stream) { + // Required headers must be present. This can only happen by some erroneous processing after the + // downstream codecs decode. + RETURN_IF_ERROR(Http::HeaderUtility::checkRequiredHeaders(headers)); + ENVOY_STREAM_LOG(debug, "encodeHeaders: (end_stream={}) {}.", *this, end_stream, headers); quic::QuicStream* writing_stream = quic::VersionUsesHttp3(transport_version()) @@ -67,6 +72,10 @@ Http::Status EnvoyQuicClientStream::encodeHeaders(const Http::RequestHeaderMap& void EnvoyQuicClientStream::encodeData(Buffer::Instance& data, bool end_stream) { ENVOY_STREAM_LOG(debug, "encodeData (end_stream={}) of {} bytes.", *this, end_stream, data.length()); + if (data.length() == 0 && !end_stream) { + return; + } + ASSERT(!local_end_stream_); local_end_stream_ = end_stream; // This is counting not serialized bytes in the send buffer. const uint64_t bytes_to_send_old = BufferedDataBytes(); @@ -107,8 +116,6 @@ void EnvoyQuicClientStream::encodeMetadata(const Http::MetadataMapVector& /*meta } void EnvoyQuicClientStream::resetStream(Http::StreamResetReason reason) { - // Higher layers expect calling resetStream() to immediately raise reset callbacks. - runResetCallbacks(reason); Reset(envoyResetReasonToQuicRstError(reason)); } @@ -125,13 +132,15 @@ void EnvoyQuicClientStream::switchStreamBlockState(bool should_block) { void EnvoyQuicClientStream::OnInitialHeadersComplete(bool fin, size_t frame_len, const quic::QuicHeaderList& header_list) { - quic::QuicSpdyStream::OnInitialHeadersComplete(fin, frame_len, header_list); if (rst_sent()) { return; } - ASSERT(headers_decompressed()); + quic::QuicSpdyStream::OnInitialHeadersComplete(fin, frame_len, header_list); + ASSERT(headers_decompressed() && !header_list.empty()); + response_decoder_->decodeHeaders( - quicHeadersToEnvoyHeaders(header_list), /*end_stream=*/fin); + quicHeadersToEnvoyHeaders(header_list), + /*end_stream=*/fin); if (fin) { end_stream_decoded_ = true; } @@ -160,18 +169,17 @@ void EnvoyQuicClientStream::OnBodyAvailable() { buffer->commit(&slice, 1); MarkConsumed(bytes_read); } + ASSERT(buffer->length() == 0 || !end_stream_decoded_); - // True if no trailer and FIN read. - bool finished_reading = IsDoneReading(); - bool empty_payload_with_fin = buffer->length() == 0 && fin_received(); + bool fin_read_and_no_trailers = IsDoneReading(); // If this call is triggered by an empty frame with FIN which is not from peer // but synthesized by stream itself upon receiving HEADERS with FIN or // TRAILERS, do not deliver end of stream here. Because either decodeHeaders // already delivered it or decodeTrailers will be called. - bool skip_decoding = empty_payload_with_fin && (end_stream_decoded_ || !finished_reading); + bool skip_decoding = (buffer->length() == 0 && !fin_read_and_no_trailers) || end_stream_decoded_; if (!skip_decoding) { - response_decoder_->decodeData(*buffer, finished_reading); - if (finished_reading) { + response_decoder_->decodeData(*buffer, fin_read_and_no_trailers); + if (fin_read_and_no_trailers) { end_stream_decoded_ = true; } } @@ -186,14 +194,10 @@ void EnvoyQuicClientStream::OnBodyAvailable() { return; } - if (!quic::VersionUsesHttp3(transport_version()) && !FinishedReadingTrailers()) { - // For Google QUIC implementation, trailers may arrived earlier and wait to - // be consumed after reading all the body. Consume it here. - // IETF QUIC shouldn't reach here because trailers are sent on same stream. - response_decoder_->decodeTrailers( - spdyHeaderBlockToEnvoyHeaders(received_trailers())); - MarkTrailersConsumed(); - } + // Trailers may arrived earlier and wait to be consumed after reading all the body. Consume it + // here. + maybeDecodeTrailers(); + OnFinRead(); in_decode_data_callstack_ = false; } @@ -202,20 +206,31 @@ void EnvoyQuicClientStream::OnTrailingHeadersComplete(bool fin, size_t frame_len const quic::QuicHeaderList& header_list) { quic::QuicSpdyStream::OnTrailingHeadersComplete(fin, frame_len, header_list); ASSERT(trailers_decompressed()); - if (session()->connection()->connected() && - (quic::VersionUsesHttp3(transport_version()) || sequencer()->IsClosed()) && - !FinishedReadingTrailers()) { - // Before QPack, trailers can arrive before body. Only decode trailers after finishing decoding - // body. + if (session()->connection()->connected() && !rst_sent()) { + maybeDecodeTrailers(); + } +} + +void EnvoyQuicClientStream::maybeDecodeTrailers() { + if (sequencer()->IsClosed() && !FinishedReadingTrailers()) { + ASSERT(!received_trailers().empty()); + // Only decode trailers after finishing decoding body. response_decoder_->decodeTrailers( spdyHeaderBlockToEnvoyHeaders(received_trailers())); + end_stream_decoded_ = true; MarkTrailersConsumed(); } } void EnvoyQuicClientStream::OnStreamReset(const quic::QuicRstStreamFrame& frame) { quic::QuicSpdyClientStream::OnStreamReset(frame); - runResetCallbacks(quicRstErrorToEnvoyResetReason(frame.error_code)); + runResetCallbacks(quicRstErrorToEnvoyRemoteResetReason(frame.error_code)); +} + +void EnvoyQuicClientStream::Reset(quic::QuicRstStreamErrorCode error) { + // Upper layers expect calling resetStream() to immediately raise reset callbacks. + runResetCallbacks(quicRstErrorToEnvoyLocalResetReason(error)); + quic::QuicSpdyClientStream::Reset(error); } void EnvoyQuicClientStream::OnConnectionClosed(quic::QuicErrorCode error, diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_client_stream.h b/source/extensions/quic_listeners/quiche/envoy_quic_client_stream.h index 2446fbb0c3e9b..2702b5f8fe790 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_client_stream.h +++ b/source/extensions/quic_listeners/quiche/envoy_quic_client_stream.h @@ -46,6 +46,7 @@ class EnvoyQuicClientStream : public quic::QuicSpdyClientStream, // quic::QuicSpdyStream void OnBodyAvailable() override; void OnStreamReset(const quic::QuicRstStreamFrame& frame) override; + void Reset(quic::QuicRstStreamErrorCode error) override; void OnClose() override; void OnCanWrite() override; // quic::Stream @@ -67,6 +68,9 @@ class EnvoyQuicClientStream : public quic::QuicSpdyClientStream, private: QuicFilterManagerConnectionImpl* filterManagerConnection(); + // Deliver awaiting trailers if body has been delivered. + void maybeDecodeTrailers(); + Http::ResponseDecoder* response_decoder_{nullptr}; }; diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_connection.cc b/source/extensions/quic_listeners/quiche/envoy_quic_connection.cc index dcc311a6eaac6..d813dfe4badb6 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_connection.cc +++ b/source/extensions/quic_listeners/quiche/envoy_quic_connection.cc @@ -6,6 +6,7 @@ namespace Envoy { namespace Quic { EnvoyQuicConnection::EnvoyQuicConnection(const quic::QuicConnectionId& server_connection_id, + quic::QuicSocketAddress initial_self_address, quic::QuicSocketAddress initial_peer_address, quic::QuicConnectionHelperInterface& helper, quic::QuicAlarmFactory& alarm_factory, @@ -13,8 +14,9 @@ EnvoyQuicConnection::EnvoyQuicConnection(const quic::QuicConnectionId& server_co quic::Perspective perspective, const quic::ParsedQuicVersionVector& supported_versions, Network::ConnectionSocketPtr&& connection_socket) - : quic::QuicConnection(server_connection_id, initial_peer_address, &helper, &alarm_factory, - writer, owns_writer, perspective, supported_versions), + : quic::QuicConnection(server_connection_id, initial_self_address, initial_peer_address, + &helper, &alarm_factory, writer, owns_writer, perspective, + supported_versions), connection_socket_(std::move(connection_socket)) {} EnvoyQuicConnection::~EnvoyQuicConnection() { connection_socket_->close(); } diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_connection.h b/source/extensions/quic_listeners/quiche/envoy_quic_connection.h index f4c8589d7118d..f8543bc938d79 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_connection.h +++ b/source/extensions/quic_listeners/quiche/envoy_quic_connection.h @@ -26,6 +26,7 @@ class EnvoyQuicConnection : public quic::QuicConnection, protected Logger::Loggable { public: EnvoyQuicConnection(const quic::QuicConnectionId& server_connection_id, + quic::QuicSocketAddress initial_self_address, quic::QuicSocketAddress initial_peer_address, quic::QuicConnectionHelperInterface& helper, quic::QuicAlarmFactory& alarm_factory, quic::QuicPacketWriter* writer, diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_dispatcher.cc b/source/extensions/quic_listeners/quiche/envoy_quic_dispatcher.cc index ba8f7f3a8239f..e6351f6436534 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_dispatcher.cc +++ b/source/extensions/quic_listeners/quiche/envoy_quic_dispatcher.cc @@ -48,11 +48,11 @@ void EnvoyQuicDispatcher::OnConnectionClosed(quic::QuicConnectionId connection_i } std::unique_ptr EnvoyQuicDispatcher::CreateQuicSession( - quic::QuicConnectionId server_connection_id, const quic::QuicSocketAddress& /*self_address*/, - const quic::QuicSocketAddress& peer_address, quiche::QuicheStringPiece /*alpn*/, + quic::QuicConnectionId server_connection_id, const quic::QuicSocketAddress& self_address, + const quic::QuicSocketAddress& peer_address, absl::string_view /*alpn*/, const quic::ParsedQuicVersion& version) { auto quic_connection = std::make_unique( - server_connection_id, peer_address, *helper(), *alarm_factory(), writer(), + server_connection_id, self_address, peer_address, *helper(), *alarm_factory(), writer(), /*owns_writer=*/false, quic::ParsedQuicVersionVector{version}, listen_socket_); auto quic_session = std::make_unique( config(), quic::ParsedQuicVersionVector{version}, std::move(quic_connection), this, diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_dispatcher.h b/source/extensions/quic_listeners/quiche/envoy_quic_dispatcher.h index 589ff53277062..d59307f415ecc 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_dispatcher.h +++ b/source/extensions/quic_listeners/quiche/envoy_quic_dispatcher.h @@ -62,7 +62,7 @@ class EnvoyQuicDispatcher : public quic::QuicDispatcher { std::unique_ptr CreateQuicSession(quic::QuicConnectionId server_connection_id, const quic::QuicSocketAddress& self_address, - const quic::QuicSocketAddress& peer_address, quiche::QuicheStringPiece alpn, + const quic::QuicSocketAddress& peer_address, absl::string_view alpn, const quic::ParsedQuicVersion& version) override; private: diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_proof_source.cc b/source/extensions/quic_listeners/quiche/envoy_quic_proof_source.cc index 1f65e4e7e6a0f..967765829a28d 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_proof_source.cc +++ b/source/extensions/quic_listeners/quiche/envoy_quic_proof_source.cc @@ -36,7 +36,7 @@ EnvoyQuicProofSource::GetCertChain(const quic::QuicSocketAddress& server_address void EnvoyQuicProofSource::signPayload( const quic::QuicSocketAddress& server_address, const quic::QuicSocketAddress& client_address, - const std::string& hostname, uint16_t signature_algorithm, quiche::QuicheStringPiece in, + const std::string& hostname, uint16_t signature_algorithm, absl::string_view in, std::unique_ptr callback) { CertConfigWithFilterChain res = getTlsCertConfigAndFilterChain(server_address, client_address, hostname); diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_proof_source.h b/source/extensions/quic_listeners/quiche/envoy_quic_proof_source.h index 6e1c74c9234c3..e22bf3465f49b 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_proof_source.h +++ b/source/extensions/quic_listeners/quiche/envoy_quic_proof_source.h @@ -28,7 +28,7 @@ class EnvoyQuicProofSource : public EnvoyQuicProofSourceBase { // quic::ProofSource void signPayload(const quic::QuicSocketAddress& server_address, const quic::QuicSocketAddress& client_address, const std::string& hostname, - uint16_t signature_algorithm, quiche::QuicheStringPiece in, + uint16_t signature_algorithm, absl::string_view in, std::unique_ptr callback) override; private: diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_proof_source_base.cc b/source/extensions/quic_listeners/quiche/envoy_quic_proof_source_base.cc index 2c82c04d901d8..9ad3cb07f4281 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_proof_source_base.cc +++ b/source/extensions/quic_listeners/quiche/envoy_quic_proof_source_base.cc @@ -21,7 +21,7 @@ void EnvoyQuicProofSourceBase::GetProof(const quic::QuicSocketAddress& server_ad const std::string& hostname, const std::string& server_config, quic::QuicTransportVersion /*transport_version*/, - quiche::QuicheStringPiece chlo_hash, + absl::string_view chlo_hash, std::unique_ptr callback) { quic::QuicReferenceCountedPointer chain = GetCertChain(server_address, client_address, hostname); @@ -68,13 +68,12 @@ void EnvoyQuicProofSourceBase::GetProof(const quic::QuicSocketAddress& server_ad auto signature_callback = std::make_unique(std::move(callback), chain); signPayload(server_address, client_address, hostname, sign_alg, - quiche::QuicheStringPiece(payload.get(), payload_size), - std::move(signature_callback)); + absl::string_view(payload.get(), payload_size), std::move(signature_callback)); } void EnvoyQuicProofSourceBase::ComputeTlsSignature( const quic::QuicSocketAddress& server_address, const quic::QuicSocketAddress& client_address, - const std::string& hostname, uint16_t signature_algorithm, quiche::QuicheStringPiece in, + const std::string& hostname, uint16_t signature_algorithm, absl::string_view in, std::unique_ptr callback) { signPayload(server_address, client_address, hostname, signature_algorithm, in, std::move(callback)); diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_proof_source_base.h b/source/extensions/quic_listeners/quiche/envoy_quic_proof_source_base.h index b7d76981e5193..a9e7e8c3f094d 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_proof_source_base.h +++ b/source/extensions/quic_listeners/quiche/envoy_quic_proof_source_base.h @@ -57,7 +57,7 @@ class EnvoyQuicProofSourceBase : public quic::ProofSource, void GetProof(const quic::QuicSocketAddress& server_address, const quic::QuicSocketAddress& client_address, const std::string& hostname, const std::string& server_config, quic::QuicTransportVersion /*transport_version*/, - quiche::QuicheStringPiece chlo_hash, + absl::string_view chlo_hash, std::unique_ptr callback) override; TicketCrypter* GetTicketCrypter() override { return nullptr; } @@ -65,14 +65,14 @@ class EnvoyQuicProofSourceBase : public quic::ProofSource, void ComputeTlsSignature(const quic::QuicSocketAddress& server_address, const quic::QuicSocketAddress& client_address, const std::string& hostname, uint16_t signature_algorithm, - quiche::QuicheStringPiece in, + absl::string_view in, std::unique_ptr callback) override; protected: virtual void signPayload(const quic::QuicSocketAddress& server_address, const quic::QuicSocketAddress& client_address, const std::string& hostname, uint16_t signature_algorithm, - quiche::QuicheStringPiece in, + absl::string_view in, std::unique_ptr callback) PURE; private: diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_proof_verifier_base.cc b/source/extensions/quic_listeners/quiche/envoy_quic_proof_verifier_base.cc index 229b3ab36628b..e375905295a3e 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_proof_verifier_base.cc +++ b/source/extensions/quic_listeners/quiche/envoy_quic_proof_verifier_base.cc @@ -58,8 +58,8 @@ bool EnvoyQuicProofVerifierBase::verifySignature(const std::string& server_confi *error_details = "QuicPacketWriter error."; return false; } - bool valid = cert_view->VerifySignature(quiche::QuicheStringPiece(payload.get(), payload_size), - signature, sign_alg); + bool valid = cert_view->VerifySignature(absl::string_view(payload.get(), payload_size), signature, + sign_alg); if (!valid) { *error_details = "Signature is not valid."; } diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_server_connection.cc b/source/extensions/quic_listeners/quiche/envoy_quic_server_connection.cc index b8fa94221f054..974c6c8ebc8cd 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_server_connection.cc +++ b/source/extensions/quic_listeners/quiche/envoy_quic_server_connection.cc @@ -11,11 +11,13 @@ namespace Quic { EnvoyQuicServerConnection::EnvoyQuicServerConnection( const quic::QuicConnectionId& server_connection_id, - quic::QuicSocketAddress initial_peer_address, quic::QuicConnectionHelperInterface& helper, - quic::QuicAlarmFactory& alarm_factory, quic::QuicPacketWriter* writer, bool owns_writer, + quic::QuicSocketAddress initial_self_address, quic::QuicSocketAddress initial_peer_address, + quic::QuicConnectionHelperInterface& helper, quic::QuicAlarmFactory& alarm_factory, + quic::QuicPacketWriter* writer, bool owns_writer, const quic::ParsedQuicVersionVector& supported_versions, Network::Socket& listen_socket) - : EnvoyQuicConnection(server_connection_id, initial_peer_address, helper, alarm_factory, writer, - owns_writer, quic::Perspective::IS_SERVER, supported_versions, + : EnvoyQuicConnection(server_connection_id, initial_self_address, initial_peer_address, helper, + alarm_factory, writer, owns_writer, quic::Perspective::IS_SERVER, + supported_versions, std::make_unique( // Wraps the real IoHandle instance so that if the connection socket // gets closed, the real IoHandle won't be affected. diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_server_connection.h b/source/extensions/quic_listeners/quiche/envoy_quic_server_connection.h index 7b7fac05e9257..7625fad02d0ba 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_server_connection.h +++ b/source/extensions/quic_listeners/quiche/envoy_quic_server_connection.h @@ -10,6 +10,7 @@ namespace Quic { class EnvoyQuicServerConnection : public EnvoyQuicConnection { public: EnvoyQuicServerConnection(const quic::QuicConnectionId& server_connection_id, + quic::QuicSocketAddress initial_self_address, quic::QuicSocketAddress initial_peer_address, quic::QuicConnectionHelperInterface& helper, quic::QuicAlarmFactory& alarm_factory, quic::QuicPacketWriter* writer, diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_server_stream.cc b/source/extensions/quic_listeners/quiche/envoy_quic_server_stream.cc index d5e5726bf3693..c7d25b8d47da9 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_server_stream.cc +++ b/source/extensions/quic_listeners/quiche/envoy_quic_server_stream.cc @@ -84,6 +84,10 @@ void EnvoyQuicServerStream::encodeHeaders(const Http::ResponseHeaderMap& headers void EnvoyQuicServerStream::encodeData(Buffer::Instance& data, bool end_stream) { ENVOY_STREAM_LOG(debug, "encodeData (end_stream={}) of {} bytes.", *this, end_stream, data.length()); + if (data.length() == 0 && !end_stream) { + return; + } + ASSERT(!local_end_stream_); local_end_stream_ = end_stream; // This is counting not serialized bytes in the send buffer. const uint64_t bytes_to_send_old = BufferedDataBytes(); @@ -121,8 +125,6 @@ void EnvoyQuicServerStream::encodeMetadata(const Http::MetadataMapVector& /*meta } void EnvoyQuicServerStream::resetStream(Http::StreamResetReason reason) { - // Upper layers expect calling resetStream() to immediately raise reset callbacks. - runResetCallbacks(reason); if (local_end_stream_ && !reading_stopped()) { // This is after 200 early response. Reset with QUIC_STREAM_NO_ERROR instead // of propagating original reset reason. In QUICHE if a stream stops reading @@ -146,10 +148,17 @@ void EnvoyQuicServerStream::switchStreamBlockState(bool should_block) { void EnvoyQuicServerStream::OnInitialHeadersComplete(bool fin, size_t frame_len, const quic::QuicHeaderList& header_list) { + // TODO(danzh) Fix in QUICHE. If the stream has been reset in the call stack, + // OnInitialHeadersComplete() shouldn't be called. + if (rst_sent()) { + return; + } quic::QuicSpdyServerStreamBase::OnInitialHeadersComplete(fin, frame_len, header_list); - ASSERT(headers_decompressed()); + ASSERT(headers_decompressed() && !header_list.empty()); + request_decoder_->decodeHeaders( - quicHeadersToEnvoyHeaders(header_list), /*end_stream=*/fin); + quicHeadersToEnvoyHeaders(header_list), + /*end_stream=*/fin); if (fin) { end_stream_decoded_ = true; } @@ -179,17 +188,15 @@ void EnvoyQuicServerStream::OnBodyAvailable() { MarkConsumed(bytes_read); } - // True if no trailer and FIN read. - bool finished_reading = IsDoneReading(); - bool empty_payload_with_fin = buffer->length() == 0 && fin_received(); + bool fin_read_and_no_trailers = IsDoneReading(); // If this call is triggered by an empty frame with FIN which is not from peer // but synthesized by stream itself upon receiving HEADERS with FIN or // TRAILERS, do not deliver end of stream here. Because either decodeHeaders // already delivered it or decodeTrailers will be called. - bool skip_decoding = empty_payload_with_fin && (end_stream_decoded_ || !finished_reading); + bool skip_decoding = (buffer->length() == 0 && !fin_read_and_no_trailers) || end_stream_decoded_; if (!skip_decoding) { - request_decoder_->decodeData(*buffer, finished_reading); - if (finished_reading) { + request_decoder_->decodeData(*buffer, fin_read_and_no_trailers); + if (fin_read_and_no_trailers) { end_stream_decoded_ = true; } } @@ -204,14 +211,10 @@ void EnvoyQuicServerStream::OnBodyAvailable() { return; } - if (!quic::VersionUsesHttp3(transport_version()) && !FinishedReadingTrailers()) { - // For Google QUIC implementation, trailers may arrived earlier and wait to - // be consumed after reading all the body. Consume it here. - // IETF QUIC shouldn't reach here because trailers are sent on same stream. - request_decoder_->decodeTrailers( - spdyHeaderBlockToEnvoyHeaders(received_trailers())); - MarkTrailersConsumed(); - } + // Trailers may arrived earlier and wait to be consumed after reading all the body. Consume it + // here. + maybeDecodeTrailers(); + OnFinRead(); in_decode_data_callstack_ = false; } @@ -219,20 +222,32 @@ void EnvoyQuicServerStream::OnBodyAvailable() { void EnvoyQuicServerStream::OnTrailingHeadersComplete(bool fin, size_t frame_len, const quic::QuicHeaderList& header_list) { quic::QuicSpdyServerStreamBase::OnTrailingHeadersComplete(fin, frame_len, header_list); - if (session()->connection()->connected() && - (quic::VersionUsesHttp3(transport_version()) || sequencer()->IsClosed()) && - !FinishedReadingTrailers()) { - // Before QPack trailers can arrive before body. Only decode trailers after finishing decoding - // body. + ASSERT(trailers_decompressed()); + if (session()->connection()->connected() && !rst_sent()) { + maybeDecodeTrailers(); + } +} + +void EnvoyQuicServerStream::maybeDecodeTrailers() { + if (sequencer()->IsClosed() && !FinishedReadingTrailers()) { + ASSERT(!received_trailers().empty()); + // Only decode trailers after finishing decoding body. request_decoder_->decodeTrailers( spdyHeaderBlockToEnvoyHeaders(received_trailers())); + end_stream_decoded_ = true; MarkTrailersConsumed(); } } void EnvoyQuicServerStream::OnStreamReset(const quic::QuicRstStreamFrame& frame) { quic::QuicSpdyServerStreamBase::OnStreamReset(frame); - runResetCallbacks(quicRstErrorToEnvoyResetReason(frame.error_code)); + runResetCallbacks(quicRstErrorToEnvoyRemoteResetReason(frame.error_code)); +} + +void EnvoyQuicServerStream::Reset(quic::QuicRstStreamErrorCode error) { + // Upper layers expect calling resetStream() to immediately raise reset callbacks. + runResetCallbacks(quicRstErrorToEnvoyLocalResetReason(error)); + quic::QuicSpdyServerStreamBase::Reset(error); } void EnvoyQuicServerStream::OnConnectionClosed(quic::QuicErrorCode error, diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_server_stream.h b/source/extensions/quic_listeners/quiche/envoy_quic_server_stream.h index b05a707751ff0..acd4138db3986 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_server_stream.h +++ b/source/extensions/quic_listeners/quiche/envoy_quic_server_stream.h @@ -49,9 +49,10 @@ class EnvoyQuicServerStream : public quic::QuicSpdyServerStreamBase, // quic::QuicSpdyStream void OnBodyAvailable() override; void OnStreamReset(const quic::QuicRstStreamFrame& frame) override; + void Reset(quic::QuicRstStreamErrorCode error) override; void OnClose() override; void OnCanWrite() override; - // quic::QuicServerSessionBase + // quic::QuicSpdyServerStreamBase void OnConnectionClosed(quic::QuicErrorCode error, quic::ConnectionCloseSource source) override; protected: @@ -69,6 +70,9 @@ class EnvoyQuicServerStream : public quic::QuicSpdyServerStreamBase, private: QuicFilterManagerConnectionImpl* filterManagerConnection(); + // Deliver awaiting trailers if body has been delivered. + void maybeDecodeTrailers(); + Http::RequestDecoder* request_decoder_{nullptr}; }; diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_utils.cc b/source/extensions/quic_listeners/quiche/envoy_quic_utils.cc index 473c01e617d63..bd0a8a657ccdb 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_utils.cc +++ b/source/extensions/quic_listeners/quiche/envoy_quic_utils.cc @@ -65,20 +65,32 @@ quic::QuicRstStreamErrorCode envoyResetReasonToQuicRstError(Http::StreamResetRea case Http::StreamResetReason::LocalRefusedStreamReset: return quic::QUIC_REFUSED_STREAM; case Http::StreamResetReason::ConnectionFailure: + case Http::StreamResetReason::ConnectionTermination: return quic::QUIC_STREAM_CONNECTION_ERROR; case Http::StreamResetReason::LocalReset: return quic::QUIC_STREAM_CANCELLED; - case Http::StreamResetReason::ConnectionTermination: - return quic::QUIC_STREAM_NO_ERROR; default: return quic::QUIC_BAD_APPLICATION_PAYLOAD; } } -Http::StreamResetReason quicRstErrorToEnvoyResetReason(quic::QuicRstStreamErrorCode rst_err) { +Http::StreamResetReason quicRstErrorToEnvoyLocalResetReason(quic::QuicRstStreamErrorCode rst_err) { + switch (rst_err) { + case quic::QUIC_REFUSED_STREAM: + return Http::StreamResetReason::LocalRefusedStreamReset; + case quic::QUIC_STREAM_CONNECTION_ERROR: + return Http::StreamResetReason::ConnectionFailure; + default: + return Http::StreamResetReason::LocalReset; + } +} + +Http::StreamResetReason quicRstErrorToEnvoyRemoteResetReason(quic::QuicRstStreamErrorCode rst_err) { switch (rst_err) { case quic::QUIC_REFUSED_STREAM: return Http::StreamResetReason::RemoteRefusedStreamReset; + case quic::QUIC_STREAM_CONNECTION_ERROR: + return Http::StreamResetReason::ConnectError; default: return Http::StreamResetReason::RemoteReset; } diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_utils.h b/source/extensions/quic_listeners/quiche/envoy_quic_utils.h index 563e0960cbd9a..3c29b28ef21f0 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_utils.h +++ b/source/extensions/quic_listeners/quiche/envoy_quic_utils.h @@ -66,7 +66,10 @@ spdy::SpdyHeaderBlock envoyHeadersToSpdyHeaderBlock(const Http::HeaderMap& heade quic::QuicRstStreamErrorCode envoyResetReasonToQuicRstError(Http::StreamResetReason reason); // Called when a RST_STREAM frame is received. -Http::StreamResetReason quicRstErrorToEnvoyResetReason(quic::QuicRstStreamErrorCode rst_err); +Http::StreamResetReason quicRstErrorToEnvoyLocalResetReason(quic::QuicRstStreamErrorCode rst_err); + +// Called when a QUIC stack reset the stream. +Http::StreamResetReason quicRstErrorToEnvoyRemoteResetReason(quic::QuicRstStreamErrorCode rst_err); // Called when underlying QUIC connection is closed either locally or by peer. Http::StreamResetReason quicErrorCodeToEnvoyResetReason(quic::QuicErrorCode error); diff --git a/source/extensions/quic_listeners/quiche/platform/BUILD b/source/extensions/quic_listeners/quiche/platform/BUILD index f53e07b58a33b..839664d52f970 100644 --- a/source/extensions/quic_listeners/quiche/platform/BUILD +++ b/source/extensions/quic_listeners/quiche/platform/BUILD @@ -36,15 +36,16 @@ envoy_extension_package() envoy_cc_library( name = "flags_impl_lib", srcs = ["flags_impl.cc"], - hdrs = [ - "flags_impl.h", - "flags_list.h", - ], + hdrs = ["flags_impl.h"], external_deps = [ "abseil_base", "abseil_synchronization", ], visibility = ["//visibility:public"], + deps = [ + "@com_googlesource_quiche//:quic_core_flags_list_lib", + "@com_googlesource_quiche//:quic_core_protocol_flags_list_lib", + ], ) envoy_cc_library( @@ -62,7 +63,6 @@ envoy_cc_library( envoy_cc_library( name = "http2_platform_impl_lib", hdrs = [ - "http2_arraysize_impl.h", "http2_bug_tracker_impl.h", "http2_containers_impl.h", "http2_estimate_memory_usage_impl.h", @@ -74,7 +74,6 @@ envoy_cc_library( ], external_deps = [ "abseil_base", - "abseil_optional", "abseil_str_format", ], visibility = ["//visibility:public"], @@ -114,16 +113,13 @@ envoy_cc_library( "quic_mem_slice_impl.cc", ], hdrs = [ - "quic_aligned_impl.h", "quic_client_stats_impl.h", "quic_containers_impl.h", "quic_error_code_wrappers_impl.h", "quic_estimate_memory_usage_impl.h", - "quic_fallthrough_impl.h", "quic_flag_utils_impl.h", "quic_flags_impl.h", "quic_iovec_impl.h", - "quic_macros_impl.h", "quic_map_util_impl.h", "quic_mem_slice_impl.h", "quic_prefetch_impl.h", @@ -132,6 +128,7 @@ envoy_cc_library( "quic_server_stats_impl.h", "quic_stack_trace_impl.h", "quic_stream_buffer_allocator_impl.h", + "quic_testvalue_impl.h", "quic_uint128_impl.h", ], external_deps = [ @@ -141,7 +138,6 @@ envoy_cc_library( "abseil_memory", "abseil_node_hash_map", "abseil_node_hash_set", - "abseil_optional", ], tags = ["nofips"], visibility = ["//visibility:public"], @@ -236,6 +232,7 @@ envoy_cc_library( }), repository = "@envoy", tags = ["nofips"], + visibility = ["//visibility:public"], ) envoy_cc_library( @@ -250,23 +247,12 @@ envoy_cc_library( ], ) -envoy_cc_library( - name = "quiche_common_platform_optional_impl_lib", - hdrs = ["quiche_optional_impl.h"], - external_deps = [ - "abseil_node_hash_map", - ], - visibility = ["//visibility:public"], -) - envoy_cc_library( name = "quiche_common_platform_impl_lib", srcs = ["quiche_time_utils_impl.cc"], hdrs = [ - "quiche_arraysize_impl.h", "quiche_logging_impl.h", "quiche_map_util_impl.h", - "quiche_ptr_util_impl.h", "quiche_str_cat_impl.h", "quiche_string_piece_impl.h", "quiche_text_utils_impl.h", @@ -281,17 +267,14 @@ envoy_cc_library( deps = [ ":quic_platform_logging_impl_lib", ":string_utils_lib", - "@com_googlesource_quiche//:quiche_common_platform_optional", ], ) envoy_cc_library( name = "spdy_platform_impl_lib", hdrs = [ - "spdy_arraysize_impl.h", "spdy_bug_tracker_impl.h", "spdy_containers_impl.h", - "spdy_endianness_util_impl.h", "spdy_estimate_memory_usage_impl.h", "spdy_flags_impl.h", "spdy_logging_impl.h", @@ -331,14 +314,3 @@ envoy_cc_library( tags = ["nofips"], visibility = ["//visibility:public"], ) - -envoy_cc_library( - name = "quiche_common_platform_endian_impl_lib", - hdrs = ["quiche_endian_impl.h"], - tags = ["nofips"], - visibility = ["//visibility:public"], - deps = [ - "quiche_common_platform_export_impl_lib", - "//source/common/common:byte_order_lib", - ], -) diff --git a/source/extensions/quic_listeners/quiche/platform/flags_impl.cc b/source/extensions/quic_listeners/quiche/platform/flags_impl.cc index 70fb182d673d0..9d4ea89ce3a62 100644 --- a/source/extensions/quic_listeners/quiche/platform/flags_impl.cc +++ b/source/extensions/quic_listeners/quiche/platform/flags_impl.cc @@ -15,12 +15,24 @@ namespace quiche { namespace { -absl::flat_hash_map MakeFlagMap() { +absl::flat_hash_map makeFlagMap() { absl::flat_hash_map flags; -#define QUICHE_FLAG(type, flag, value, help) flags.emplace(FLAGS_##flag->name(), FLAGS_##flag); -#include "extensions/quic_listeners/quiche/platform/flags_list.h" -#undef QUICHE_FLAG +#define QUIC_FLAG(flag, ...) flags.emplace(flag->name(), flag); +#include "quiche/quic/core/quic_flags_list.h" + QUIC_FLAG(FLAGS_quic_reloadable_flag_spdy_testonly_default_false, false) + QUIC_FLAG(FLAGS_quic_reloadable_flag_spdy_testonly_default_true, true) + QUIC_FLAG(FLAGS_quic_restart_flag_spdy_testonly_default_false, false) + QUIC_FLAG(FLAGS_quic_restart_flag_spdy_testonly_default_true, true) + QUIC_FLAG(FLAGS_quic_reloadable_flag_http2_testonly_default_false, false) + QUIC_FLAG(FLAGS_quic_reloadable_flag_http2_testonly_default_true, true) + QUIC_FLAG(FLAGS_quic_restart_flag_http2_testonly_default_false, false) + QUIC_FLAG(FLAGS_quic_restart_flag_http2_testonly_default_true, true) +#undef QUIC_FLAG + +#define QUIC_PROTOCOL_FLAG(type, flag, ...) flags.emplace(FLAGS_##flag->name(), FLAGS_##flag); +#include "quiche/quic/core/quic_protocol_flags_list.h" +#undef QUIC_PROTOCOL_FLAG return flags; } @@ -28,75 +40,123 @@ absl::flat_hash_map MakeFlagMap() { } // namespace // static -FlagRegistry& FlagRegistry::GetInstance() { +FlagRegistry& FlagRegistry::getInstance() { static auto* instance = new FlagRegistry(); return *instance; } -FlagRegistry::FlagRegistry() : flags_(MakeFlagMap()) {} +FlagRegistry::FlagRegistry() : flags_(makeFlagMap()) {} -void FlagRegistry::ResetFlags() const { +void FlagRegistry::resetFlags() const { for (auto& kv : flags_) { - kv.second->ResetValue(); + kv.second->resetValue(); } } -Flag* FlagRegistry::FindFlag(const std::string& name) const { +Flag* FlagRegistry::findFlag(const std::string& name) const { auto it = flags_.find(name); return (it != flags_.end()) ? it->second : nullptr; } -template <> bool TypedFlag::SetValueFromString(const std::string& value_str) { +template <> bool TypedFlag::setValueFromString(const std::string& value_str) { static const auto* kTrueValues = new std::set({"1", "t", "true", "y", "yes"}); static const auto* kFalseValues = new std::set({"0", "f", "false", "n", "no"}); auto lower = absl::AsciiStrToLower(value_str); if (kTrueValues->find(lower) != kTrueValues->end()) { - SetValue(true); + setValue(true); return true; } if (kFalseValues->find(lower) != kFalseValues->end()) { - SetValue(false); + setValue(false); return true; } return false; } -template <> bool TypedFlag::SetValueFromString(const std::string& value_str) { +template <> bool TypedFlag::setValueFromString(const std::string& value_str) { int32_t value; if (absl::SimpleAtoi(value_str, &value)) { - SetValue(value); + setValue(value); return true; } return false; } -template <> bool TypedFlag::SetValueFromString(const std::string& value_str) { +template <> bool TypedFlag::setValueFromString(const std::string& value_str) { int64_t value; if (absl::SimpleAtoi(value_str, &value)) { - SetValue(value); + setValue(value); return true; } return false; } -template <> bool TypedFlag::SetValueFromString(const std::string& value_str) { +template <> bool TypedFlag::setValueFromString(const std::string& value_str) { double value; if (absl::SimpleAtod(value_str, &value)) { - SetValue(value); + setValue(value); return true; } return false; } -template <> bool TypedFlag::SetValueFromString(const std::string& value_str) { - SetValue(value_str); +template <> bool TypedFlag::setValueFromString(const std::string& value_str) { + setValue(value_str); return true; } +template <> bool TypedFlag::setValueFromString(const std::string& value_str) { + unsigned long value; + if (absl::SimpleAtoi(value_str, &value)) { + setValue(value); + return true; + } + return false; +} + +template <> bool TypedFlag::setValueFromString(const std::string& value_str) { + unsigned long long value; + if (absl::SimpleAtoi(value_str, &value)) { + setValue(value); + return true; + } + return false; +} + // Flag definitions -#define QUICHE_FLAG(type, flag, value, help) \ - TypedFlag* FLAGS_##flag = new TypedFlag(#flag, value, help); -#include "extensions/quic_listeners/quiche/platform/flags_list.h" -#undef QUICHE_FLAG +#define QUIC_FLAG(flag, value) TypedFlag* flag = new TypedFlag(#flag, value, ""); +#include "quiche/quic/core/quic_flags_list.h" +QUIC_FLAG(FLAGS_quic_reloadable_flag_spdy_testonly_default_false, false) +QUIC_FLAG(FLAGS_quic_reloadable_flag_spdy_testonly_default_true, true) +QUIC_FLAG(FLAGS_quic_restart_flag_spdy_testonly_default_false, false) +QUIC_FLAG(FLAGS_quic_restart_flag_spdy_testonly_default_true, true) +QUIC_FLAG(FLAGS_quic_reloadable_flag_http2_testonly_default_false, false) +QUIC_FLAG(FLAGS_quic_reloadable_flag_http2_testonly_default_true, true) +QUIC_FLAG(FLAGS_quic_restart_flag_http2_testonly_default_false, false) +QUIC_FLAG(FLAGS_quic_restart_flag_http2_testonly_default_true, true) + +#undef QUIC_FLAG + +#define STRINGIFY(X) #X + +#define DEFINE_QUIC_PROTOCOL_FLAG_IMPL(type, flag, value, help) \ + TypedFlag* FLAGS_##flag = new TypedFlag(STRINGIFY(FLAGS_##flag), value, help); + +#define DEFINE_QUIC_PROTOCOL_FLAG_SINGLE_VALUE(type, flag, value, doc) \ + DEFINE_QUIC_PROTOCOL_FLAG_IMPL(type, flag, value, doc) + +#define DEFINE_QUIC_PROTOCOL_FLAG_TWO_VALUES(type, flag, internal_value, external_value, doc) \ + DEFINE_QUIC_PROTOCOL_FLAG_IMPL(type, flag, external_value, doc) + +// Select the right macro based on the number of arguments. +#define GET_6TH_ARG(arg1, arg2, arg3, arg4, arg5, arg6, ...) arg6 + +#define QUIC_PROTOCOL_FLAG_MACRO_CHOOSER(...) \ + GET_6TH_ARG(__VA_ARGS__, DEFINE_QUIC_PROTOCOL_FLAG_TWO_VALUES, \ + DEFINE_QUIC_PROTOCOL_FLAG_SINGLE_VALUE) + +#define QUIC_PROTOCOL_FLAG(...) QUIC_PROTOCOL_FLAG_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__) +#include "quiche/quic/core/quic_protocol_flags_list.h" +#undef QUIC_PROTOCOL_FLAG } // namespace quiche diff --git a/source/extensions/quic_listeners/quiche/platform/flags_impl.h b/source/extensions/quic_listeners/quiche/platform/flags_impl.h index 5db9399255105..83ed8430c07d7 100644 --- a/source/extensions/quic_listeners/quiche/platform/flags_impl.h +++ b/source/extensions/quic_listeners/quiche/platform/flags_impl.h @@ -26,13 +26,13 @@ class FlagRegistry { ~FlagRegistry() = default; // Return singleton instance. - static FlagRegistry& GetInstance(); + static FlagRegistry& getInstance(); // Reset all registered flags to their default values. - void ResetFlags() const; + void resetFlags() const; // Look up a flag by name. - Flag* FindFlag(const std::string& name) const; + Flag* findFlag(const std::string& name) const; private: FlagRegistry(); @@ -48,10 +48,10 @@ class Flag { virtual ~Flag() = default; // Set flag value from given string, returning true iff successful. - virtual bool SetValueFromString(const std::string& value_str) = 0; + virtual bool setValueFromString(const std::string& value_str) = 0; // Reset flag to default value. - virtual void ResetValue() = 0; + virtual void resetValue() = 0; // Return flag name. std::string name() const { return name_; } @@ -70,15 +70,15 @@ template class TypedFlag : public Flag { TypedFlag(const char* name, T default_value, const char* help) : Flag(name, help), value_(default_value), default_value_(default_value) {} - bool SetValueFromString(const std::string& value_str) override; + bool setValueFromString(const std::string& value_str) override; - void ResetValue() override { + void resetValue() override { absl::MutexLock lock(&mutex_); value_ = default_value_; } // Set flag value. - void SetValue(T value) { + void setValue(T value) { absl::MutexLock lock(&mutex_); value_ = value; } @@ -96,15 +96,29 @@ template class TypedFlag : public Flag { }; // SetValueFromString specializations -template <> bool TypedFlag::SetValueFromString(const std::string& value_str); -template <> bool TypedFlag::SetValueFromString(const std::string& value_str); -template <> bool TypedFlag::SetValueFromString(const std::string& value_str); -template <> bool TypedFlag::SetValueFromString(const std::string& value_str); -template <> bool TypedFlag::SetValueFromString(const std::string& value_str); +template <> bool TypedFlag::setValueFromString(const std::string& value_str); +template <> bool TypedFlag::setValueFromString(const std::string& value_str); +template <> bool TypedFlag::setValueFromString(const std::string& value_str); +template <> bool TypedFlag::setValueFromString(const std::string& value_str); +template <> bool TypedFlag::setValueFromString(const std::string& value_str); +template <> bool TypedFlag::setValueFromString(const std::string& value_str); +template <> bool TypedFlag::setValueFromString(const std::string& value_str); // Flag declarations -#define QUICHE_FLAG(type, flag, value, help) extern TypedFlag* FLAGS_##flag; -#include "extensions/quic_listeners/quiche/platform/flags_list.h" -#undef QUICHE_FLAG +#define QUIC_FLAG(flag, ...) extern TypedFlag* flag; +#include "quiche/quic/core/quic_flags_list.h" +QUIC_FLAG(FLAGS_quic_reloadable_flag_spdy_testonly_default_false, false) +QUIC_FLAG(FLAGS_quic_reloadable_flag_spdy_testonly_default_true, true) +QUIC_FLAG(FLAGS_quic_restart_flag_spdy_testonly_default_false, false) +QUIC_FLAG(FLAGS_quic_restart_flag_spdy_testonly_default_true, true) +QUIC_FLAG(FLAGS_quic_reloadable_flag_http2_testonly_default_false, false) +QUIC_FLAG(FLAGS_quic_reloadable_flag_http2_testonly_default_true, true) +QUIC_FLAG(FLAGS_quic_restart_flag_http2_testonly_default_false, false) +QUIC_FLAG(FLAGS_quic_restart_flag_http2_testonly_default_true, true) +#undef QUIC_FLAG + +#define QUIC_PROTOCOL_FLAG(type, flag, ...) extern TypedFlag* FLAGS_##flag; +#include "quiche/quic/core/quic_protocol_flags_list.h" +#undef QUIC_PROTOCOL_FLAG } // namespace quiche diff --git a/source/extensions/quic_listeners/quiche/platform/flags_list.h b/source/extensions/quic_listeners/quiche/platform/flags_list.h deleted file mode 100644 index 52454caec0a29..0000000000000 --- a/source/extensions/quic_listeners/quiche/platform/flags_list.h +++ /dev/null @@ -1,502 +0,0 @@ -// This file intentionally does not have header guards. It is intended to be -// included multiple times, each time with a different definition of -// QUICHE_FLAG. - -// NOLINT(namespace-envoy) - -// This file is part of the QUICHE platform implementation, and is not to be -// consumed or referenced directly by other Envoy code. It serves purely as a -// porting layer for QUICHE. - -// This file is generated by //third_party/quic/tools:quic_flags_list in -// Google3. - -#if defined(QUICHE_FLAG) - -QUICHE_FLAG( - bool, http2_reloadable_flag_http2_backend_alpn_failure_error_code, false, - "If true, the GFE will return a new ResponseCodeDetails error when ALPN to the backend fails.") - -QUICHE_FLAG(bool, http2_reloadable_flag_http2_ip_based_cwnd_exp, true, - "If true, enable IP address based CWND bootstrapping experiment with different " - "bandwidth models and priorities in HTTP2.") - -QUICHE_FLAG( - bool, http2_reloadable_flag_http2_load_based_goaway_warning, false, - "If true, load-based connection closures will send a warning GOAWAY before the actual GOAWAY.") - -QUICHE_FLAG(bool, http2_reloadable_flag_http2_security_requirement_for_client3, false, - "If true, check whether client meets security requirements during SSL handshake. If " - "flag is true and client does not meet security requirements, do not negotiate HTTP/2 " - "with client or terminate the session with SPDY_INADEQUATE_SECURITY if HTTP/2 is " - "already negotiated. The spec contains both cipher and TLS version requirements.") - -QUICHE_FLAG(bool, http2_reloadable_flag_http2_websocket_detection, false, - "If true, uses a HTTP/2-specific method of detecting websocket upgrade requests.") - -QUICHE_FLAG(bool, http2_reloadable_flag_permissive_http2_switch, false, - "If true, the GFE allows both HTTP/1.0 and HTTP/1.1 versions in HTTP/2 upgrade " - "requests/responses.") - -QUICHE_FLAG(bool, quic_reloadable_flag_advertise_quic_for_https_for_debugips, false, "") - -QUICHE_FLAG(bool, quic_reloadable_flag_advertise_quic_for_https_for_external_users, false, "") - -QUICHE_FLAG(bool, quic_reloadable_flag_gclb_quic_allow_alia, true, - "If gfe2_reloadable_flag_gclb_use_alia is also true, use Alia for GCLB QUIC " - "handshakes. To be used as a big red button if there's a problem with Alia/QUIC.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_abort_qpack_on_stream_close, false, - "If true, abort async QPACK header decompression in QuicSpdyStream::OnClose().") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_ack_delay_alarm_granularity, false, - "When true, ensure the ACK delay is never less than the alarm granularity when ACK " - "decimation is enabled.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_add_missing_connected_checks, false, - "If true, add missing connected checks.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_add_silent_idle_timeout, true, - "If true, when server is silently closing connections due to idle timeout, serialize " - "the connection close packets which will be added to time wait list.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_add_stream_info_to_idle_close_detail, false, - "If true, include stream information in idle timeout connection close detail.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_allow_backend_set_stream_ttl, false, - "If true, check backend response header for X-Response-Ttl. If it is provided, the " - "stream TTL is set. A QUIC stream will be immediately canceled when tries to write " - "data if this TTL expired.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_allow_client_enabled_bbr_v2, true, - "If true, allow client to enable BBRv2 on server via connection option 'B2ON'.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_alpn_dispatch, false, - "Support different QUIC sessions, as indicated by ALPN. Used for QBONE.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_bbr2_avoid_too_low_probe_bw_cwnd, false, - "If true, QUIC BBRv2's PROBE_BW mode will not reduce cwnd below BDP+ack_height.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_bbr2_fewer_startup_round_trips, false, - "When true, the 1RTT and 2RTT connection options decrease the number of round trips in " - "BBRv2 STARTUP without a 25% bandwidth increase to 1 or 2 round trips respectively.") - -QUICHE_FLAG( - bool, quic_reloadable_flag_quic_bbr2_limit_inflight_hi, false, - "When true, the B2HI connection option limits reduction of inflight_hi to (1-Beta)*CWND.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_bbr2_use_post_inflight_to_detect_queuing, false, - "If true, QUIC BBRv2 will use inflight byte after congestion event to detect queuing " - "during PROBE_UP.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_bbr_no_bytes_acked_in_startup_recovery, false, - "When in STARTUP and recovery, do not add bytes_acked to QUIC BBR's CWND in " - "CalculateCongestionWindow()") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_bootstrap_cwnd_by_spdy_priority, true, - "If true, bootstrap initial QUIC cwnd by SPDY priorities.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_cap_large_client_initial_rtt, true, - "If true, cap client suggested initial RTT to 1s if it is longer than 1s.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_clean_up_spdy_session_destructor, false, - "If true, QuicSpdySession's destructor won't need to do cleanup.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_close_connection_in_on_can_write_with_blocked_writer, - false, - "If true, close connection if writer is still blocked while OnCanWrite is called.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_close_connection_on_serialization_failure, false, - "If true, close connection on packet serialization failures.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_conservative_bursts, false, - "If true, set burst token to 2 in cwnd bootstrapping experiment.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_conservative_cwnd_and_pacing_gains, false, - "If true, uses conservative cwnd gain and pacing gain when cwnd gets bootstrapped.") - -QUICHE_FLAG( - bool, quic_reloadable_flag_quic_copy_bbr_cwnd_to_bbr2, false, - "If true, when switching from BBR to BBRv2, BBRv2 will use BBR's cwnd as its initial cwnd.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_default_enable_5rto_blackhole_detection2, true, - "If true, default-enable 5RTO blachole detection.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_default_on_pto, false, - "If true, default on PTO which unifies TLP + RTO loss recovery.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_default_to_bbr, true, - "When true, defaults to BBR congestion control instead of Cubic.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_default_to_bbr_v2, false, - "If true, use BBRv2 as the default congestion controller. Takes precedence over " - "--quic_default_to_bbr.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_disable_server_blackhole_detection, false, - "If true, disable blackhole detection on server side.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_disable_version_draft_27, false, - "If true, disable QUIC version h3-27.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_disable_version_draft_29, false, - "If true, disable QUIC version h3-29.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_disable_version_q043, false, - "If true, disable QUIC version Q043.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_disable_version_q046, false, - "If true, disable QUIC version Q046.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_disable_version_q050, false, - "If true, disable QUIC version Q050.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_disable_version_t050, false, - "If true, disable QUIC version h3-T050.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_disable_version_t051, false, - "If true, disable QUIC version h3-T051.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_discard_initial_packet_with_key_dropped, false, - "If true, discard INITIAL packet if the key has been dropped.") - -QUICHE_FLAG( - bool, quic_reloadable_flag_quic_do_not_accept_stop_waiting, false, - "In v44 and above, where STOP_WAITING is never sent, close the connection if it's received.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_donot_reset_ideal_next_packet_send_time, false, - "If true, stop resetting ideal_next_packet_send_time_ in pacing sender.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_enable_loss_detection_experiment_at_gfe, false, - "If ture, enable GFE-picked loss detection experiment.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_enable_loss_detection_tuner, false, - "If true, allow QUIC loss detection tuning to be enabled by connection option ELDT.") - -QUICHE_FLAG( - bool, quic_reloadable_flag_quic_enable_mtu_discovery_at_server, false, - "If true, QUIC will default enable MTU discovery at server, with a target of 1450 bytes.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_enabled, false, "") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_fix_arm_pto_for_application_data, false, - "If true, do not arm PTO for application data until handshake confirmed.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_fix_bytes_left_for_batch_write, false, - "If true, convert bytes_left_for_batch_write_ to unsigned int.") - -QUICHE_FLAG( - bool, quic_reloadable_flag_quic_fix_http3_goaway_stream_id, false, - "If true, send the lowest stream ID that can be retried by the client in a GOAWAY frame. If " - "false, send the highest received stream ID, which actually should not be retried.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_fix_out_of_order_sending, false, - "If true, fix a potential out of order sending caused by handshake gets confirmed " - "while the coalescer is not empty.") - -QUICHE_FLAG( - bool, quic_reloadable_flag_quic_fix_pto_pending_timer_count, false, - "If true, make sure there is pending timer credit when trying to PTO retransmit any packets.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_fix_undecryptable_packets2, false, - "If true, remove processed undecryptable packets.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_get_stream_information_from_stream_map, true, - "If true, gQUIC will only consult stream_map in QuicSession::GetNumActiveStreams().") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_give_sent_packet_to_debug_visitor_after_sent, false, - "If true, QUIC connection will pass sent packet information to the debug visitor after " - "a packet is recorded as sent in sent packet manager.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_http3_new_default_urgency_value, false, - "If true, QuicStream::kDefaultUrgency is 3, otherwise 1.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_ip_based_cwnd_exp, true, - "If true, enable IP address based CWND bootstrapping experiment with different " - "bandwidth models and priorities. ") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_listener_never_fake_epollout, false, - "If true, QuicListener::OnSocketIsWritable will always return false, which means there " - "will never be a fake `EPOLLOUT` event in the next epoll iteration.") - -QUICHE_FLAG(bool, - quic_reloadable_flag_quic_neuter_initial_packet_in_coalescer_with_initial_key_discarded, - false, "If true, neuter initial packet in the coalescer when discarding initial keys.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_no_dup_experiment_id_2, false, - "If true, transport connection stats doesn't report duplicated experiments for same " - "connection.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_no_silent_close_for_idle_timeout, true, - "If true, always send connection close for idle timeout if NSLC is received.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_only_set_uaid_in_tcs_visitor, false, - "If true, QuicTransportConnectionStatsVisitor::PopulateTransportConnectionStats will " - "be the only place where TCS's uaid field is set.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_only_truncate_long_cids, true, - "In IETF QUIC, only truncate long CIDs from the client's Initial, don't modify them.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_preferred_altsvc_version, false, - "When true, we will send a preferred QUIC version at the start of our Alt-Svc list.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_proxy_write_packed_strings, false, - "If true, QuicProxyDispatcher will write packed_client_address and packed_server_vip " - "in TcpProxyHeaderProto.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_record_frontend_service_vip_mapping, true, - "If true, for L1 GFE, as requests come in, record frontend service to VIP mapping " - "which is used to announce VIP in SHLO for proxied sessions. ") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_record_received_min_ack_delay, false, - "If true, record the received min_ack_delay in transport parameters to QUIC config.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_reject_all_traffic, false, "") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_remove_zombie_streams, true, - "If true, QuicSession doesn't keep a separate zombie_streams. Instead, all streams are " - "stored in stream_map_.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_require_handshake_confirmation, false, - "If true, require handshake confirmation for QUIC connections, functionally disabling " - "0-rtt handshakes.") - -QUICHE_FLAG( - bool, quic_reloadable_flag_quic_send_key_update_not_yet_supported, false, - "When true, QUIC+TLS versions will send the key_update_not_yet_supported transport parameter.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_send_path_response, false, - "If true, send PATH_RESPONSE upon receiving PATH_CHALLENGE regardless of perspective. " - "--gfe2_reloadable_flag_quic_start_peer_migration_earlier has to be true before turn " - "on this flag.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_send_timestamps, false, - "When the STMP connection option is sent by the client, timestamps in the QUIC ACK " - "frame are sent and processed.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_server_push, false, - "If true, enable server push feature on QUIC.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_set_resumed_ssl_session_early, false, - "If true, set resumed_ssl_session if this is a 0-RTT connection.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_start_peer_migration_earlier, false, - "If true, while reading an IETF quic packet, start peer migration immediately when " - "detecting the existence of any non-probing frame instead of at the end of the packet.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_stop_sending_uses_ietf_error_code, false, - "If true, use IETF QUIC application error codes in STOP_SENDING frames. If false, use " - "QuicRstStreamErrorCodes.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_testonly_default_false, false, - "A testonly reloadable flag that will always default to false.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_testonly_default_true, true, - "A testonly reloadable flag that will always default to true.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_unified_iw_options, false, - "When true, set the initial congestion control window from connection options in " - "QuicSentPacketManager rather than TcpCubicSenderBytes.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_use_header_stage_idle_list2, false, - "If true, use header stage idle list for QUIC connections in GFE.") - -QUICHE_FLAG(bool, quic_reloadable_flag_quic_use_leto_key_exchange, false, - "If true, QUIC will attempt to use the Leto key exchange service and only fall back to " - "local key exchange if that fails.") - -QUICHE_FLAG(bool, quic_reloadable_flag_send_quic_fallback_server_config_on_leto_error, false, - "If true and using Leto for QUIC shared-key calculations, GFE will react to a failure " - "to contact Leto by sending a REJ containing a fallback ServerConfig, allowing the " - "client to continue the handshake.") - -QUICHE_FLAG( - bool, quic_restart_flag_dont_fetch_quic_private_keys_from_leto, false, - "If true, GFE will not request private keys when fetching QUIC ServerConfigs from Leto.") - -QUICHE_FLAG(bool, quic_restart_flag_quic_adjust_initial_cwnd_by_gws, true, - "If true, GFE informs backend that a client request is the first one on the connection " - "via frontline header \"first_request=1\". Also, adjust initial cwnd based on " - "X-Google-Gws-Initial-Cwnd-Mode sent by GWS.") - -QUICHE_FLAG( - bool, quic_restart_flag_quic_allow_loas_multipacket_chlo, false, - "If true, inspects QUIC CHLOs for kLOAS and early creates sessions to allow multi-packet CHLOs") - -QUICHE_FLAG( - bool, quic_restart_flag_quic_disable_gws_cwnd_experiment, false, - "If true, X-Google-Gws-Initial-Cwnd-Mode related header sent by GWS becomes no-op for QUIC.") - -QUICHE_FLAG(bool, quic_restart_flag_quic_enable_tls_resumption_v4, true, - "If true, enables support for TLS resumption in QUIC.") - -QUICHE_FLAG(bool, quic_restart_flag_quic_enable_zero_rtt_for_tls_v2, true, - "If true, support for IETF QUIC 0-rtt is enabled.") - -QUICHE_FLAG(bool, quic_restart_flag_quic_offload_pacing_to_usps2, false, - "If true, QUIC offload pacing when using USPS as egress method.") - -QUICHE_FLAG(bool, quic_restart_flag_quic_rx_ring_use_tpacket_v3, false, - "If true, use TPACKET_V3 for QuicRxRing instead of TPACKET_V2.") - -QUICHE_FLAG(bool, quic_restart_flag_quic_should_accept_new_connection, false, - "If true, reject QUIC CHLO packets when dispatcher is asked to do so.") - -QUICHE_FLAG(bool, quic_restart_flag_quic_support_release_time_for_gso, false, - "If true, QuicGsoBatchWriter will support release time if it is available and the " - "process has the permission to do so.") - -QUICHE_FLAG(bool, quic_restart_flag_quic_testonly_default_false, false, - "A testonly restart flag that will always default to false.") - -QUICHE_FLAG(bool, quic_restart_flag_quic_testonly_default_true, true, - "A testonly restart flag that will always default to true.") - -QUICHE_FLAG( - bool, quic_restart_flag_quic_use_leto_for_quic_configs, false, - "If true, use Leto to fetch QUIC server configs instead of using the seeds from Memento.") - -QUICHE_FLAG(bool, quic_restart_flag_quic_use_pigeon_socket_to_backend, false, - "If true, create a shared pigeon socket for all quic to backend connections and switch " - "to use it after successful handshake.") - -QUICHE_FLAG(bool, spdy_reloadable_flag_quic_bootstrap_cwnd_by_spdy_priority, true, - "If true, bootstrap initial QUIC cwnd by SPDY priorities.") - -QUICHE_FLAG(bool, spdy_reloadable_flag_quic_clean_up_spdy_session_destructor, false, - "If true, QuicSpdySession's destructor won't need to do cleanup.") - -QUICHE_FLAG( - bool, spdy_reloadable_flag_spdy_discard_response_body_if_disallowed, false, - "If true, SPDY will discard all response body bytes when response code indicates no response " - "body should exist. Previously, we only discard partial bytes on the first response processing " - "and the rest of the response bytes would still be delivered even though the response code " - "said there should not be any body associated with the response code.") - -QUICHE_FLAG(bool, quic_allow_chlo_buffering, true, - "If true, allows packets to be buffered in anticipation of a " - "future CHLO, and allow CHLO packets to be buffered until next " - "iteration of the event loop.") - -QUICHE_FLAG(bool, quic_disable_pacing_for_perf_tests, false, "If true, disable pacing in QUIC") - -QUICHE_FLAG(bool, quic_enforce_single_packet_chlo, true, - "If true, enforce that QUIC CHLOs fit in one packet") - -QUICHE_FLAG(int64_t, quic_time_wait_list_max_connections, 600000, - "Maximum number of connections on the time-wait list. " - "A negative value implies no configured limit.") - -QUICHE_FLAG(int64_t, quic_time_wait_list_seconds, 200, - "Time period for which a given connection_id should live in " - "the time-wait state.") - -QUICHE_FLAG(double, quic_bbr_cwnd_gain, 2.0f, - "Congestion window gain for QUIC BBR during PROBE_BW phase.") - -QUICHE_FLAG(int32_t, quic_buffered_data_threshold, 8 * 1024, - "If buffered data in QUIC stream is less than this " - "threshold, buffers all provided data or asks upper layer for more data") - -QUICHE_FLAG(int32_t, quic_send_buffer_max_data_slice_size, 4 * 1024, - "Max size of data slice in bytes for QUIC stream send buffer.") - -QUICHE_FLAG(int32_t, quic_lumpy_pacing_size, 2, - "Number of packets that the pacing sender allows in bursts during " - "pacing. This flag is ignored if a flow's estimated bandwidth is " - "lower than 1200 kbps.") - -QUICHE_FLAG(double, quic_lumpy_pacing_cwnd_fraction, 0.25f, - "Congestion window fraction that the pacing sender allows in bursts " - "during pacing.") - -QUICHE_FLAG(int32_t, quic_max_pace_time_into_future_ms, 10, - "Max time that QUIC can pace packets into the future in ms.") - -QUICHE_FLAG(double, quic_pace_time_into_future_srtt_fraction, 0.125f, - "Smoothed RTT fraction that a connection can pace packets into the future.") - -QUICHE_FLAG(bool, quic_export_server_num_packets_per_write_histogram, false, - "If true, export number of packets written per write operation histogram.") - -QUICHE_FLAG(bool, quic_disable_version_negotiation_grease_randomness, false, - "If true, use predictable version negotiation versions.") - -QUICHE_FLAG(bool, quic_enable_http3_grease_randomness, true, - "If true, use random greased settings and frames.") - -QUICHE_FLAG(int64_t, quic_max_tracked_packet_count, 10000, "Maximum number of tracked packets.") - -QUICHE_FLAG(bool, quic_prober_uses_length_prefixed_connection_ids, false, - "If true, QuicFramer::WriteClientVersionNegotiationProbePacket uses " - "length-prefixed connection IDs.") - -QUICHE_FLAG(bool, quic_client_convert_http_header_name_to_lowercase, true, - "If true, HTTP request header names sent from QuicSpdyClientBase(and " - "descendents) will be automatically converted to lower case.") - -QUICHE_FLAG(bool, quic_enable_http3_server_push, false, - "If true, server push will be allowed in QUIC versions that use HTTP/3.") - -QUICHE_FLAG(int32_t, quic_bbr2_default_probe_bw_base_duration_ms, 2000, - "The default minimum duration for BBRv2-native probes, in milliseconds.") - -QUICHE_FLAG(int32_t, quic_bbr2_default_probe_bw_max_rand_duration_ms, 1000, - "The default upper bound of the random amount of BBRv2-native " - "probes, in milliseconds.") - -QUICHE_FLAG(int32_t, quic_bbr2_default_probe_rtt_period_ms, 10000, - "The default period for entering PROBE_RTT, in milliseconds.") - -QUICHE_FLAG(double, quic_bbr2_default_loss_threshold, 0.02, - "The default loss threshold for QUIC BBRv2, should be a value " - "between 0 and 1.") - -QUICHE_FLAG(int32_t, quic_bbr2_default_startup_full_loss_count, 8, - "The default minimum number of loss marking events to exit STARTUP.") - -QUICHE_FLAG(int32_t, quic_bbr2_default_probe_bw_full_loss_count, 2, - "The default minimum number of loss marking events to exit PROBE_UP phase.") - -QUICHE_FLAG(double, quic_bbr2_default_inflight_hi_headroom, 0.01, - "The default fraction of unutilized headroom to try to leave in path " - "upon high loss.") - -QUICHE_FLAG(int32_t, quic_bbr2_default_initial_ack_height_filter_window, 10, - "The default initial value of the max ack height filter's window length.") - -QUICHE_FLAG(double, quic_ack_aggregation_bandwidth_threshold, 1.0, - "If the bandwidth during ack aggregation is smaller than (estimated " - "bandwidth * this flag), consider the current aggregation completed " - "and starts a new one.") - -QUICHE_FLAG(int32_t, quic_anti_amplification_factor, 5, - "Anti-amplification factor. Before address validation, server will " - "send no more than factor times bytes received.") - -QUICHE_FLAG(int32_t, quic_max_buffered_crypto_bytes, 16 * 1024, - "The maximum amount of CRYPTO frame data that can be buffered.") - -QUICHE_FLAG(int32_t, quic_max_aggressive_retransmittable_on_wire_ping_count, 0, - "If set to non-zero, the maximum number of consecutive pings that " - "can be sent with aggressive initial retransmittable on wire timeout " - "if there is no new data received. After which, the timeout will be " - "exponentially back off until exceeds the default ping timeout.") - -QUICHE_FLAG(int32_t, quic_max_congestion_window, 2000, "The maximum congestion window in packets.") - -QUICHE_FLAG(int32_t, quic_max_streams_window_divisor, 2, - "The divisor that controls how often MAX_STREAMS frame is sent.") - -QUICHE_FLAG(bool, http2_reloadable_flag_http2_testonly_default_false, false, - "A testonly reloadable flag that will always default to false.") - -QUICHE_FLAG(bool, http2_restart_flag_http2_testonly_default_false, false, - "A testonly restart flag that will always default to false.") - -QUICHE_FLAG(bool, spdy_reloadable_flag_spdy_testonly_default_false, false, - "A testonly reloadable flag that will always default to false.") - -QUICHE_FLAG(bool, spdy_restart_flag_spdy_testonly_default_false, false, - "A testonly restart flag that will always default to false.") - -#endif diff --git a/source/extensions/quic_listeners/quiche/platform/http2_flags_impl.h b/source/extensions/quic_listeners/quiche/platform/http2_flags_impl.h index 7d25614697800..dc6fe5429bdee 100644 --- a/source/extensions/quic_listeners/quiche/platform/http2_flags_impl.h +++ b/source/extensions/quic_listeners/quiche/platform/http2_flags_impl.h @@ -8,10 +8,10 @@ #include "extensions/quic_listeners/quiche/platform/flags_impl.h" -#define GetHttp2ReloadableFlagImpl(flag) quiche::FLAGS_http2_reloadable_flag_##flag->value() +#define GetHttp2ReloadableFlagImpl(flag) quiche::FLAGS_quic_reloadable_flag_##flag->value() #define SetHttp2ReloadableFlagImpl(flag, value) \ - quiche::FLAGS_http2_reloadable_flag_##flag->SetValue(value) + quiche::FLAGS_quic_reloadable_flag_##flag->setValue(value) #define HTTP2_CODE_COUNT_N_IMPL(flag, instance, total) \ do { \ diff --git a/source/extensions/quic_listeners/quiche/platform/quic_aligned_impl.h b/source/extensions/quic_listeners/quiche/platform/quic_aligned_impl.h deleted file mode 100644 index 3f595380b7208..0000000000000 --- a/source/extensions/quic_listeners/quiche/platform/quic_aligned_impl.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "absl/base/optimization.h" - -// NOLINT(namespace-envoy) - -// This file is part of the QUICHE platform implementation, and is not to be -// consumed or referenced directly by other Envoy code. It serves purely as a -// porting layer for QUICHE. - -#define QUIC_ALIGN_OF_IMPL alignof -#ifdef _MSC_VER -#define QUIC_ALIGNED_IMPL(X) __declspec(align(X)) -#else -#define QUIC_ALIGNED_IMPL(X) __attribute__((aligned(X))) -#endif -#define QUIC_CACHELINE_ALIGNED_IMPL ABSL_CACHELINE_ALIGNED -#define QUIC_CACHELINE_SIZE_IMPL ABSL_CACHELINE_SIZE diff --git a/source/extensions/quic_listeners/quiche/platform/quic_cert_utils_impl.cc b/source/extensions/quic_listeners/quiche/platform/quic_cert_utils_impl.cc index 2a886a12caa1d..27b977908d95b 100644 --- a/source/extensions/quic_listeners/quiche/platform/quic_cert_utils_impl.cc +++ b/source/extensions/quic_listeners/quiche/platform/quic_cert_utils_impl.cc @@ -10,25 +10,7 @@ namespace quic { -// static -bool QuicCertUtilsImpl::ExtractSubjectNameFromDERCert(quiche::QuicheStringPiece cert, - quiche::QuicheStringPiece* subject_out) { - CBS tbs_certificate; - if (!SeekToSubject(cert, &tbs_certificate)) { - return false; - } - - CBS subject; - if (!CBS_get_asn1_element(&tbs_certificate, &subject, CBS_ASN1_SEQUENCE)) { - return false; - } - *subject_out = - absl::string_view(reinterpret_cast(CBS_data(&subject)), CBS_len(&subject)); - return true; -} - -// static -bool QuicCertUtilsImpl::SeekToSubject(quiche::QuicheStringPiece cert, CBS* tbs_certificate) { +bool seekToSubject(absl::string_view cert, CBS* tbs_certificate) { CBS der; CBS_init(&der, reinterpret_cast(cert.data()), cert.size()); CBS certificate; @@ -65,4 +47,22 @@ bool QuicCertUtilsImpl::SeekToSubject(quiche::QuicheStringPiece cert, CBS* tbs_c return true; } +// static +// NOLINTNEXTLINE(readability-identifier-naming) +bool QuicCertUtilsImpl::ExtractSubjectNameFromDERCert(absl::string_view cert, + absl::string_view* subject_out) { + CBS tbs_certificate; + if (!seekToSubject(cert, &tbs_certificate)) { + return false; + } + + CBS subject; + if (!CBS_get_asn1_element(&tbs_certificate, &subject, CBS_ASN1_SEQUENCE)) { + return false; + } + *subject_out = + absl::string_view(reinterpret_cast(CBS_data(&subject)), CBS_len(&subject)); + return true; +} + } // namespace quic diff --git a/source/extensions/quic_listeners/quiche/platform/quic_cert_utils_impl.h b/source/extensions/quic_listeners/quiche/platform/quic_cert_utils_impl.h index 0c41b9dbcf21e..29b882b7d75d2 100644 --- a/source/extensions/quic_listeners/quiche/platform/quic_cert_utils_impl.h +++ b/source/extensions/quic_listeners/quiche/platform/quic_cert_utils_impl.h @@ -6,18 +6,15 @@ // consumed or referenced directly by other Envoy code. It serves purely as a // porting layer for QUICHE. +#include "absl/strings/string_view.h" #include "openssl/base.h" -#include "quiche/common/platform/api/quiche_string_piece.h" namespace quic { class QuicCertUtilsImpl { public: - static bool ExtractSubjectNameFromDERCert(quiche::QuicheStringPiece cert, - quiche::QuicheStringPiece* subject_out); - -private: - static bool SeekToSubject(quiche::QuicheStringPiece cert, CBS* tbs_certificate); + // NOLINTNEXTLINE(readability-identifier-naming) + static bool ExtractSubjectNameFromDERCert(absl::string_view cert, absl::string_view* subject_out); }; } // namespace quic diff --git a/source/extensions/quic_listeners/quiche/platform/quic_fallthrough_impl.h b/source/extensions/quic_listeners/quiche/platform/quic_fallthrough_impl.h deleted file mode 100644 index aa9d6bc36a188..0000000000000 --- a/source/extensions/quic_listeners/quiche/platform/quic_fallthrough_impl.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -// NOLINT(namespace-envoy) - -// This file is part of the QUICHE platform implementation, and is not to be -// consumed or referenced directly by other Envoy code. It serves purely as a -// porting layer for QUICHE. - -#include "absl/base/macros.h" - -#define QUIC_FALLTHROUGH_INTENDED_IMPL ABSL_FALLTHROUGH_INTENDED diff --git a/source/extensions/quic_listeners/quiche/platform/quic_file_utils_impl.cc b/source/extensions/quic_listeners/quiche/platform/quic_file_utils_impl.cc index 91d52c44abbca..b2e396fab4be0 100644 --- a/source/extensions/quic_listeners/quiche/platform/quic_file_utils_impl.cc +++ b/source/extensions/quic_listeners/quiche/platform/quic_file_utils_impl.cc @@ -36,6 +36,7 @@ void depthFirstTraverseDirectory(const std::string& dirname, std::vector ReadFileContentsImpl(const std::string& dirname) { std::vector files; depthFirstTraverseDirectory(dirname, files); @@ -43,7 +44,8 @@ std::vector ReadFileContentsImpl(const std::string& dirname) { } // Reads the contents of |filename| as a string into |contents|. -void ReadFileContentsImpl(quiche::QuicheStringPiece filename, std::string* contents) { +// NOLINTNEXTLINE(readability-identifier-naming) +void ReadFileContentsImpl(absl::string_view filename, std::string* contents) { #ifdef WIN32 Envoy::Filesystem::InstanceImplWin32 fs; #else diff --git a/source/extensions/quic_listeners/quiche/platform/quic_file_utils_impl.h b/source/extensions/quic_listeners/quiche/platform/quic_file_utils_impl.h index 654c1ad1826b5..25c31e9deca27 100644 --- a/source/extensions/quic_listeners/quiche/platform/quic_file_utils_impl.h +++ b/source/extensions/quic_listeners/quiche/platform/quic_file_utils_impl.h @@ -8,7 +8,7 @@ #include -#include "quiche/common/platform/api/quiche_string_piece.h" +#include "absl/strings/string_view.h" namespace quic { @@ -16,6 +16,7 @@ namespace quic { * Traverses the directory |dirname| and returns all of the files it contains. * @param dirname full path without trailing '/'. */ +// NOLINTNEXTLINE(readability-identifier-naming)` std::vector ReadFileContentsImpl(const std::string& dirname); /** @@ -23,6 +24,7 @@ std::vector ReadFileContentsImpl(const std::string& dirname); * @param filename the full path to the file. * @param contents output location of the file content. */ -void ReadFileContentsImpl(quiche::QuicheStringPiece filename, std::string* contents); +// NOLINTNEXTLINE(readability-identifier-naming) +void ReadFileContentsImpl(absl::string_view filename, std::string* contents); } // namespace quic diff --git a/source/extensions/quic_listeners/quiche/platform/quic_flags_impl.h b/source/extensions/quic_listeners/quiche/platform/quic_flags_impl.h index 872495f2db8ed..d562bb1a4813d 100644 --- a/source/extensions/quic_listeners/quiche/platform/quic_flags_impl.h +++ b/source/extensions/quic_listeners/quiche/platform/quic_flags_impl.h @@ -15,16 +15,16 @@ #define GetQuicFlagImpl(flag) (quiche::flag)->value() // |flag| is the global flag variable, which is a pointer to TypedFlag. -#define SetQuicFlagImpl(flag, value) (quiche::flag)->SetValue(value) +#define SetQuicFlagImpl(flag, value) (quiche::flag)->setValue(value) #define GetQuicReloadableFlagImpl(flag) quiche::FLAGS_quic_reloadable_flag_##flag->value() #define SetQuicReloadableFlagImpl(flag, value) \ - quiche::FLAGS_quic_reloadable_flag_##flag->SetValue(value) + quiche::FLAGS_quic_reloadable_flag_##flag->setValue(value) #define GetQuicRestartFlagImpl(flag) quiche::FLAGS_quic_restart_flag_##flag->value() -#define SetQuicRestartFlagImpl(flag, value) quiche::FLAGS_quic_restart_flag_##flag->SetValue(value) +#define SetQuicRestartFlagImpl(flag, value) quiche::FLAGS_quic_restart_flag_##flag->setValue(value) // Not wired into command-line parsing. #define DEFINE_QUIC_COMMAND_LINE_FLAG_IMPL(type, flag, value, help) \ diff --git a/source/extensions/quic_listeners/quiche/platform/quic_hostname_utils_impl.cc b/source/extensions/quic_listeners/quiche/platform/quic_hostname_utils_impl.cc index bcbafb56639ed..75849611d6a22 100644 --- a/source/extensions/quic_listeners/quiche/platform/quic_hostname_utils_impl.cc +++ b/source/extensions/quic_listeners/quiche/platform/quic_hostname_utils_impl.cc @@ -19,7 +19,8 @@ namespace quic { // static -bool QuicHostnameUtilsImpl::IsValidSNI(quiche::QuicheStringPiece sni) { +// NOLINTNEXTLINE(readability-identifier-naming) +bool QuicHostnameUtilsImpl::IsValidSNI(absl::string_view sni) { // TODO(wub): Implement it on top of GoogleUrl, once it is available. return sni.find_last_of('.') != std::string::npos && @@ -27,7 +28,8 @@ bool QuicHostnameUtilsImpl::IsValidSNI(quiche::QuicheStringPiece sni) { } // static -std::string QuicHostnameUtilsImpl::NormalizeHostname(quiche::QuicheStringPiece hostname) { +// NOLINTNEXTLINE(readability-identifier-naming) +std::string QuicHostnameUtilsImpl::NormalizeHostname(absl::string_view hostname) { // TODO(wub): Implement it on top of GoogleUrl, once it is available. std::string host = absl::AsciiStrToLower(hostname); diff --git a/source/extensions/quic_listeners/quiche/platform/quic_hostname_utils_impl.h b/source/extensions/quic_listeners/quiche/platform/quic_hostname_utils_impl.h index 2b7ed43571b48..67cd787d03c25 100644 --- a/source/extensions/quic_listeners/quiche/platform/quic_hostname_utils_impl.h +++ b/source/extensions/quic_listeners/quiche/platform/quic_hostname_utils_impl.h @@ -6,7 +6,7 @@ // consumed or referenced directly by other Envoy code. It serves purely as a // porting layer for QUICHE. -#include "quiche/common/platform/api/quiche_string_piece.h" +#include "absl/strings/string_view.h" #include "quiche/quic/platform/api/quic_export.h" namespace quic { @@ -18,7 +18,8 @@ class QUIC_EXPORT_PRIVATE QuicHostnameUtilsImpl { // (2) check that the hostname contains valid characters only; and // (3) contains at least one dot. // NOTE(wub): Only (3) is implemented for now. - static bool IsValidSNI(quiche::QuicheStringPiece sni); + // NOLINTNEXTLINE(readability-identifier-naming) + static bool IsValidSNI(absl::string_view sni); // Normalize a hostname: // (1) Canonicalize it, similar to what Chromium does in @@ -27,7 +28,8 @@ class QUIC_EXPORT_PRIVATE QuicHostnameUtilsImpl { // (3) Remove the trailing '.'. // WARNING: May mutate |hostname| in place. // NOTE(wub): Only (2) and (3) are implemented for now. - static std::string NormalizeHostname(quiche::QuicheStringPiece hostname); + // NOLINTNEXTLINE(readability-identifier-naming) + static std::string NormalizeHostname(absl::string_view hostname); private: QuicHostnameUtilsImpl() = delete; diff --git a/source/extensions/quic_listeners/quiche/platform/quic_macros_impl.h b/source/extensions/quic_listeners/quiche/platform/quic_macros_impl.h deleted file mode 100644 index b8b70a0426b43..0000000000000 --- a/source/extensions/quic_listeners/quiche/platform/quic_macros_impl.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -// NOLINT(namespace-envoy) - -// This file is part of the QUICHE platform implementation, and is not to be -// consumed or referenced directly by other Envoy code. It serves purely as a -// porting layer for QUICHE. - -#include "absl/base/attributes.h" - -#define QUIC_MUST_USE_RESULT_IMPL ABSL_MUST_USE_RESULT -#define QUIC_UNUSED_IMPL ABSL_ATTRIBUTE_UNUSED -#define QUIC_CONST_INIT_IMPL ABSL_CONST_INIT diff --git a/source/extensions/quic_listeners/quiche/platform/quic_mem_slice_impl.cc b/source/extensions/quic_listeners/quiche/platform/quic_mem_slice_impl.cc index 903ee1332d04e..f1c21d0509f76 100644 --- a/source/extensions/quic_listeners/quiche/platform/quic_mem_slice_impl.cc +++ b/source/extensions/quic_listeners/quiche/platform/quic_mem_slice_impl.cc @@ -29,15 +29,11 @@ QuicMemSliceImpl::QuicMemSliceImpl(Envoy::Buffer::Instance& buffer, size_t lengt } const char* QuicMemSliceImpl::data() const { - Envoy::Buffer::RawSliceVector slices = single_slice_buffer_.getRawSlices(/*max_slices=*/1); - ASSERT(slices.size() <= 1); - return !slices.empty() ? static_cast(slices[0].mem_) : nullptr; + return reinterpret_cast(single_slice_buffer_.frontSlice().mem_); } size_t QuicMemSliceImpl::firstSliceLength(Envoy::Buffer::Instance& buffer) { - Envoy::Buffer::RawSliceVector slices = buffer.getRawSlices(/*max_slices=*/1); - ASSERT(slices.size() == 1); - return slices[0].len_; + return buffer.frontSlice().len_; } } // namespace quic diff --git a/source/extensions/quic_listeners/quiche/platform/quic_mem_slice_span_impl.cc b/source/extensions/quic_listeners/quiche/platform/quic_mem_slice_span_impl.cc index c2eb527d6584b..9e46c37df344d 100644 --- a/source/extensions/quic_listeners/quiche/platform/quic_mem_slice_span_impl.cc +++ b/source/extensions/quic_listeners/quiche/platform/quic_mem_slice_span_impl.cc @@ -10,7 +10,8 @@ namespace quic { -quiche::QuicheStringPiece QuicMemSliceSpanImpl::GetData(size_t index) { +// NOLINTNEXTLINE(readability-identifier-naming) +absl::string_view QuicMemSliceSpanImpl::GetData(size_t index) { Envoy::Buffer::RawSliceVector slices = buffer_->getRawSlices(/*max_slices=*/index + 1); ASSERT(slices.size() > index); return {reinterpret_cast(slices[index].mem_), slices[index].len_}; diff --git a/source/extensions/quic_listeners/quiche/platform/quic_mem_slice_span_impl.h b/source/extensions/quic_listeners/quiche/platform/quic_mem_slice_span_impl.h index 1824fb8d1fa54..ef40e63870573 100644 --- a/source/extensions/quic_listeners/quiche/platform/quic_mem_slice_span_impl.h +++ b/source/extensions/quic_listeners/quiche/platform/quic_mem_slice_span_impl.h @@ -9,7 +9,7 @@ #include "envoy/buffer/buffer.h" #include "absl/container/fixed_array.h" -#include "quiche/common/platform/api/quiche_string_piece.h" +#include "absl/strings/string_view.h" #include "quiche/quic/core/quic_types.h" #include "quiche/quic/platform/api/quic_mem_slice.h" @@ -43,9 +43,13 @@ class QuicMemSliceSpanImpl { } // QuicMemSliceSpan - quiche::QuicheStringPiece GetData(size_t index); + // NOLINTNEXTLINE(readability-identifier-naming) + absl::string_view GetData(size_t index); + // NOLINTNEXTLINE(readability-identifier-naming) QuicByteCount total_length() { return buffer_->length(); }; + // NOLINTNEXTLINE(readability-identifier-naming) size_t NumSlices() { return buffer_->getRawSlices().size(); } + // NOLINTNEXTLINE(readability-identifier-naming) template QuicByteCount ConsumeAll(ConsumeFunction consume); bool empty() const { return buffer_->length() == 0; } @@ -54,6 +58,7 @@ class QuicMemSliceSpanImpl { }; template +// NOLINTNEXTLINE(readability-identifier-naming) QuicByteCount QuicMemSliceSpanImpl::ConsumeAll(ConsumeFunction consume) { size_t saved_length = 0; for (auto& slice : buffer_->getRawSlices()) { diff --git a/source/extensions/quic_listeners/quiche/platform/quiche_ptr_util_impl.h b/source/extensions/quic_listeners/quiche/platform/quic_testvalue_impl.h similarity index 52% rename from source/extensions/quic_listeners/quiche/platform/quiche_ptr_util_impl.h rename to source/extensions/quic_listeners/quiche/platform/quic_testvalue_impl.h index aaebe5d5c3527..4b0201c35af67 100644 --- a/source/extensions/quic_listeners/quiche/platform/quiche_ptr_util_impl.h +++ b/source/extensions/quic_listeners/quiche/platform/quic_testvalue_impl.h @@ -6,12 +6,11 @@ // consumed or referenced directly by other Envoy code. It serves purely as a // porting layer for QUICHE. -#include "absl/memory/memory.h" +#include "absl/strings/string_view.h" -namespace quiche { +namespace quic { -template std::unique_ptr QuicheWrapUniqueImpl(T* ptr) { - return absl::WrapUnique(ptr); -} +// NOLINTNEXTLINE(readability-identifier-naming) +template void AdjustTestValueImpl(absl::string_view /*label*/, T* /*var*/) {} -} // namespace quiche +} // namespace quic diff --git a/source/extensions/quic_listeners/quiche/platform/quic_udp_socket_platform_impl.h b/source/extensions/quic_listeners/quiche/platform/quic_udp_socket_platform_impl.h index 248cfc193e029..1e88abe466cc1 100644 --- a/source/extensions/quic_listeners/quiche/platform/quic_udp_socket_platform_impl.h +++ b/source/extensions/quic_listeners/quiche/platform/quic_udp_socket_platform_impl.h @@ -19,4 +19,7 @@ inline bool GetGooglePacketHeadersFromControlMessageImpl(struct ::cmsghdr* /*cms return false; } +// NOLINTNEXTLINE(readability-identifier-naming) +inline void SetGoogleSocketOptionsImpl(int /*fd*/) {} + } // namespace quic diff --git a/source/extensions/quic_listeners/quiche/platform/quiche_arraysize_impl.h b/source/extensions/quic_listeners/quiche/platform/quiche_arraysize_impl.h deleted file mode 100644 index 7a23b53da85de..0000000000000 --- a/source/extensions/quic_listeners/quiche/platform/quiche_arraysize_impl.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "absl/base/macros.h" - -// NOLINT(namespace-envoy) - -// This file is part of the QUICHE platform implementation, and is not to be -// consumed or referenced directly by other Envoy code. It serves purely as a -// porting layer for QUICHE. - -#define QUICHE_ARRAYSIZE_IMPL(array) ABSL_ARRAYSIZE(array) diff --git a/source/extensions/quic_listeners/quiche/platform/quiche_optional_impl.h b/source/extensions/quic_listeners/quiche/platform/quiche_optional_impl.h deleted file mode 100644 index f8b2b6c0800d4..0000000000000 --- a/source/extensions/quic_listeners/quiche/platform/quiche_optional_impl.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "absl/types/optional.h" - -// NOLINT(namespace-envoy) - -// This file is part of the QUICHE platform implementation, and is not to be -// consumed or referenced directly by other Envoy code. It serves purely as a -// porting layer for QUICHE. - -namespace quiche { - -template using QuicheOptionalImpl = absl::optional; - -#define QUICHE_NULLOPT_IMPL absl::nullopt - -} // namespace quiche diff --git a/source/extensions/quic_listeners/quiche/platform/quiche_text_utils_impl.h b/source/extensions/quic_listeners/quiche/platform/quiche_text_utils_impl.h index 3a6d1a393a8b3..7b87c1cd61e81 100644 --- a/source/extensions/quic_listeners/quiche/platform/quiche_text_utils_impl.h +++ b/source/extensions/quic_listeners/quiche/platform/quiche_text_utils_impl.h @@ -2,7 +2,6 @@ #include "common/common/base64.h" -#include "extensions/quic_listeners/quiche/platform/quiche_optional_impl.h" #include "extensions/quic_listeners/quiche/platform/quiche_string_piece_impl.h" #include "extensions/quic_listeners/quiche/platform/string_utils.h" @@ -13,6 +12,7 @@ #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/strings/str_split.h" +#include "absl/types/optional.h" // NOLINT(namespace-envoy) @@ -25,58 +25,16 @@ namespace quiche { class QuicheTextUtilsImpl { public: // NOLINTNEXTLINE(readability-identifier-naming) - static bool StartsWith(QuicheStringPieceImpl data, QuicheStringPieceImpl prefix) { - return absl::StartsWith(data, prefix); - } - - // NOLINTNEXTLINE(readability-identifier-naming) - static bool EndsWith(QuicheStringPieceImpl data, QuicheStringPieceImpl suffix) { - return absl::EndsWith(data, suffix); - } - - // NOLINTNEXTLINE(readability-identifier-naming) - static bool EndsWithIgnoreCase(QuicheStringPieceImpl data, QuicheStringPieceImpl suffix) { - return absl::EndsWithIgnoreCase(data, suffix); - } - - // NOLINTNEXTLINE(readability-identifier-naming) - static std::string ToLower(QuicheStringPieceImpl data) { return absl::AsciiStrToLower(data); } + static std::string ToLower(absl::string_view data) { return absl::AsciiStrToLower(data); } // NOLINTNEXTLINE(readability-identifier-naming) - static void RemoveLeadingAndTrailingWhitespace(QuicheStringPieceImpl* data) { + static void RemoveLeadingAndTrailingWhitespace(absl::string_view* data) { *data = absl::StripAsciiWhitespace(*data); } - // NOLINTNEXTLINE(readability-identifier-naming) - static bool StringToUint64(QuicheStringPieceImpl in, uint64_t* out) { - return absl::SimpleAtoi(in, out); - } - - // NOLINTNEXTLINE(readability-identifier-naming) - static bool StringToInt(QuicheStringPieceImpl in, int* out) { return absl::SimpleAtoi(in, out); } - - // NOLINTNEXTLINE(readability-identifier-naming) - static bool StringToUint32(QuicheStringPieceImpl in, uint32_t* out) { - return absl::SimpleAtoi(in, out); - } - - // NOLINTNEXTLINE(readability-identifier-naming) - static bool StringToSizeT(QuicheStringPieceImpl in, size_t* out) { - return absl::SimpleAtoi(in, out); - } - - // NOLINTNEXTLINE(readability-identifier-naming) - static std::string Uint64ToString(uint64_t in) { return absl::StrCat(in); } - - // NOLINTNEXTLINE(readability-identifier-naming) - static std::string HexEncode(QuicheStringPieceImpl data) { return absl::BytesToHexString(data); } - // NOLINTNEXTLINE(readability-identifier-naming) static std::string Hex(uint32_t v) { return absl::StrCat(absl::Hex(v)); } - // NOLINTNEXTLINE(readability-identifier-naming) - static std::string HexDecode(QuicheStringPieceImpl data) { return absl::HexStringToBytes(data); } - // NOLINTNEXTLINE(readability-identifier-naming) static void Base64Encode(const uint8_t* data, size_t data_len, std::string* output) { *output = @@ -84,27 +42,28 @@ class QuicheTextUtilsImpl { } // NOLINTNEXTLINE(readability-identifier-naming) - static QuicheOptionalImpl Base64Decode(QuicheStringPieceImpl input) { + static absl::optional Base64Decode(absl::string_view input) { return Envoy::Base64::decodeWithoutPadding(input); } // NOLINTNEXTLINE(readability-identifier-naming) - static std::string HexDump(QuicheStringPieceImpl binary_data) { - return quiche::HexDump(binary_data); - } + static std::string Uint64ToString(uint64_t in) { return absl::StrCat(in); } + + // NOLINTNEXTLINE(readability-identifier-naming) + static std::string HexDump(absl::string_view binary_data) { return quiche::HexDump(binary_data); } // NOLINTNEXTLINE(readability-identifier-naming) - static bool ContainsUpperCase(QuicheStringPieceImpl data) { + static bool ContainsUpperCase(absl::string_view data) { return std::any_of(data.begin(), data.end(), absl::ascii_isupper); } // NOLINTNEXTLINE(readability-identifier-naming) - static bool IsAllDigits(QuicheStringPieceImpl data) { + static bool IsAllDigits(absl::string_view data) { return std::all_of(data.begin(), data.end(), absl::ascii_isdigit); } // NOLINTNEXTLINE(readability-identifier-naming) - static std::vector Split(QuicheStringPieceImpl data, char delim) { + static std::vector Split(absl::string_view data, char delim) { return absl::StrSplit(data, delim); } }; diff --git a/source/extensions/quic_listeners/quiche/platform/quiche_time_utils_impl.cc b/source/extensions/quic_listeners/quiche/platform/quiche_time_utils_impl.cc index 3260eafee4da0..5387e059876ae 100644 --- a/source/extensions/quic_listeners/quiche/platform/quiche_time_utils_impl.cc +++ b/source/extensions/quic_listeners/quiche/platform/quiche_time_utils_impl.cc @@ -9,7 +9,7 @@ namespace quiche { namespace { -QuicheOptional quicheUtcDateTimeToUnixSecondsInner(int year, int month, int day, int hour, +absl::optional quicheUtcDateTimeToUnixSecondsInner(int year, int month, int day, int hour, int minute, int second) { const absl::CivilSecond civil_time(year, month, day, hour, minute, second); if (second != 60 && (civil_time.year() != year || civil_time.month() != month || @@ -24,7 +24,7 @@ QuicheOptional quicheUtcDateTimeToUnixSecondsInner(int year, int month, } // namespace // NOLINTNEXTLINE(readability-identifier-naming) -QuicheOptional QuicheUtcDateTimeToUnixSecondsImpl(int year, int month, int day, int hour, +absl::optional QuicheUtcDateTimeToUnixSecondsImpl(int year, int month, int day, int hour, int minute, int second) { // Handle leap seconds without letting any other irregularities happen. if (second == 60) { diff --git a/source/extensions/quic_listeners/quiche/platform/quiche_time_utils_impl.h b/source/extensions/quic_listeners/quiche/platform/quiche_time_utils_impl.h index a1b70b70a51ea..5e2ef79567f53 100644 --- a/source/extensions/quic_listeners/quiche/platform/quiche_time_utils_impl.h +++ b/source/extensions/quic_listeners/quiche/platform/quiche_time_utils_impl.h @@ -10,12 +10,12 @@ #include "absl/time/civil_time.h" #include "absl/time/time.h" -#include "quiche/common/platform/api/quiche_optional.h" +#include "absl/types/optional.h" namespace quiche { // NOLINTNEXTLINE(readability-identifier-naming) -QuicheOptional QuicheUtcDateTimeToUnixSecondsImpl(int year, int month, int day, int hour, +absl::optional QuicheUtcDateTimeToUnixSecondsImpl(int year, int month, int day, int hour, int minute, int second); } // namespace quiche diff --git a/source/extensions/quic_listeners/quiche/platform/spdy_endianness_util_impl.h b/source/extensions/quic_listeners/quiche/platform/spdy_endianness_util_impl.h deleted file mode 100644 index 737b81ee29140..0000000000000 --- a/source/extensions/quic_listeners/quiche/platform/spdy_endianness_util_impl.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include - -#include "envoy/common/platform.h" - -// NOLINT(namespace-envoy) - -// This file is part of the QUICHE platform implementation, and is not to be -// consumed or referenced directly by other Envoy code. It serves purely as a -// porting layer for QUICHE. - -namespace spdy { - -inline uint16_t SpdyNetToHost16Impl(uint16_t x) { return ntohs(x); } - -inline uint32_t SpdyNetToHost32Impl(uint32_t x) { return ntohl(x); } - -// TODO: implement -inline uint64_t SpdyNetToHost64Impl(uint64_t /*x*/) { return 0; } - -inline uint16_t SpdyHostToNet16Impl(uint16_t x) { return htons(x); } - -inline uint32_t SpdyHostToNet32Impl(uint32_t x) { return htonl(x); } - -// TODO: implement -inline uint64_t SpdyHostToNet64Impl(uint64_t /*x*/) { return 0; } - -} // namespace spdy diff --git a/source/extensions/quic_listeners/quiche/platform/spdy_flags_impl.h b/source/extensions/quic_listeners/quiche/platform/spdy_flags_impl.h index a3cbd680ffc5f..833562fab5b9c 100644 --- a/source/extensions/quic_listeners/quiche/platform/spdy_flags_impl.h +++ b/source/extensions/quic_listeners/quiche/platform/spdy_flags_impl.h @@ -8,9 +8,9 @@ #include "extensions/quic_listeners/quiche/platform/flags_impl.h" -#define GetSpdyReloadableFlagImpl(flag) quiche::FLAGS_spdy_reloadable_flag_##flag->value() +#define GetSpdyReloadableFlagImpl(flag) quiche::FLAGS_quic_reloadable_flag_##flag->value() -#define GetSpdyRestartFlagImpl(flag) quiche::FLAGS_spdy_restart_flag_##flag->value() +#define GetSpdyRestartFlagImpl(flag) quiche::FLAGS_quic_restart_flag_##flag->value() #define SPDY_CODE_COUNT_N_IMPL(flag, instance, total) \ do { \ diff --git a/source/extensions/quic_listeners/quiche/platform/spdy_string_utils_impl.h b/source/extensions/quic_listeners/quiche/platform/spdy_string_utils_impl.h index 41fa3cad815fa..4b01b2dbddb32 100644 --- a/source/extensions/quic_listeners/quiche/platform/spdy_string_utils_impl.h +++ b/source/extensions/quic_listeners/quiche/platform/spdy_string_utils_impl.h @@ -50,7 +50,7 @@ inline std::string SpdyHexEncodeUInt32AndTrimImpl(uint32_t data) { inline std::string SpdyHexDumpImpl(absl::string_view data) { return quiche::HexDump(data); } struct SpdyStringPieceCaseHashImpl { - size_t operator()(quiche::QuicheStringPiece data) const { + size_t operator()(absl::string_view data) const { std::string lower = absl::AsciiStrToLower(data); return absl::Hash()(lower); } diff --git a/source/extensions/quic_listeners/quiche/quic_filter_manager_connection_impl.cc b/source/extensions/quic_listeners/quiche/quic_filter_manager_connection_impl.cc index 3e30e6ec5779f..4954196bfa473 100644 --- a/source/extensions/quic_listeners/quiche/quic_filter_manager_connection_impl.cc +++ b/source/extensions/quic_listeners/quiche/quic_filter_manager_connection_impl.cc @@ -42,6 +42,11 @@ void QuicFilterManagerConnectionImpl::enableHalfClose(bool enabled) { RELEASE_ASSERT(!enabled, "Quic connection doesn't support half close."); } +bool QuicFilterManagerConnectionImpl::isHalfCloseEnabled() { + // Quic doesn't support half close. + return false; +} + void QuicFilterManagerConnectionImpl::setBufferLimits(uint32_t /*limit*/) { // Currently read buffer is capped by connection level flow control. And write buffer limit is set // during construction. Changing the buffer limit during the life time of the connection is not diff --git a/source/extensions/quic_listeners/quiche/quic_filter_manager_connection_impl.h b/source/extensions/quic_listeners/quiche/quic_filter_manager_connection_impl.h index 8f01d03ca6b9c..06ef6a9cb98b4 100644 --- a/source/extensions/quic_listeners/quiche/quic_filter_manager_connection_impl.h +++ b/source/extensions/quic_listeners/quiche/quic_filter_manager_connection_impl.h @@ -35,6 +35,7 @@ class QuicFilterManagerConnectionImpl : public Network::ConnectionImplBase { NOT_REACHED_GCOVR_EXCL_LINE; } void enableHalfClose(bool enabled) override; + bool isHalfCloseEnabled() override; void close(Network::ConnectionCloseType type) override; Event::Dispatcher& dispatcher() override { return dispatcher_; } std::string nextProtocol() const override { return EMPTY_STRING; } diff --git a/source/extensions/quic_listeners/quiche/spdy_server_push_utils_for_envoy.cc b/source/extensions/quic_listeners/quiche/spdy_server_push_utils_for_envoy.cc index 3bd0bc2950b20..5ac5738c4bfe1 100644 --- a/source/extensions/quic_listeners/quiche/spdy_server_push_utils_for_envoy.cc +++ b/source/extensions/quic_listeners/quiche/spdy_server_push_utils_for_envoy.cc @@ -12,25 +12,29 @@ using spdy::SpdyHeaderBlock; namespace quic { // static +// NOLINTNEXTLINE(readability-identifier-naming) std::string SpdyServerPushUtils::GetPromisedUrlFromHeaders(const SpdyHeaderBlock& /*headers*/) { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } // static std::string +// NOLINTNEXTLINE(readability-identifier-naming) SpdyServerPushUtils::GetPromisedHostNameFromHeaders(const SpdyHeaderBlock& /*headers*/) { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } // static +// NOLINTNEXTLINE(readability-identifier-naming) bool SpdyServerPushUtils::PromisedUrlIsValid(const SpdyHeaderBlock& /*headers*/) { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } // static -std::string SpdyServerPushUtils::GetPushPromiseUrl(quiche::QuicheStringPiece /*scheme*/, - quiche::QuicheStringPiece /*authority*/, - quiche::QuicheStringPiece /*path*/) { +// NOLINTNEXTLINE(readability-identifier-naming) +std::string SpdyServerPushUtils::GetPushPromiseUrl(absl::string_view /*scheme*/, + absl::string_view /*authority*/, + absl::string_view /*path*/) { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } diff --git a/source/extensions/stat_sinks/hystrix/hystrix.cc b/source/extensions/stat_sinks/hystrix/hystrix.cc index a35f67a8d3f77..6f4a1808accf2 100644 --- a/source/extensions/stat_sinks/hystrix/hystrix.cc +++ b/source/extensions/stat_sinks/hystrix/hystrix.cc @@ -339,7 +339,7 @@ void HystrixSink::flush(Stats::MetricSnapshot& snapshot) { } incCounter(); std::stringstream ss; - Upstream::ClusterManager::ClusterInfoMap clusters = server_.clusterManager().clusters(); + Upstream::ClusterManager::ClusterInfoMaps all_clusters = server_.clusterManager().clusters(); // Save a map of the relevant histograms per cluster in a convenient format. absl::node_hash_map time_histograms; @@ -370,7 +370,7 @@ void HystrixSink::flush(Stats::MetricSnapshot& snapshot) { } } - for (auto& cluster : clusters) { + for (auto& cluster : all_clusters.active_clusters_) { Upstream::ClusterInfoConstSharedPtr cluster_info = cluster.second.get().info(); std::unique_ptr& cluster_stats_cache_ptr = @@ -407,9 +407,9 @@ void HystrixSink::flush(Stats::MetricSnapshot& snapshot) { } // check if any clusters were removed, and remove from cache - if (clusters.size() < cluster_stats_cache_map_.size()) { + if (all_clusters.active_clusters_.size() < cluster_stats_cache_map_.size()) { for (auto it = cluster_stats_cache_map_.begin(); it != cluster_stats_cache_map_.end();) { - if (clusters.find(it->first) == clusters.end()) { + if (all_clusters.active_clusters_.find(it->first) == all_clusters.active_clusters_.end()) { auto next_it = std::next(it); cluster_stats_cache_map_.erase(it); it = next_it; diff --git a/source/extensions/transport_sockets/tls/context_impl.cc b/source/extensions/transport_sockets/tls/context_impl.cc index e163eddfc8b48..e79a1aeadb6dc 100644 --- a/source/extensions/transport_sockets/tls/context_impl.cc +++ b/source/extensions/transport_sockets/tls/context_impl.cc @@ -417,9 +417,11 @@ ContextImpl::ContextImpl(Stats::Scope& scope, const Envoy::Ssl::ContextConfig& c !tls_certificate.password().empty() ? const_cast(tls_certificate.password().c_str()) : nullptr)); + if (pkey == nullptr || !SSL_CTX_use_PrivateKey(ctx.ssl_ctx_.get(), pkey.get())) { - throw EnvoyException( - absl::StrCat("Failed to load private key from ", tls_certificate.privateKeyPath())); + throw EnvoyException(fmt::format("Failed to load private key from {}, Cause: {}", + tls_certificate.privateKeyPath(), + Utility::getLastCryptoError().value_or("unknown"))); } #ifdef BORINGSSL_FIPS diff --git a/source/extensions/transport_sockets/tls/ssl_socket.cc b/source/extensions/transport_sockets/tls/ssl_socket.cc index 50b2d27926e21..37a1f8547952b 100644 --- a/source/extensions/transport_sockets/tls/ssl_socket.cc +++ b/source/extensions/transport_sockets/tls/ssl_socket.cc @@ -293,6 +293,17 @@ void SslSocket::shutdownSsl() { if (info_->state() != Ssl::SocketState::ShutdownSent && callbacks_->connection().state() != Network::Connection::State::Closed) { int rc = SSL_shutdown(rawSsl()); + if constexpr (Event::PlatformDefaultTriggerType == Event::FileTriggerType::EmulatedEdge) { + // Windows operate under `EmulatedEdge`. These are level events that are artificially + // made to behave like edge events. And if the rc is 0 then in that case we want read + // activation resumption. This code is protected with an `constexpr` if, to minimize the tax + // on POSIX systems that operate in Edge events. + if (rc == 0) { + // See https://www.openssl.org/docs/manmaster/man3/SSL_shutdown.html + // if return value is 0, Call SSL_read() to do a bidirectional shutdown. + callbacks_->setReadBufferReady(); + } + } ENVOY_CONN_LOG(debug, "SSL shutdown: rc={}", callbacks_->connection(), rc); drainErrorQueue(); info_->setState(Ssl::SocketState::ShutdownSent); diff --git a/source/extensions/transport_sockets/tls/ssl_socket.h b/source/extensions/transport_sockets/tls/ssl_socket.h index 4c5f38e0fb143..81b4712979fd7 100644 --- a/source/extensions/transport_sockets/tls/ssl_socket.h +++ b/source/extensions/transport_sockets/tls/ssl_socket.h @@ -70,8 +70,6 @@ class SslSocket : public Network::TransportSocket, void onFailure() override; Network::TransportSocketCallbacks* transportSocketCallbacks() override { return callbacks_; } - SSL* rawSslForTest() const { return rawSsl(); } - protected: SSL* rawSsl() const { return info_->ssl_.get(); } diff --git a/source/extensions/upstreams/http/http/BUILD b/source/extensions/upstreams/http/http/BUILD index 4c0b5be394b94..3b777db5fd986 100644 --- a/source/extensions/upstreams/http/http/BUILD +++ b/source/extensions/upstreams/http/http/BUILD @@ -33,6 +33,7 @@ envoy_cc_library( hdrs = [ "upstream_request.h", ], + visibility = ["//visibility:public"], deps = [ "//include/envoy/http:codes_interface", "//include/envoy/http:conn_pool_interface", diff --git a/source/extensions/upstreams/http/http/upstream_request.h b/source/extensions/upstreams/http/http/upstream_request.h index ff0650a3b231a..68cd57d0fae93 100644 --- a/source/extensions/upstreams/http/http/upstream_request.h +++ b/source/extensions/upstreams/http/http/upstream_request.h @@ -45,7 +45,7 @@ class HttpConnPool : public Router::GenericConnPool, public Envoy::Http::Connect bool valid() { return conn_pool_ != nullptr; } -private: +protected: // Points to the actual connection pool to create streams from. Envoy::Http::ConnectionPool::Instance* conn_pool_{}; Envoy::Http::ConnectionPool::Cancellable* conn_pool_stream_handle_{}; diff --git a/source/extensions/upstreams/http/tcp/BUILD b/source/extensions/upstreams/http/tcp/BUILD index 6daa95ce15d7e..e99752677e315 100644 --- a/source/extensions/upstreams/http/tcp/BUILD +++ b/source/extensions/upstreams/http/tcp/BUILD @@ -33,6 +33,7 @@ envoy_cc_library( hdrs = [ "upstream_request.h", ], + visibility = ["//visibility:public"], deps = [ "//include/envoy/http:codes_interface", "//include/envoy/http:filter_interface", diff --git a/source/extensions/upstreams/tcp/generic/BUILD b/source/extensions/upstreams/tcp/generic/BUILD index d6e2f2f3cae22..dc1ae3eb91168 100644 --- a/source/extensions/upstreams/tcp/generic/BUILD +++ b/source/extensions/upstreams/tcp/generic/BUILD @@ -19,6 +19,7 @@ envoy_cc_extension( security_posture = "robust_to_untrusted_downstream", visibility = ["//visibility:public"], deps = [ + "//source/common/http:codec_client_lib", "//source/common/tcp_proxy:upstream_lib", "@envoy_api//envoy/extensions/upstreams/tcp/generic/v3:pkg_cc_proto", ], diff --git a/source/extensions/upstreams/tcp/generic/config.cc b/source/extensions/upstreams/tcp/generic/config.cc index 634862885f5c8..675eda9122f3f 100644 --- a/source/extensions/upstreams/tcp/generic/config.cc +++ b/source/extensions/upstreams/tcp/generic/config.cc @@ -2,6 +2,7 @@ #include "envoy/upstream/cluster_manager.h" +#include "common/http/codec_client.h" #include "common/tcp_proxy/upstream.h" namespace Envoy { @@ -19,16 +20,11 @@ TcpProxy::GenericConnPoolPtr GenericConnPoolFactory::createGenericConnPool( if (!cluster) { return nullptr; } - // TODO(snowp): Ideally we should prevent this from being configured, but that's tricky to get - // right since whether a cluster is invalid depends on both the tcp_proxy config + cluster - // config. - if ((cluster->info()->features() & Upstream::ClusterInfo::Features::HTTP2) == 0) { - ENVOY_LOG_MISC(error, "Attempted to tunnel over HTTP/1.1, this is not supported. Set " - "http2_protocol_options on the cluster."); - return nullptr; - } - auto ret = std::make_unique(cluster_name, cluster_manager, context, - config.value(), upstream_callbacks); + auto pool_type = ((cluster->info()->features() & Upstream::ClusterInfo::Features::HTTP2) != 0) + ? Http::CodecClient::Type::HTTP2 + : Http::CodecClient::Type::HTTP1; + auto ret = std::make_unique( + cluster_name, cluster_manager, context, config.value(), upstream_callbacks, pool_type); return (ret->valid() ? std::move(ret) : nullptr); } auto ret = std::make_unique(cluster_name, cluster_manager, context, diff --git a/source/extensions/wasm_runtime/null/BUILD b/source/extensions/wasm_runtime/null/BUILD new file mode 100644 index 0000000000000..63969c889c256 --- /dev/null +++ b/source/extensions/wasm_runtime/null/BUILD @@ -0,0 +1,21 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_extension", + "envoy_extension_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_extension_package() + +envoy_cc_extension( + name = "config", + srcs = ["config.cc"], + security_posture = "unknown", + status = "alpha", + deps = [ + "//include/envoy/registry", + "//source/extensions/common/wasm:wasm_runtime_factory_interface", + "@proxy_wasm_cpp_host//:null_lib", + ], +) diff --git a/source/extensions/wasm_runtime/null/config.cc b/source/extensions/wasm_runtime/null/config.cc new file mode 100644 index 0000000000000..3515c9462ce17 --- /dev/null +++ b/source/extensions/wasm_runtime/null/config.cc @@ -0,0 +1,25 @@ +#include "envoy/registry/registry.h" + +#include "extensions/common/wasm/wasm_runtime_factory.h" + +#include "include/proxy-wasm/null.h" + +namespace Envoy { +namespace Extensions { +namespace Common { +namespace Wasm { + +class NullRuntimeFactory : public WasmRuntimeFactory { +public: + WasmVmPtr createWasmVm() override { return proxy_wasm::createNullVm(); } + + absl::string_view name() override { return "envoy.wasm.runtime.null"; } + absl::string_view shortName() override { return "null"; } +}; + +REGISTER_FACTORY(NullRuntimeFactory, WasmRuntimeFactory); + +} // namespace Wasm +} // namespace Common +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/wasm_runtime/v8/BUILD b/source/extensions/wasm_runtime/v8/BUILD new file mode 100644 index 0000000000000..8785616044d74 --- /dev/null +++ b/source/extensions/wasm_runtime/v8/BUILD @@ -0,0 +1,23 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_extension", + "envoy_extension_package", +) +load("//bazel:envoy_select.bzl", "envoy_select_wasm_v8") + +licenses(["notice"]) # Apache 2 + +envoy_extension_package() + +envoy_cc_extension( + name = "config", + srcs = ["config.cc"], + security_posture = "unknown", + status = "alpha", + deps = [ + "//include/envoy/registry", + "//source/extensions/common/wasm:wasm_runtime_factory_interface", + ] + envoy_select_wasm_v8([ + "@proxy_wasm_cpp_host//:v8_lib", + ]), +) diff --git a/source/extensions/wasm_runtime/v8/config.cc b/source/extensions/wasm_runtime/v8/config.cc new file mode 100644 index 0000000000000..1061b17b2b9df --- /dev/null +++ b/source/extensions/wasm_runtime/v8/config.cc @@ -0,0 +1,27 @@ +#include "envoy/registry/registry.h" + +#include "extensions/common/wasm/wasm_runtime_factory.h" + +#include "include/proxy-wasm/v8.h" + +namespace Envoy { +namespace Extensions { +namespace Common { +namespace Wasm { + +class V8RuntimeFactory : public WasmRuntimeFactory { +public: + WasmVmPtr createWasmVm() override { return proxy_wasm::createV8Vm(); } + + absl::string_view name() override { return "envoy.wasm.runtime.v8"; } + absl::string_view shortName() override { return "v8"; } +}; + +#if defined(ENVOY_WASM_V8) +REGISTER_FACTORY(V8RuntimeFactory, WasmRuntimeFactory); +#endif + +} // namespace Wasm +} // namespace Common +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/wasm_runtime/wasmtime/BUILD b/source/extensions/wasm_runtime/wasmtime/BUILD new file mode 100644 index 0000000000000..d0adea5660c67 --- /dev/null +++ b/source/extensions/wasm_runtime/wasmtime/BUILD @@ -0,0 +1,23 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_extension", + "envoy_extension_package", +) +load("//bazel:envoy_select.bzl", "envoy_select_wasm_wasmtime") + +licenses(["notice"]) # Apache 2 + +envoy_extension_package() + +envoy_cc_extension( + name = "config", + srcs = ["config.cc"], + security_posture = "unknown", + status = "alpha", + deps = [ + "//include/envoy/registry", + "//source/extensions/common/wasm:wasm_runtime_factory_interface", + ] + envoy_select_wasm_wasmtime([ + "@proxy_wasm_cpp_host//:wasmtime_lib", + ]), +) diff --git a/source/extensions/wasm_runtime/wasmtime/config.cc b/source/extensions/wasm_runtime/wasmtime/config.cc new file mode 100644 index 0000000000000..a407d847bdfdc --- /dev/null +++ b/source/extensions/wasm_runtime/wasmtime/config.cc @@ -0,0 +1,27 @@ +#include "envoy/registry/registry.h" + +#include "extensions/common/wasm/wasm_runtime_factory.h" + +#include "include/proxy-wasm/wasmtime.h" + +namespace Envoy { +namespace Extensions { +namespace Common { +namespace Wasm { + +class WasmtimeRuntimeFactory : public WasmRuntimeFactory { +public: + WasmVmPtr createWasmVm() override { return proxy_wasm::createWasmtimeVm(); } + + absl::string_view name() override { return "envoy.wasm.runtime.wasmtime"; } + absl::string_view shortName() override { return "wasmtime"; } +}; + +#if defined(ENVOY_WASM_WASMTIME) +REGISTER_FACTORY(WasmtimeRuntimeFactory, WasmRuntimeFactory); +#endif + +} // namespace Wasm +} // namespace Common +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/wasm_runtime/wavm/BUILD b/source/extensions/wasm_runtime/wavm/BUILD new file mode 100644 index 0000000000000..c9a5153efe31f --- /dev/null +++ b/source/extensions/wasm_runtime/wavm/BUILD @@ -0,0 +1,23 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_extension", + "envoy_extension_package", +) +load("//bazel:envoy_select.bzl", "envoy_select_wasm_wavm") + +licenses(["notice"]) # Apache 2 + +envoy_extension_package() + +envoy_cc_extension( + name = "config", + srcs = ["config.cc"], + security_posture = "unknown", + status = "alpha", + deps = [ + "//include/envoy/registry", + "//source/extensions/common/wasm:wasm_runtime_factory_interface", + ] + envoy_select_wasm_wavm([ + "@proxy_wasm_cpp_host//:wavm_lib", + ]), +) diff --git a/source/extensions/wasm_runtime/wavm/config.cc b/source/extensions/wasm_runtime/wavm/config.cc new file mode 100644 index 0000000000000..d50119cf784d1 --- /dev/null +++ b/source/extensions/wasm_runtime/wavm/config.cc @@ -0,0 +1,27 @@ +#include "envoy/registry/registry.h" + +#include "extensions/common/wasm/wasm_runtime_factory.h" + +#include "include/proxy-wasm/wavm.h" + +namespace Envoy { +namespace Extensions { +namespace Common { +namespace Wasm { + +class WavmRuntimeFactory : public WasmRuntimeFactory { +public: + WasmVmPtr createWasmVm() override { return proxy_wasm::createWavmVm(); } + + absl::string_view name() override { return "envoy.wasm.runtime.wavm"; } + absl::string_view shortName() override { return "wavm"; } +}; + +#if defined(ENVOY_WASM_WAVM) +REGISTER_FACTORY(WavmRuntimeFactory, WasmRuntimeFactory); +#endif + +} // namespace Wasm +} // namespace Common +} // namespace Extensions +} // namespace Envoy diff --git a/source/server/BUILD b/source/server/BUILD index c3404818a2172..cc21ce681f280 100644 --- a/source/server/BUILD +++ b/source/server/BUILD @@ -418,6 +418,7 @@ envoy_cc_library( "//include/envoy/network:dns_interface", "//include/envoy/server:bootstrap_extension_config_interface", "//include/envoy/server:drain_manager_interface", + "//include/envoy/server:fatal_action_interface", "//include/envoy/server:instance_interface", "//include/envoy/server:listener_manager_interface", "//include/envoy/server:options_interface", @@ -444,6 +445,7 @@ envoy_cc_library( "//source/common/router:rds_lib", "//source/common/runtime:runtime_lib", "//source/common/secret:secret_manager_impl_lib", + "//source/common/signal:fatal_error_handler_lib", "//source/common/singleton:manager_impl_lib", "//source/common/stats:thread_local_store_lib", "//source/common/upstream:cluster_manager_lib", diff --git a/source/server/admin/admin.h b/source/server/admin/admin.h index de79c60b19923..6e78cea526c63 100644 --- a/source/server/admin/admin.h +++ b/source/server/admin/admin.h @@ -258,6 +258,10 @@ class AdminImpl : public Admin, Event::TimerPtr createScaledTimer(OverloadTimerType, Event::TimerCb callback) override { return dispatcher_.createTimer(callback); } + Event::TimerPtr createScaledTimer(Event::ScaledTimerMinimum, + Event::TimerCb callback) override { + return dispatcher_.createTimer(callback); + } Event::Dispatcher& dispatcher_; const OverloadActionState inactive_ = OverloadActionState::inactive(); diff --git a/source/server/admin/clusters_handler.cc b/source/server/admin/clusters_handler.cc index e0e17350b7c91..801045e63ecd5 100644 --- a/source/server/admin/clusters_handler.cc +++ b/source/server/admin/clusters_handler.cc @@ -100,7 +100,9 @@ void setHealthFlag(Upstream::Host::HealthFlag flag, const Upstream::Host& host, // TODO(efimki): Add support of text readouts stats. void ClustersHandler::writeClustersAsJson(Buffer::Instance& response) { envoy::admin::v3::Clusters clusters; - for (const auto& [name, cluster_ref] : server_.clusterManager().clusters()) { + // TODO(mattklein123): Add ability to see warming clusters in admin output. + auto all_clusters = server_.clusterManager().clusters(); + for (const auto& [name, cluster_ref] : all_clusters.active_clusters_) { const Upstream::Cluster& cluster = cluster_ref.get(); Upstream::ClusterInfoConstSharedPtr cluster_info = cluster.info(); @@ -184,7 +186,9 @@ void ClustersHandler::writeClustersAsJson(Buffer::Instance& response) { // TODO(efimki): Add support of text readouts stats. void ClustersHandler::writeClustersAsText(Buffer::Instance& response) { - for (const auto& [name, cluster_ref] : server_.clusterManager().clusters()) { + // TODO(mattklein123): Add ability to see warming clusters in admin output. + auto all_clusters = server_.clusterManager().clusters(); + for (const auto& [name, cluster_ref] : all_clusters.active_clusters_) { const Upstream::Cluster& cluster = cluster_ref.get(); const std::string& cluster_name = cluster.info()->name(); addOutlierInfo(cluster_name, cluster.outlierDetector(), response); diff --git a/source/server/admin/config_dump_handler.cc b/source/server/admin/config_dump_handler.cc index 9e1d54e9d3e9b..e255f084757c6 100644 --- a/source/server/admin/config_dump_handler.cc +++ b/source/server/admin/config_dump_handler.cc @@ -149,7 +149,9 @@ ConfigDumpHandler::addResourceToDump(envoy::admin::v3::ConfigDump& dump, const std::string& resource, bool include_eds) const { Envoy::Server::ConfigTracker::CbsMap callbacks_map = config_tracker_.getCallbacksMap(); if (include_eds) { - if (!server_.clusterManager().clusters().empty()) { + // TODO(mattklein123): Add ability to see warming clusters in admin output. + auto all_clusters = server_.clusterManager().clusters(); + if (!all_clusters.active_clusters_.empty()) { callbacks_map.emplace("endpoint", [this] { return dumpEndpointConfigs(); }); } } @@ -195,7 +197,9 @@ void ConfigDumpHandler::addAllConfigToDump(envoy::admin::v3::ConfigDump& dump, bool include_eds) const { Envoy::Server::ConfigTracker::CbsMap callbacks_map = config_tracker_.getCallbacksMap(); if (include_eds) { - if (!server_.clusterManager().clusters().empty()) { + // TODO(mattklein123): Add ability to see warming clusters in admin output. + auto all_clusters = server_.clusterManager().clusters(); + if (!all_clusters.active_clusters_.empty()) { callbacks_map.emplace("endpoint", [this] { return dumpEndpointConfigs(); }); } } @@ -220,8 +224,9 @@ void ConfigDumpHandler::addAllConfigToDump(envoy::admin::v3::ConfigDump& dump, ProtobufTypes::MessagePtr ConfigDumpHandler::dumpEndpointConfigs() const { auto endpoint_config_dump = std::make_unique(); - - for (const auto& [name, cluster_ref] : server_.clusterManager().clusters()) { + // TODO(mattklein123): Add ability to see warming clusters in admin output. + auto all_clusters = server_.clusterManager().clusters(); + for (const auto& [name, cluster_ref] : all_clusters.active_clusters_) { UNREFERENCED_PARAMETER(name); const Upstream::Cluster& cluster = cluster_ref.get(); Upstream::ClusterInfoConstSharedPtr cluster_info = cluster.info(); diff --git a/source/server/api_listener_impl.h b/source/server/api_listener_impl.h index b0dd0ef701c34..e56fec57d73b8 100644 --- a/source/server/api_listener_impl.h +++ b/source/server/api_listener_impl.h @@ -99,6 +99,7 @@ class ApiListenerImplBase : public ApiListener, NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } void enableHalfClose(bool) override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } + bool isHalfCloseEnabled() override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } void close(Network::ConnectionCloseType) override {} Event::Dispatcher& dispatcher() override { return parent_.parent_.factory_context_.dispatcher(); diff --git a/source/server/connection_handler_impl.cc b/source/server/connection_handler_impl.cc index beba66b72f0b5..91b92f763ffc7 100644 --- a/source/server/connection_handler_impl.cc +++ b/source/server/connection_handler_impl.cc @@ -460,9 +460,10 @@ void ConnectionHandlerImpl::ActiveTcpListener::resumeListening() { void ConnectionHandlerImpl::ActiveTcpListener::newConnection( Network::ConnectionSocketPtr&& socket, std::unique_ptr stream_info) { - // Refresh local address in case it was restored by a listener filter like the original_dst - // filter. + // Refresh addresses in case they are modified by listener filters, such as proxy protocol or + // original_dst. stream_info->setDownstreamLocalAddress(socket->localAddress()); + stream_info->setDownstreamRemoteAddress(socket->remoteAddress()); // Find matching filter chain. const auto filter_chain = config_->filterChainManager().findFilterChain(*socket); diff --git a/source/server/hot_restarting_parent.cc b/source/server/hot_restarting_parent.cc index 874c19b11a5a0..6898c0db9999e 100644 --- a/source/server/hot_restarting_parent.cc +++ b/source/server/hot_restarting_parent.cc @@ -29,7 +29,7 @@ void HotRestartingParent::initialize(Event::Dispatcher& dispatcher, Server::Inst ASSERT(events == Event::FileReadyType::Read); onSocketEvent(); }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read); internal_ = std::make_unique(&server); } diff --git a/source/server/listener_impl.cc b/source/server/listener_impl.cc index b62d36dd071b1..517f6263565e0 100644 --- a/source/server/listener_impl.cc +++ b/source/server/listener_impl.cc @@ -38,15 +38,22 @@ namespace Envoy { namespace Server { namespace { +bool anyFilterChain( + const envoy::config::listener::v3::Listener& config, + std::function predicate) { + return (config.has_default_filter_chain() && predicate(config.default_filter_chain())) || + std::any_of(config.filter_chains().begin(), config.filter_chains().end(), predicate); +} + bool needTlsInspector(const envoy::config::listener::v3::Listener& config) { - return std::any_of(config.filter_chains().begin(), config.filter_chains().end(), - [](const auto& filter_chain) { - const auto& matcher = filter_chain.filter_chain_match(); - return matcher.transport_protocol() == "tls" || - (matcher.transport_protocol().empty() && - (!matcher.server_names().empty() || - !matcher.application_protocols().empty())); - }) && + return anyFilterChain(config, + [](const auto& filter_chain) { + const auto& matcher = filter_chain.filter_chain_match(); + return matcher.transport_protocol() == "tls" || + (matcher.transport_protocol().empty() && + (!matcher.server_names().empty() || + !matcher.application_protocols().empty())); + }) && !std::any_of( config.listener_filters().begin(), config.listener_filters().end(), [](const auto& filter) { @@ -55,6 +62,14 @@ bool needTlsInspector(const envoy::config::listener::v3::Listener& config) { filter.name() == "envoy.listener.tls_inspector"; }); } + +bool usesProxyProto(const envoy::config::listener::v3::Listener& config) { + // TODO(#14085): `use_proxy_proto` should be deprecated. + // Checking only the first or default filter chain is done for backwards compatibility. + return PROTOBUF_GET_WRAPPED_OR_DEFAULT( + config.filter_chains().empty() ? config.default_filter_chain() : config.filter_chains()[0], + use_proxy_proto, false); +} } // namespace ListenSocketFactoryImpl::ListenSocketFactoryImpl(ListenerComponentFactory& factory, @@ -458,21 +473,22 @@ void ListenerImpl::createListenerFilterFactories(Network::Socket::Type socket_ty } void ListenerImpl::validateFilterChains(Network::Socket::Type socket_type) { - if (config_.filter_chains().empty() && (socket_type == Network::Socket::Type::Stream || - !udp_listener_factory_->isTransportConnectionless())) { + if (config_.filter_chains().empty() && !config_.has_default_filter_chain() && + (socket_type == Network::Socket::Type::Stream || + !udp_listener_factory_->isTransportConnectionless())) { // If we got here, this is a tcp listener or connection-oriented udp listener, so ensure there // is a filter chain specified throw EnvoyException(fmt::format("error adding listener '{}': no filter chains specified", address_->asString())); } else if (udp_listener_factory_ != nullptr && !udp_listener_factory_->isTransportConnectionless()) { - for (auto& filter_chain : config_.filter_chains()) { - // Early fail if any filter chain doesn't have transport socket configured. - if (!filter_chain.has_transport_socket()) { - throw EnvoyException(fmt::format("error adding listener '{}': no transport socket " - "specified for connection oriented UDP listener", - address_->asString())); - } + // Early fail if any filter chain doesn't have transport socket configured. + if (anyFilterChain(config_, [](const auto& filter_chain) { + return !filter_chain.has_transport_socket(); + })) { + throw EnvoyException(fmt::format("error adding listener '{}': no transport socket " + "specified for connection oriented UDP listener", + address_->asString())); } } } @@ -528,7 +544,7 @@ void ListenerImpl::buildProxyProtocolListenerFilter() { // TODO(jrajahalme): This is the last listener filter on purpose. When filter chain matching // is implemented, this needs to be run after the filter chain has been // selected. - if (PROTOBUF_GET_WRAPPED_OR_DEFAULT(config_.filter_chains()[0], use_proxy_proto, false)) { + if (usesProxyProto(config_)) { auto& factory = Config::Utility::getAndCheckFactoryByName( Extensions::ListenerFilters::ListenerFilterNames::get().ProxyProtocol); @@ -712,10 +728,8 @@ bool ListenerImpl::supportUpdateFilterChain(const envoy::config::listener::v3::L return false; } - // See buildProxyProtocolListenerFilter(). Full listener update guarantees at least 1 filter chain - // at tcp listener. - if (PROTOBUF_GET_WRAPPED_OR_DEFAULT(config_.filter_chains()[0], use_proxy_proto, false) ^ - PROTOBUF_GET_WRAPPED_OR_DEFAULT(config.filter_chains()[0], use_proxy_proto, false)) { + // See buildProxyProtocolListenerFilter(). + if (usesProxyProto(config_) ^ usesProxyProto(config)) { return false; } diff --git a/source/server/overload_manager_impl.cc b/source/server/overload_manager_impl.cc index f399bb96ecfe7..22fea559efa7a 100644 --- a/source/server/overload_manager_impl.cc +++ b/source/server/overload_manager_impl.cc @@ -51,6 +51,11 @@ class ThreadLocalOverloadStateImpl : public ThreadLocalOverloadState { return scaled_timer_manager_->createTimer(minimum, std::move(callback)); } + Event::TimerPtr createScaledTimer(Event::ScaledTimerMinimum minimum, + Event::TimerCb callback) override { + return scaled_timer_manager_->createTimer(minimum, std::move(callback)); + } + void setState(NamedOverloadActionSymbolTable::Symbol action, OverloadActionState state) { actions_[action.index()] = state; if (scaled_timer_action_.has_value() && scaled_timer_action_.value() == action) { diff --git a/source/server/server.cc b/source/server/server.cc index ee7792c719c72..214f9d0459388 100644 --- a/source/server/server.cc +++ b/source/server/server.cc @@ -20,6 +20,7 @@ #include "envoy/network/dns.h" #include "envoy/registry/registry.h" #include "envoy/server/bootstrap_extension_config.h" +#include "envoy/server/instance.h" #include "envoy/server/options.h" #include "envoy/upstream/cluster_manager.h" @@ -40,6 +41,7 @@ #include "common/protobuf/utility.h" #include "common/router/rds_impl.h" #include "common/runtime/runtime_impl.h" +#include "common/signal/fatal_error_handler.h" #include "common/singleton/manager_impl.h" #include "common/stats/thread_local_store.h" #include "common/stats/timespan_impl.h" @@ -420,6 +422,26 @@ void InstanceImpl::initialize(const Options& options, factory.createBootstrapExtension(*config, serverFactoryContext())); } + // Register the fatal actions. + { + FatalAction::FatalActionPtrList safe_actions; + FatalAction::FatalActionPtrList unsafe_actions; + for (const auto& action_config : bootstrap_.fatal_actions()) { + auto& factory = + Config::Utility::getAndCheckFactory( + action_config.config()); + auto action = factory.createFatalActionFromProto(action_config, this); + + if (action->isAsyncSignalSafe()) { + safe_actions.push_back(std::move(action)); + } else { + unsafe_actions.push_back(std::move(action)); + } + } + Envoy::FatalErrorHandler::registerFatalActions( + std::move(safe_actions), std::move(unsafe_actions), api_->threadFactory()); + } + if (!bootstrap_.default_socket_interface().empty()) { auto& sock_name = bootstrap_.default_socket_interface(); auto sock = const_cast(Network::socketInterface(sock_name)); @@ -733,6 +755,7 @@ void InstanceImpl::terminate() { restarter_.shutdown(); ENVOY_LOG(info, "exiting"); ENVOY_FLUSH_LOG(); + FatalErrorHandler::clearFatalActionsOnTerminate(); } Runtime::Loader& InstanceImpl::runtime() { return Runtime::LoaderSingleton::get(); } diff --git a/test/common/buffer/buffer_fuzz.cc b/test/common/buffer/buffer_fuzz.cc index 4128ceea866da..7dc34ca3e58fa 100644 --- a/test/common/buffer/buffer_fuzz.cc +++ b/test/common/buffer/buffer_fuzz.cc @@ -126,6 +126,8 @@ class StringBuffer : public Buffer::Instance { return {{const_cast(start()), size_}}; } + Buffer::RawSlice frontSlice() const override { return {const_cast(start()), size_}; } + uint64_t length() const override { return size_; } void* linearize(uint32_t /*size*/) override { diff --git a/test/common/buffer/owned_impl_test.cc b/test/common/buffer/owned_impl_test.cc index dc15d80b4b5d2..e7249e2b65220 100644 --- a/test/common/buffer/owned_impl_test.cc +++ b/test/common/buffer/owned_impl_test.cc @@ -1256,6 +1256,13 @@ TEST_F(OwnedImplTest, MoveSmallSliceIntoNotEnoughFreeSpace) { TestBufferMove(4096 - 127, 128, 2); } +TEST_F(OwnedImplTest, FrontSlice) { + Buffer::OwnedImpl buffer; + EXPECT_EQ(0, buffer.frontSlice().len_); + buffer.add("a"); + EXPECT_EQ(1, buffer.frontSlice().len_); +} + } // namespace } // namespace Buffer } // namespace Envoy diff --git a/test/common/common/BUILD b/test/common/common/BUILD index 8f9ec5324dc86..726f2caa28dc4 100644 --- a/test/common/common/BUILD +++ b/test/common/common/BUILD @@ -210,6 +210,7 @@ envoy_cc_test( ], deps = [ "//source/common/common:utility_lib", + "//test/common/stats:stat_test_utility_lib", "//test/test_common:simulated_time_system_lib", "//test/test_common:test_time_lib", "//test/test_common:utility_lib", @@ -269,6 +270,17 @@ envoy_cc_test( deps = ["//source/common/common:callback_impl_lib"], ) +envoy_cc_benchmark_binary( + name = "re_speed_test", + srcs = ["re_speed_test.cc"], + external_deps = ["benchmark"], + deps = [ + "//source/common/common:assert_lib", + "//source/common/common:utility_lib", + "@com_googlesource_code_re2//:re2", + ], +) + envoy_cc_benchmark_binary( name = "utility_speed_test", srcs = ["utility_speed_test.cc"], diff --git a/test/common/common/perf_annotation_disabled_test.cc b/test/common/common/perf_annotation_disabled_test.cc index 8109cad634578..b5f67aa756d56 100644 --- a/test/common/common/perf_annotation_disabled_test.cc +++ b/test/common/common/perf_annotation_disabled_test.cc @@ -16,6 +16,8 @@ TEST(PerfAnnotationDisabled, testPerfAnnotation) { PERF_RECORD(perf, "beta", "1"); PERF_RECORD(perf, "alpha", "2"); PERF_RECORD(perf, "beta", "3"); + { PERF_OWNED_OPERATION(op); } + { PERF_OWNED_RECORD(op, "gamma", "4"); } std::string report = PERF_TO_STRING(); EXPECT_TRUE(report.empty()); PERF_CLEAR(); diff --git a/test/common/common/perf_annotation_test.cc b/test/common/common/perf_annotation_test.cc index ee23ffd9e47f7..0927ff9717490 100644 --- a/test/common/common/perf_annotation_test.cc +++ b/test/common/common/perf_annotation_test.cc @@ -16,6 +16,8 @@ namespace Envoy { class PerfAnnotationTest : public testing::Test { protected: void TearDown() override { PERF_CLEAR(); } + + PERF_OWNER(owned_perf); }; // Tests that the macros produce something in the report that includes the categories @@ -26,6 +28,10 @@ TEST_F(PerfAnnotationTest, TestMacros) { PERF_RECORD(perf, "beta", "1"); PERF_RECORD(perf, "alpha", "2"); PERF_RECORD(perf, "beta", "3"); + + { PERF_OWNED_OPERATION(owned_perf); } + { PERF_OWNED_RECORD(owned_perf, "gamma", "4"); } + std::string report = PERF_TO_STRING(); EXPECT_TRUE(report.find(" alpha ") != std::string::npos) << report; EXPECT_TRUE(report.find(" 0 ") != std::string::npos) << report; @@ -35,6 +41,8 @@ TEST_F(PerfAnnotationTest, TestMacros) { EXPECT_TRUE(report.find(" 2 ") != std::string::npos) << report; EXPECT_TRUE(report.find(" beta ") != std::string::npos) << report; EXPECT_TRUE(report.find(" 3 ") != std::string::npos) << report; + EXPECT_TRUE(report.find(" gamma ") != std::string::npos) << report; + EXPECT_TRUE(report.find(" 4 ") != std::string::npos) << report; PERF_DUMP(); } diff --git a/test/common/common/re_speed_test.cc b/test/common/common/re_speed_test.cc new file mode 100644 index 0000000000000..0db62906e281e --- /dev/null +++ b/test/common/common/re_speed_test.cc @@ -0,0 +1,128 @@ +// Note: this should be run with --compilation_mode=opt, and would benefit from +// a quiescent system with disabled cstate power management. + +#include + +#include "common/common/assert.h" + +#include "absl/strings/string_view.h" +#include "benchmark/benchmark.h" +#include "re2/re2.h" + +// NOLINT(namespace-envoy) + +static const char* ClusterInputs[] = { + "cluster.no_trailing_dot", + "cluster.match.", + "cluster.match.normal", + "cluster.match.and.a.whole.lot.of.things.coming.after.the.matches.really.too.much.stuff", +}; + +static const char ClusterRePattern[] = "^cluster\\.((.*?)\\.)"; +static const char ClusterReAltPattern[] = "^cluster\\.(([^\\.]+)\\.).*"; + +// NOLINTNEXTLINE(readability-identifier-naming) +static void BM_StdRegex(benchmark::State& state) { + std::regex re(ClusterRePattern); + uint32_t passes = 0; + std::vector inputs; + for (const char* cluster_input : ClusterInputs) { + inputs.push_back(cluster_input); + } + + for (auto _ : state) { // NOLINT + for (const std::string& cluster_input : inputs) { + std::smatch match; + if (std::regex_search(cluster_input, match, re)) { + ASSERT(match.size() >= 3); + ASSERT(match[1] == "match."); + ASSERT(match[2] == "match"); + ++passes; + } + } + } + RELEASE_ASSERT(passes > 0, ""); +} +BENCHMARK(BM_StdRegex); + +// NOLINTNEXTLINE(readability-identifier-naming) +static void BM_StdRegexStringView(benchmark::State& state) { + std::regex re(ClusterRePattern); + std::vector inputs; + for (const char* cluster_input : ClusterInputs) { + inputs.push_back(cluster_input); + } + uint32_t passes = 0; + for (auto _ : state) { // NOLINT + for (absl::string_view cluster_input : inputs) { + std::match_results smatch; + if (std::regex_search(cluster_input.begin(), cluster_input.end(), smatch, re)) { + ASSERT(smatch.size() >= 3); + ASSERT(smatch[1] == "match."); + ASSERT(smatch[2] == "match"); + ++passes; + } + } + } + RELEASE_ASSERT(passes > 0, ""); +} +BENCHMARK(BM_StdRegexStringView); + +// NOLINTNEXTLINE(readability-identifier-naming) +static void BM_StdRegexStringViewAltPattern(benchmark::State& state) { + std::regex re(ClusterReAltPattern); + std::vector inputs; + for (const char* cluster_input : ClusterInputs) { + inputs.push_back(cluster_input); + } + uint32_t passes = 0; + for (auto _ : state) { // NOLINT + for (absl::string_view cluster_input : inputs) { + std::match_results smatch; + if (std::regex_search(cluster_input.begin(), cluster_input.end(), smatch, re)) { + ASSERT(smatch.size() >= 3); + ASSERT(smatch[1] == "match."); + ASSERT(smatch[2] == "match"); + ++passes; + } + } + } + RELEASE_ASSERT(passes > 0, ""); +} +BENCHMARK(BM_StdRegexStringViewAltPattern); + +// NOLINTNEXTLINE(readability-identifier-naming) +static void BM_RE2(benchmark::State& state) { + re2::RE2 re(ClusterRePattern); + uint32_t passes = 0; + for (auto _ : state) { // NOLINT + for (const char* cluster_input : ClusterInputs) { + re2::StringPiece match1, match2; + if (re2::RE2::PartialMatch(cluster_input, re, &match1, &match2)) { + ASSERT(match1 == "match."); + ASSERT(match2 == "match"); + ++passes; + } + } + } + RELEASE_ASSERT(passes > 0, ""); +} +BENCHMARK(BM_RE2); + +// NOLINTNEXTLINE(readability-identifier-naming) +static void BM_RE2_AltPattern(benchmark::State& state) { + re2::RE2 re(ClusterReAltPattern); + uint32_t passes = 0; + for (auto _ : state) { // NOLINT + for (const char* cluster_input : ClusterInputs) { + re2::StringPiece match1, match2; + if (re2::RE2::PartialMatch(cluster_input, re, &match1, &match2)) { + ASSERT(match1 == "match."); + ASSERT(match2 == "match"); + ++passes; + } + } + } + RELEASE_ASSERT(passes > 0, ""); +} +BENCHMARK(BM_RE2_AltPattern); diff --git a/test/common/common/utility_test.cc b/test/common/common/utility_test.cc index cda2a65f807ae..6f4f8a2a628b3 100644 --- a/test/common/common/utility_test.cc +++ b/test/common/common/utility_test.cc @@ -1,3 +1,4 @@ +#include #include #include #include @@ -8,6 +9,7 @@ #include "common/common/utility.h" +#include "test/common/stats/stat_test_utility.h" #include "test/test_common/simulated_time_system.h" #include "test/test_common/test_time.h" #include "test/test_common/utility.h" @@ -116,6 +118,60 @@ TEST(DateUtil, NowToMilliseconds) { EXPECT_EQ(12345067, DateUtil::nowToMilliseconds(test_time)); } +TEST(OutputBufferStream, FailsOnWriteToEmptyBuffer) { + constexpr char data = 'x'; + OutputBufferStream ostream{nullptr, 0}; + ASSERT_TRUE(ostream.good()); + + ostream << data; + + EXPECT_TRUE(ostream.bad()); +} + +TEST(OutputBufferStream, CanWriteToBuffer) { + constexpr char data[] = "123"; + std::array buffer; + + OutputBufferStream ostream{buffer.data(), buffer.size()}; + ASSERT_EQ(ostream.bytesWritten(), 0); + + ostream << data; + + EXPECT_EQ(ostream.contents(), data); + EXPECT_EQ(ostream.bytesWritten(), 3); +} + +TEST(OutputBufferStream, CannotOverwriteBuffer) { + constexpr char data[] = "123"; + std::array buffer; + + OutputBufferStream ostream{buffer.data(), buffer.size()}; + ASSERT_EQ(ostream.bytesWritten(), 0); + + // Initial write should stop before overflowing. + ostream << data << std::endl; + EXPECT_EQ(ostream.contents(), "12"); + EXPECT_EQ(ostream.bytesWritten(), 2); + + // Try a subsequent write, which shouldn't change anything since + // the buffer is full. + ostream << data << std::endl; + EXPECT_EQ(ostream.contents(), "12"); + EXPECT_EQ(ostream.bytesWritten(), 2); +} + +TEST(OutputBufferStream, DoesNotAllocateMemoryEvenIfWeTryToOverflowBuffer) { + constexpr char data[] = "123"; + std::array buffer; + Stats::TestUtil::MemoryTest memory_test; + + OutputBufferStream ostream{buffer.data(), buffer.size()}; + ostream << data << std::endl; + + EXPECT_EQ(memory_test.consumedBytes(), 0); + EXPECT_EQ(ostream.contents(), "12"); +} + TEST(InputConstMemoryStream, All) { { InputConstMemoryStream istream{nullptr, 0}; diff --git a/test/common/config/BUILD b/test/common/config/BUILD index 52c508569ec61..c95c4b8bb72e2 100644 --- a/test/common/config/BUILD +++ b/test/common/config/BUILD @@ -502,3 +502,13 @@ envoy_cc_test( "@envoy_api//envoy/service/discovery/v3:pkg_cc_proto", ], ) + +envoy_cc_test( + name = "watched_directory_test", + srcs = ["watched_directory_test.cc"], + deps = [ + "//source/common/config:watched_directory_lib", + "//test/mocks/event:event_mocks", + "//test/mocks/filesystem:filesystem_mocks", + ], +) diff --git a/test/common/config/version_converter_test.cc b/test/common/config/version_converter_test.cc index 65bb66145fc7d..1c7e949fb6257 100644 --- a/test/common/config/version_converter_test.cc +++ b/test/common/config/version_converter_test.cc @@ -71,6 +71,18 @@ TEST(VersionConverterProto, UpgradeNextVersion) { VersionConverter::upgrade(source, dst); } +// Validate that even if we pass in a newer proto version that is being passed off as an older +// version (e.g. via a type URL mistake), we don't crash. This is a regression test for +// https://github.com/envoyproxy/envoy/issues/13681. +TEST(VersionConverterProto, UpgradeWithConfusedTypes) { + test::common::config::NextVersion source_next; + source_next.mutable_new_message_in_this_version(); + test::common::config::PreviousVersion source; + ASSERT_TRUE(source.ParseFromString(source_next.SerializeAsString())); + test::common::config::NextVersion dst; + VersionConverter::upgrade(source, dst); +} + // Bad UTF-8 can fail wire cast during upgrade. TEST(VersionConverterTest, UpgradeException) { API_NO_BOOST(envoy::api::v2::Cluster) source; diff --git a/test/common/config/watched_directory_test.cc b/test/common/config/watched_directory_test.cc new file mode 100644 index 0000000000000..8988306d4ad4d --- /dev/null +++ b/test/common/config/watched_directory_test.cc @@ -0,0 +1,33 @@ +#include "envoy/filesystem/watcher.h" + +#include "common/config/watched_directory.h" + +#include "test/mocks/event/mocks.h" +#include "test/mocks/filesystem/mocks.h" + +#include "gtest/gtest.h" + +using testing::Return; +using testing::SaveArg; + +namespace Envoy { +namespace Config { + +TEST(WatchedDirectory, All) { + Event::MockDispatcher dispatcher; + envoy::config::core::v3::WatchedDirectory config; + config.set_path("foo/bar"); + auto* watcher = new Filesystem::MockWatcher(); + EXPECT_CALL(dispatcher, createFilesystemWatcher_()).WillOnce(Return(watcher)); + Filesystem::Watcher::OnChangedCb cb; + EXPECT_CALL(*watcher, addWatch("foo/bar/", Filesystem::Watcher::Events::MovedTo, _)) + .WillOnce(SaveArg<2>(&cb)); + WatchedDirectory wd(config, dispatcher); + bool called = false; + wd.setCallback([&called] { called = true; }); + cb(Filesystem::Watcher::Events::MovedTo); + EXPECT_TRUE(called); +} + +} // namespace Config +} // namespace Envoy diff --git a/test/common/conn_pool/conn_pool_base_test.cc b/test/common/conn_pool/conn_pool_base_test.cc index bf2b1946967cb..0096c95f46e2e 100644 --- a/test/common/conn_pool/conn_pool_base_test.cc +++ b/test/common/conn_pool/conn_pool_base_test.cc @@ -12,6 +12,7 @@ namespace Envoy { namespace ConnectionPool { using testing::AnyNumber; +using testing::Invoke; using testing::InvokeWithoutArgs; using testing::Return; @@ -21,7 +22,9 @@ class TestActiveClient : public ActiveClient { void close() override { onEvent(Network::ConnectionEvent::LocalClose); } uint64_t id() const override { return 1; } bool closingWithIncompleteStream() const override { return false; } - size_t numActiveStreams() const override { return 1; } + uint32_t numActiveStreams() const override { return active_streams_; } + + uint32_t active_streams_{}; }; class TestPendingStream : public PendingStream { @@ -37,8 +40,7 @@ class TestConnPoolImplBase : public ConnPoolImplBase { using ConnPoolImplBase::ConnPoolImplBase; ConnectionPool::Cancellable* newPendingStream(AttachContext& context) override { auto entry = std::make_unique(*this, context); - LinkedList::moveIntoList(std::move(entry), pending_streams_); - return pending_streams_.front().get(); + return addPendingStream(std::move(entry)); } MOCK_METHOD(ActiveClientPtr, instantiateActiveClient, ()); MOCK_METHOD(void, onPoolFailure, @@ -50,7 +52,7 @@ class TestConnPoolImplBase : public ConnPoolImplBase { class ConnPoolImplBaseTest : public testing::Test { public: ConnPoolImplBaseTest() - : pool_(host_, Upstream::ResourcePriority::Default, dispatcher_, nullptr, nullptr) { + : pool_(host_, Upstream::ResourcePriority::Default, dispatcher_, nullptr, nullptr, state_) { // Default connections to 1024 because the tests shouldn't be relying on the // connection resource limit for most tests. cluster_->resetResourceManager(1024, 1024, 1024, 1, 1); @@ -60,10 +62,20 @@ class ConnPoolImplBaseTest : public testing::Test { ret->real_host_description_ = descr_; return ret; })); + ON_CALL(pool_, onPoolReady(_, _)) + .WillByDefault(Invoke([](ActiveClient& client, AttachContext&) -> void { + ++(reinterpret_cast(&client)->active_streams_); + })); } +#define CHECK_STATE(active, pending, capacity) \ + EXPECT_EQ(state_.pending_streams_, pending); \ + EXPECT_EQ(state_.active_streams_, active); \ + EXPECT_EQ(state_.connecting_stream_capacity_, capacity) + uint32_t stream_limit_ = 100; uint32_t concurrent_streams_ = 1; + Upstream::ClusterConnectivityState state_; std::shared_ptr> descr_{ new NiceMock()}; std::shared_ptr cluster_{new NiceMock()}; @@ -79,10 +91,13 @@ TEST_F(ConnPoolImplBaseTest, BasicPrefetch) { ON_CALL(*cluster_, perUpstreamPrefetchRatio).WillByDefault(Return(1.5)); // On new stream, create 2 connections. + CHECK_STATE(0 /*active*/, 0 /*pending*/, 0 /*connecting capacity*/); EXPECT_CALL(pool_, instantiateActiveClient).Times(2); auto cancelable = pool_.newStream(context_); + CHECK_STATE(0 /*active*/, 1 /*pending*/, 2 /*connecting capacity*/); cancelable->cancel(ConnectionPool::CancelPolicy::CloseExcess); + CHECK_STATE(0 /*active*/, 0 /*pending*/, 1 /*connecting capacity*/); pool_.destructAllConnections(); } @@ -95,6 +110,7 @@ TEST_F(ConnPoolImplBaseTest, PrefetchOnDisconnect) { // On new stream, create 2 connections. EXPECT_CALL(pool_, instantiateActiveClient).Times(2); pool_.newStream(context_); + CHECK_STATE(0 /*active*/, 1 /*pending*/, 2 /*connecting capacity*/); // If a connection fails, existing connections are purged. If a retry causes // a new stream, make sure we create the correct number of connections. @@ -103,6 +119,7 @@ TEST_F(ConnPoolImplBaseTest, PrefetchOnDisconnect) { })); EXPECT_CALL(pool_, instantiateActiveClient).Times(1); clients_[0]->close(); + CHECK_STATE(0 /*active*/, 1 /*pending*/, 2 /*connecting capacity*/); EXPECT_CALL(pool_, onPoolFailure); pool_.destructAllConnections(); @@ -118,6 +135,7 @@ TEST_F(ConnPoolImplBaseTest, NoPrefetchIfUnhealthy) { // On new stream, create 1 connection. EXPECT_CALL(pool_, instantiateActiveClient).Times(1); auto cancelable = pool_.newStream(context_); + CHECK_STATE(0 /*active*/, 1 /*pending*/, 1 /*connecting capacity*/); cancelable->cancel(ConnectionPool::CancelPolicy::CloseExcess); pool_.destructAllConnections(); @@ -146,11 +164,13 @@ TEST_F(ConnPoolImplBaseTest, ExplicitPrefetch) { // With global prefetch off, we won't prefetch. EXPECT_FALSE(pool_.maybePrefetch(0)); + CHECK_STATE(0 /*active*/, 0 /*pending*/, 0 /*connecting capacity*/); // With prefetch ratio of 1.1, we'll prefetch two connections. // Currently, no number of subsequent calls to prefetch will increase that. EXPECT_TRUE(pool_.maybePrefetch(1.1)); EXPECT_TRUE(pool_.maybePrefetch(1.1)); EXPECT_FALSE(pool_.maybePrefetch(1.1)); + CHECK_STATE(0 /*active*/, 0 /*pending*/, 2 /*connecting capacity*/); // With a higher prefetch ratio, more connections may be prefetched. EXPECT_TRUE(pool_.maybePrefetch(3)); diff --git a/test/common/event/BUILD b/test/common/event/BUILD index 2eaba5a4f461a..d5448366b593a 100644 --- a/test/common/event/BUILD +++ b/test/common/event/BUILD @@ -11,7 +11,6 @@ envoy_package() envoy_cc_test( name = "dispatcher_impl_test", srcs = ["dispatcher_impl_test.cc"], - tags = ["fails_on_windows"], deps = [ "//source/common/api:api_lib", "//source/common/event:deferred_task", @@ -30,7 +29,6 @@ envoy_cc_test( envoy_cc_test( name = "file_event_impl_test", srcs = ["file_event_impl_test.cc"], - tags = ["fails_on_windows"], deps = [ "//include/envoy/event:file_event_interface", "//source/common/event:dispatcher_includes", diff --git a/test/common/event/dispatcher_impl_test.cc b/test/common/event/dispatcher_impl_test.cc index cbb0119f0ff27..468c79bb62b7a 100644 --- a/test/common/event/dispatcher_impl_test.cc +++ b/test/common/event/dispatcher_impl_test.cc @@ -458,6 +458,51 @@ TEST_F(DispatcherImplTest, IsThreadSafe) { EXPECT_FALSE(dispatcher_->isThreadSafe()); } +class TestFatalAction : public Server::Configuration::FatalAction { +public: + void run(const ScopeTrackedObject* /*current_object*/) override { ++times_ran_; } + bool isAsyncSignalSafe() const override { return true; } + int getNumTimesRan() { return times_ran_; } + +private: + int times_ran_ = 0; +}; + +TEST_F(DispatcherImplTest, OnlyRunsFatalActionsIfRunningOnSameThread) { + FatalAction::FatalActionPtrList actions; + actions.emplace_back(std::make_unique()); + auto* action = dynamic_cast(actions.front().get()); + + ASSERT_EQ(action->getNumTimesRan(), 0); + + // Should not run as dispatcher isn't running yet + auto non_running_dispatcher = api_->allocateDispatcher("non_running_thread"); + static_cast(non_running_dispatcher.get()) + ->runFatalActionsOnTrackedObject(actions); + ASSERT_EQ(action->getNumTimesRan(), 0); + + // Should not run when not on same thread + static_cast(dispatcher_.get())->runFatalActionsOnTrackedObject(actions); + ASSERT_EQ(action->getNumTimesRan(), 0); + + // Should run since on same thread as dispatcher + dispatcher_->post([this, &actions]() { + { + Thread::LockGuard lock(mu_); + static_cast(dispatcher_.get())->runFatalActionsOnTrackedObject(actions); + work_finished_ = true; + } + cv_.notifyOne(); + }); + + Thread::LockGuard lock(mu_); + while (!work_finished_) { + cv_.wait(mu_); + } + + EXPECT_EQ(action->getNumTimesRan(), 1); +} + class NotStartedDispatcherImplTest : public testing::Test { protected: NotStartedDispatcherImplTest() @@ -1202,7 +1247,7 @@ TEST_F(DispatcherWithWatchdogTest, TouchBeforeTimer) { } TEST_F(DispatcherWithWatchdogTest, TouchBeforeFdEvent) { - os_fd_t fd = os_sys_calls_.socket(AF_INET6, SOCK_STREAM, 0).rc_; + os_fd_t fd = os_sys_calls_.socket(AF_INET6, SOCK_DGRAM, 0).rc_; ASSERT_TRUE(SOCKET_VALID(fd)); ReadyWatcher watcher; @@ -1213,7 +1258,7 @@ TEST_F(DispatcherWithWatchdogTest, TouchBeforeFdEvent) { file_event->activate(FileReadyType::Read); InSequence s; - EXPECT_CALL(*watchdog_, touch()); + EXPECT_CALL(*watchdog_, touch()).Times(2); EXPECT_CALL(watcher, ready()); dispatcher_->run(Dispatcher::RunType::NonBlock); } diff --git a/test/common/event/file_event_impl_test.cc b/test/common/event/file_event_impl_test.cc index 7116fd8bc5f71..974c498dc905d 100644 --- a/test/common/event/file_event_impl_test.cc +++ b/test/common/event/file_event_impl_test.cc @@ -47,14 +47,9 @@ class FileEventImplTest : public testing::Test { Api::OsSysCalls& os_sys_calls_; }; -class FileEventImplActivateTest - : public testing::TestWithParam> { +class FileEventImplActivateTest : public testing::TestWithParam { public: - FileEventImplActivateTest() : os_sys_calls_(Api::OsSysCallsSingleton::get()) { - Runtime::LoaderSingleton::getExisting()->mergeValues( - {{"envoy.reloadable_features.activate_fds_next_event_loop", - activateFdsNextEventLoop() ? "true" : "false"}}); - } + FileEventImplActivateTest() : os_sys_calls_(Api::OsSysCallsSingleton::get()) {} static void onWatcherReady(evwatch*, const evwatch_prepare_cb_info*, void* arg) { // `arg` contains the ReadyWatcher passed in from evwatch_prepare_new. @@ -62,19 +57,15 @@ class FileEventImplActivateTest watcher->ready(); } - int domain() { - return std::get<0>(GetParam()) == Network::Address::IpVersion::v4 ? AF_INET : AF_INET6; - } - bool activateFdsNextEventLoop() { return std::get<1>(GetParam()); } + int domain() { return GetParam() == Network::Address::IpVersion::v4 ? AF_INET : AF_INET6; } protected: Api::OsSysCalls& os_sys_calls_; TestScopedRuntime scoped_runtime_; }; -INSTANTIATE_TEST_SUITE_P( - IpVersions, FileEventImplActivateTest, - testing::Combine(testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), testing::Bool())); +INSTANTIATE_TEST_SUITE_P(IpVersions, FileEventImplActivateTest, + testing::ValuesIn(TestEnvironment::getIpVersionsForTest())); TEST_P(FileEventImplActivateTest, Activate) { os_fd_t fd = os_sys_calls_.socket(domain(), SOCK_STREAM, 0).rc_; @@ -115,7 +106,7 @@ TEST_P(FileEventImplActivateTest, Activate) { } TEST_P(FileEventImplActivateTest, ActivateChaining) { - os_fd_t fd = os_sys_calls_.socket(domain(), SOCK_STREAM, 0).rc_; + os_fd_t fd = os_sys_calls_.socket(domain(), SOCK_DGRAM, 0).rc_; ASSERT_TRUE(SOCKET_VALID(fd)); Api::ApiPtr api = Api::createApiForTest(); @@ -160,29 +151,17 @@ TEST_P(FileEventImplActivateTest, ActivateChaining) { EXPECT_CALL(fd_event, ready()); EXPECT_CALL(read_event, ready()); EXPECT_CALL(write_event, ready()); - if (activateFdsNextEventLoop()) { - // Second loop iteration: handle write and close events scheduled while handling read. - EXPECT_CALL(prepare_watcher, ready()); - EXPECT_CALL(fd_event, ready()); - EXPECT_CALL(write_event, ready()); - EXPECT_CALL(closed_event, ready()); - // Third loop iteration: handle close event scheduled while handling write. - EXPECT_CALL(prepare_watcher, ready()); - EXPECT_CALL(fd_event, ready()); - EXPECT_CALL(closed_event, ready()); - // Fourth loop iteration: poll returned no new real events. - EXPECT_CALL(prepare_watcher, ready()); - } else { - // Same loop iteration activation: handle write and close events scheduled while handling read. - EXPECT_CALL(fd_event, ready()); - EXPECT_CALL(write_event, ready()); - EXPECT_CALL(closed_event, ready()); - // Second same loop iteration activation: handle close event scheduled while handling write. - EXPECT_CALL(fd_event, ready()); - EXPECT_CALL(closed_event, ready()); - // Second loop iteration: poll returned no new real events. - EXPECT_CALL(prepare_watcher, ready()); - } + // Second loop iteration: handle write and close events scheduled while handling read. + EXPECT_CALL(prepare_watcher, ready()); + EXPECT_CALL(fd_event, ready()); + EXPECT_CALL(write_event, ready()); + EXPECT_CALL(closed_event, ready()); + // Third loop iteration: handle close event scheduled while handling write. + EXPECT_CALL(prepare_watcher, ready()); + EXPECT_CALL(fd_event, ready()); + EXPECT_CALL(closed_event, ready()); + // Fourth loop iteration: poll returned no new real events. + EXPECT_CALL(prepare_watcher, ready()); file_event->activate(FileReadyType::Read); dispatcher->run(Event::Dispatcher::RunType::NonBlock); @@ -191,7 +170,7 @@ TEST_P(FileEventImplActivateTest, ActivateChaining) { } TEST_P(FileEventImplActivateTest, SetEnableCancelsActivate) { - os_fd_t fd = os_sys_calls_.socket(domain(), SOCK_STREAM, 0).rc_; + os_fd_t fd = os_sys_calls_.socket(domain(), SOCK_DGRAM, 0).rc_; ASSERT_TRUE(SOCKET_VALID(fd)); Api::ApiPtr api = Api::createApiForTest(); diff --git a/test/common/grpc/async_client_manager_impl_test.cc b/test/common/grpc/async_client_manager_impl_test.cc index 55d5c14e2fb11..448f52aa6140b 100644 --- a/test/common/grpc/async_client_manager_impl_test.cc +++ b/test/common/grpc/async_client_manager_impl_test.cc @@ -38,10 +38,10 @@ TEST_F(AsyncClientManagerImplTest, EnvoyGrpcOk) { envoy::config::core::v3::GrpcService grpc_service; grpc_service.mutable_envoy_grpc()->set_cluster_name("foo"); - Upstream::ClusterManager::ClusterInfoMap cluster_map; + Upstream::ClusterManager::ClusterInfoMaps cluster_maps; Upstream::MockClusterMockPrioritySet cluster; - cluster_map.emplace("foo", cluster); - EXPECT_CALL(cm_, clusters()).WillOnce(Return(cluster_map)); + cluster_maps.active_clusters_.emplace("foo", cluster); + EXPECT_CALL(cm_, clusters()).WillOnce(Return(cluster_maps)); EXPECT_CALL(cluster, info()); EXPECT_CALL(*cluster.info_, addedViaApi()); @@ -65,7 +65,8 @@ TEST_F(AsyncClientManagerImplTest, EnvoyGrpcDynamicCluster) { Upstream::ClusterManager::ClusterInfoMap cluster_map; Upstream::MockClusterMockPrioritySet cluster; cluster_map.emplace("foo", cluster); - EXPECT_CALL(cm_, clusters()).WillOnce(Return(cluster_map)); + EXPECT_CALL(cm_, clusters()) + .WillOnce(Return(Upstream::ClusterManager::ClusterInfoMaps{cluster_map, {}})); EXPECT_CALL(cluster, info()); EXPECT_CALL(*cluster.info_, addedViaApi()).WillOnce(Return(true)); EXPECT_THROW_WITH_MESSAGE( diff --git a/test/common/grpc/grpc_client_integration_test_harness.h b/test/common/grpc/grpc_client_integration_test_harness.h index be23d01b2791b..2e728d1d2c8df 100644 --- a/test/common/grpc/grpc_client_integration_test_harness.h +++ b/test/common/grpc/grpc_client_integration_test_harness.h @@ -298,8 +298,9 @@ class GrpcClientIntegrationTest : public GrpcClientIntegrationParamTest { EXPECT_CALL(*mock_host_, createConnection_(_, _)).WillRepeatedly(Return(connection_data)); EXPECT_CALL(*mock_host_, cluster()).WillRepeatedly(ReturnRef(*cluster_info_ptr_)); EXPECT_CALL(*mock_host_description_, locality()).WillRepeatedly(ReturnRef(host_locality_)); - http_conn_pool_ = Http::Http2::allocateConnPool( - *dispatcher_, random_, host_ptr_, Upstream::ResourcePriority::Default, nullptr, nullptr); + http_conn_pool_ = Http::Http2::allocateConnPool(*dispatcher_, random_, host_ptr_, + Upstream::ResourcePriority::Default, nullptr, + nullptr, state_); EXPECT_CALL(cm_, httpConnPoolForCluster(_, _, _, _)) .WillRepeatedly(Return(http_conn_pool_.get())); http_async_client_ = std::make_unique( @@ -456,6 +457,7 @@ class GrpcClientIntegrationTest : public GrpcClientIntegrationParamTest { const TestMetadata empty_metadata_; // Fake/mock infrastructure for Grpc::AsyncClientImpl upstream. + Upstream::ClusterConnectivityState state_; Network::TransportSocketPtr async_client_transport_socket_{new Network::RawBufferSocket()}; const std::string fake_cluster_name_{"fake_cluster"}; Upstream::MockClusterManager cm_; diff --git a/test/common/http/codec_client_test.cc b/test/common/http/codec_client_test.cc index 48a1dad0da8e5..25ba456a87fe6 100644 --- a/test/common/http/codec_client_test.cc +++ b/test/common/http/codec_client_test.cc @@ -374,6 +374,7 @@ TEST_P(CodecNetworkTest, SendData) { upstream_connection_->write(data, false); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance& data) -> Http::Status { EXPECT_EQ(full_data, data.toString()); + data.drain(data.length()); dispatcher_->exit(); return Http::okStatus(); })); @@ -397,10 +398,12 @@ TEST_P(CodecNetworkTest, SendHeadersAndClose) { .Times(2) .WillOnce(Invoke([&](Buffer::Instance& data) -> Http::Status { EXPECT_EQ(full_data, data.toString()); + data.drain(data.length()); return Http::okStatus(); })) .WillOnce(Invoke([&](Buffer::Instance& data) -> Http::Status { EXPECT_EQ("", data.toString()); + data.drain(data.length()); return Http::okStatus(); })); // Because the headers are not complete, the disconnect will reset the stream. @@ -435,6 +438,7 @@ TEST_P(CodecNetworkTest, SendHeadersAndCloseUnderReadDisable) { .Times(2) .WillOnce(Invoke([&](Buffer::Instance& data) -> Http::Status { EXPECT_EQ(full_data, data.toString()); + data.drain(data.length()); return Http::okStatus(); })) .WillOnce(Invoke([&](Buffer::Instance& data) -> Http::Status { diff --git a/test/common/http/conn_manager_impl_test_base.cc b/test/common/http/conn_manager_impl_test_base.cc index 9589d1cc3323f..f32f39b70258d 100644 --- a/test/common/http/conn_manager_impl_test_base.cc +++ b/test/common/http/conn_manager_impl_test_base.cc @@ -53,7 +53,7 @@ void HttpConnectionManagerImplTest::setup(bool ssl, const std::string& server_na server_name_ = server_name; ON_CALL(filter_callbacks_.connection_, ssl()).WillByDefault(Return(ssl_connection_)); ON_CALL(Const(filter_callbacks_.connection_), ssl()).WillByDefault(Return(ssl_connection_)); - ON_CALL(overload_manager_.overload_state_, createScaledTimer_) + ON_CALL(overload_manager_.overload_state_, createScaledTypedTimer_) .WillByDefault([&](auto, auto callback) { return filter_callbacks_.connection_.dispatcher_.createTimer(callback).release(); }); diff --git a/test/common/http/http1/conn_pool_test.cc b/test/common/http/http1/conn_pool_test.cc index 3803add0f7248..0e6e2a54cc29b 100644 --- a/test/common/http/http1/conn_pool_test.cc +++ b/test/common/http/http1/conn_pool_test.cc @@ -56,6 +56,7 @@ class ConnPoolImplForTest : public FixedHttpConnPoolImpl { : FixedHttpConnPoolImpl( Upstream::makeTestHost(cluster, "tcp://127.0.0.1:9000"), Upstream::ResourcePriority::Default, dispatcher, nullptr, nullptr, random_generator, + state_, [](HttpConnPoolImplBase* pool) { return std::make_unique(*pool); }, [](Upstream::Host::CreateConnectionData&, HttpConnPoolImplBase*) { return nullptr; // Not used: createCodecClient overloaded. @@ -66,7 +67,7 @@ class ConnPoolImplForTest : public FixedHttpConnPoolImpl { ~ConnPoolImplForTest() override { EXPECT_EQ(0U, ready_clients_.size()); EXPECT_EQ(0U, busy_clients_.size()); - EXPECT_EQ(0U, pending_streams_.size()); + EXPECT_FALSE(hasPendingStreams()); } struct TestCodecClient { @@ -121,6 +122,7 @@ class ConnPoolImplForTest : public FixedHttpConnPoolImpl { void expectAndRunUpstreamReady() { post_cb_(); } + Upstream::ClusterConnectivityState state_; Api::ApiPtr api_; Event::MockDispatcher& mock_dispatcher_; Event::PostCb post_cb_; diff --git a/test/common/http/http2/codec_impl_test.cc b/test/common/http/http2/codec_impl_test.cc index e2c749c559406..5430db5f61d33 100644 --- a/test/common/http/http2/codec_impl_test.cc +++ b/test/common/http/http2/codec_impl_test.cc @@ -782,8 +782,8 @@ TEST_P(Http2CodecImplTest, SmallMetadataVecTest) { // Generates a valid stream_id by sending a request header. TestRequestHeaderMapImpl request_headers; HttpTestUtility::addDefaultHeaders(request_headers); - EXPECT_CALL(request_decoder_, decodeHeaders_(_, true)); - EXPECT_TRUE(request_encoder_->encodeHeaders(request_headers, true).ok()); + EXPECT_CALL(request_decoder_, decodeHeaders_(_, false)); + EXPECT_TRUE(request_encoder_->encodeHeaders(request_headers, false).ok()); MetadataMapVector metadata_map_vector; const int size = 10; @@ -812,8 +812,8 @@ TEST_P(Http2CodecImplTest, LargeMetadataVecTest) { // Generates a valid stream_id by sending a request header. TestRequestHeaderMapImpl request_headers; HttpTestUtility::addDefaultHeaders(request_headers); - EXPECT_CALL(request_decoder_, decodeHeaders_(_, true)); - EXPECT_TRUE(request_encoder_->encodeHeaders(request_headers, true).ok()); + EXPECT_CALL(request_decoder_, decodeHeaders_(_, false)); + EXPECT_TRUE(request_encoder_->encodeHeaders(request_headers, false).ok()); MetadataMapVector metadata_map_vector; const int size = 10; @@ -839,8 +839,8 @@ TEST_P(Http2CodecImplTest, BadMetadataVecReceivedTest) { // Generates a valid stream_id by sending a request header. TestRequestHeaderMapImpl request_headers; HttpTestUtility::addDefaultHeaders(request_headers); - EXPECT_CALL(request_decoder_, decodeHeaders_(_, true)); - EXPECT_TRUE(request_encoder_->encodeHeaders(request_headers, true).ok()); + EXPECT_CALL(request_decoder_, decodeHeaders_(_, false)); + EXPECT_TRUE(request_encoder_->encodeHeaders(request_headers, false).ok()); MetadataMap metadata_map = { {"header_key1", "header_value1"}, @@ -886,6 +886,27 @@ TEST_P(Http2CodecImplTest, EncodeMetadataWhileDispatchingTest) { EXPECT_TRUE(request_encoder_->encodeHeaders(request_headers, true).ok()); } +// Verifies that metadata is not decoded after the stream ended. +TEST_P(Http2CodecImplTest, NoMetadataEndStreamTest) { + allow_metadata_ = true; + initialize(); + + // Generates a valid stream_id by sending a request header, and end stream. + TestRequestHeaderMapImpl request_headers; + HttpTestUtility::addDefaultHeaders(request_headers); + EXPECT_CALL(request_decoder_, decodeHeaders_(_, true)); + EXPECT_TRUE(request_encoder_->encodeHeaders(request_headers, true).ok()); + + const MetadataMap metadata_map = {{"header_key1", "header_value1"}}; + MetadataMapPtr metadata_map_ptr = std::make_unique(metadata_map); + MetadataMapVector metadata_map_vector; + metadata_map_vector.push_back(std::move(metadata_map_ptr)); + + // The metadata decoding will not be called after the stream has ended. + EXPECT_CALL(request_decoder_, decodeMetadata_(_)).Times(0); + request_encoder_->encodeMetadata(metadata_map_vector); +} + // Validate the keepalive PINGs are sent and received correctly. TEST_P(Http2CodecImplTest, ConnectionKeepalive) { constexpr uint32_t interval_ms = 100; diff --git a/test/common/http/http2/conn_pool_test.cc b/test/common/http/http2/conn_pool_test.cc index 90b7a48350bf3..47d6799a4c8d9 100644 --- a/test/common/http/http2/conn_pool_test.cc +++ b/test/common/http/http2/conn_pool_test.cc @@ -41,10 +41,11 @@ class TestConnPoolImpl : public FixedHttpConnPoolImpl { TestConnPoolImpl(Event::Dispatcher& dispatcher, Random::RandomGenerator& random_generator, Upstream::HostConstSharedPtr host, Upstream::ResourcePriority priority, const Network::ConnectionSocket::OptionsSharedPtr& options, - const Network::TransportSocketOptionsSharedPtr& transport_socket_options) + const Network::TransportSocketOptionsSharedPtr& transport_socket_options, + Envoy::Upstream::ClusterConnectivityState& state) : FixedHttpConnPoolImpl( std::move(host), std::move(priority), dispatcher, options, transport_socket_options, - random_generator, + random_generator, state, [](HttpConnPoolImplBase* pool) { return std::make_unique(*pool); }, [](Upstream::Host::CreateConnectionData&, HttpConnPoolImplBase*) { return nullptr; }, std::vector{Protocol::Http2}) {} @@ -73,8 +74,9 @@ class Http2ConnPoolImplTest : public testing::Test { Http2ConnPoolImplTest() : api_(Api::createApiForTest(stats_store_)), - pool_(std::make_unique( - dispatcher_, random_, host_, Upstream::ResourcePriority::Default, nullptr, nullptr)) { + pool_(std::make_unique(dispatcher_, random_, host_, + Upstream::ResourcePriority::Default, nullptr, + nullptr, state_)) { // Default connections to 1024 because the tests shouldn't be relying on the // connection resource limit for most tests. cluster_->resetResourceManager(1024, 1024, 1024, 1, 1); @@ -172,6 +174,12 @@ class Http2ConnPoolImplTest : public testing::Test { // Asserts that the provided requests receives onPoolFailure. void expectStreamReset(ActiveTestRequest& r); +// Use a macro to avoid tons of cut and paste, but to retain line numbers on error. +#define CHECK_STATE(active, pending, capacity) \ + EXPECT_EQ(state_.pending_streams_, pending); \ + EXPECT_EQ(state_.active_streams_, active); \ + EXPECT_EQ(state_.connecting_stream_capacity_, capacity); + /** * Closes a test client. */ @@ -195,6 +203,7 @@ class Http2ConnPoolImplTest : public testing::Test { MOCK_METHOD(void, onClientDestroy, ()); + Upstream::ClusterConnectivityState state_; int timer_index_{}; int connection_index_{}; Stats::IsolatedStoreImpl stats_store_; @@ -327,8 +336,8 @@ TEST_F(Http2ConnPoolImplTest, VerifyAlpnFallback) { // Recreate the conn pool so that the host re-evaluates the transport socket match, arriving at // our test transport socket factory. host_ = Upstream::makeTestHost(cluster_, "tcp://127.0.0.1:80"); - pool_ = std::make_unique(dispatcher_, random_, host_, - Upstream::ResourcePriority::Default, nullptr, nullptr); + pool_ = std::make_unique( + dispatcher_, random_, host_, Upstream::ResourcePriority::Default, nullptr, nullptr, state_); // This requires some careful set up of expectations ordering: the call to createTransportSocket // happens before all the connection set up but after the test client is created (due to some) @@ -960,8 +969,12 @@ TEST_F(Http2ConnPoolImplTest, VerifyBufferLimits) { InSequence s; expectClientCreate(8192); ActiveTestRequest r1(*this, 0, false); + // 1 stream. HTTP/2 defaults to 536870912 streams/connection. + CHECK_STATE(0 /*active*/, 1 /*pending*/, 536870912 /*capacity*/); expectClientConnect(0, r1); + // capacity goes down by one as one stream is used. + CHECK_STATE(1 /*active*/, 0 /*pending*/, 536870911 /*capacity*/); EXPECT_CALL(r1.inner_encoder_, encodeHeaders(_, true)); EXPECT_TRUE( r1.callbacks_.outer_encoder_ @@ -974,6 +987,7 @@ TEST_F(Http2ConnPoolImplTest, VerifyBufferLimits) { test_clients_[0].connection_->raiseEvent(Network::ConnectionEvent::RemoteClose); EXPECT_CALL(*this, onClientDestroy()); dispatcher_.clearDeferredDeleteList(); + CHECK_STATE(0 /*active*/, 0 /*pending*/, 0 /*capacity*/); EXPECT_EQ(1U, cluster_->stats_.upstream_cx_destroy_.value()); EXPECT_EQ(1U, cluster_->stats_.upstream_cx_destroy_remote_.value()); @@ -1391,16 +1405,19 @@ TEST_F(Http2ConnPoolImplTest, PrefetchWithoutMultiplexing) { // kick off 2 connections. expectClientsCreate(2); ActiveTestRequest r1(*this, 0, false); + CHECK_STATE(0 /*active*/, 1 /*pending*/, 2 /*capacity*/); // With another incoming request, we'll have 2 in flight and want 1.5*2 so // create one connection. expectClientsCreate(1); ActiveTestRequest r2(*this, 0, false); + CHECK_STATE(0 /*active*/, 2 /*pending*/, 3 /*capacity*/); // With a third request we'll have 3 in flight and want 1.5*3 -> 5 so kick off // two again. expectClientsCreate(2); ActiveTestRequest r3(*this, 0, false); + CHECK_STATE(0 /*active*/, 3 /*pending*/, 5 /*capacity*/); r1.handle_->cancel(Envoy::ConnectionPool::CancelPolicy::CloseExcess); r2.handle_->cancel(Envoy::ConnectionPool::CancelPolicy::CloseExcess); @@ -1436,11 +1453,13 @@ TEST_F(Http2ConnPoolImplTest, PrefetchWithMultiplexing) { // only kick off 1 connection. expectClientsCreate(1); ActiveTestRequest r1(*this, 0, false); + CHECK_STATE(0 /*active*/, 1 /*pending*/, 2 /*capacity*/); // With another incoming request, we'll have capacity(2) in flight and want 1.5*2 so // create an additional connection. expectClientsCreate(1); ActiveTestRequest r2(*this, 0, false); + CHECK_STATE(0 /*active*/, 2 /*pending*/, 4 /*capacity*/); // Clean up. r1.handle_->cancel(Envoy::ConnectionPool::CancelPolicy::CloseExcess); @@ -1534,6 +1553,44 @@ TEST_F(Http2ConnPoolImplTest, MaybePrefetch) { closeAllClients(); } +TEST_F(Http2ConnPoolImplTest, TestStateWithMultiplexing) { + cluster_->http2_options_.mutable_max_concurrent_streams()->set_value(2); + cluster_->max_requests_per_connection_ = 4; + + expectClientsCreate(1); + ActiveTestRequest r1(*this, 0, false); + // Initially, capacity is based on concurrency and capped at 2. + CHECK_STATE(0 /*active*/, 1 /*pending*/, 2 /*capacity*/); + expectClientConnect(0, r1); + // Now the stream is active, remaining concurrency capacity is 1 + CHECK_STATE(1 /*active*/, 0 /*pending*/, 1 /*capacity*/); + + // With one more stream, remaining concurrency capacity is 0. + ActiveTestRequest r2(*this, 0, true); + CHECK_STATE(2 /*active*/, 0 /*pending*/, 0 /*capacity*/); + + // If one stream closes, concurrency capacity goes to 1 (2 remaining streams) + completeRequest(r1); + CHECK_STATE(1 /*active*/, 0 /*pending*/, 1 /*capacity*/); + + // Assigning a new stream, concurrency capacity returns to 0 (1 remaining stream); + ActiveTestRequest r3(*this, 0, true); + CHECK_STATE(2 /*active*/, 0 /*pending*/, 0 /*capacity*/); + + // Closing a stream, capacity returns to 1 (both concurrency and remaining streams) + completeRequest(r2); + CHECK_STATE(1 /*active*/, 0 /*pending*/, 1 /*capacity*/); + + // Closing another, capacity remains at 1, as there is only 1 remaining stream. + completeRequest(r3); + CHECK_STATE(0 /*active*/, 0 /*pending*/, 1 /*capacity*/); + + // Clean up with an outstanding stream. + pool_->drainConnections(); + closeAllClients(); + CHECK_STATE(0 /*active*/, 0 /*pending*/, 0 /*capacity*/); +} + } // namespace Http2 } // namespace Http } // namespace Envoy diff --git a/test/common/http/http2/http2_frame.cc b/test/common/http/http2/http2_frame.cc index 34decb609a460..6717ec49b3b85 100644 --- a/test/common/http/http2/http2_frame.cc +++ b/test/common/http/http2/http2_frame.cc @@ -13,19 +13,6 @@ namespace { // Converts stream ID to the network byte order. Supports all values in the range [0, 2^30). uint32_t makeNetworkOrderStreamId(uint32_t stream_id) { return htonl(stream_id); } -// All this templatized stuff is for the typesafe constexpr bitwise ORing of the "enum class" values -template struct FirstArgType { - using type = First; // NOLINT(readability-identifier-naming) -}; - -template constexpr uint8_t orFlags(Flag flag) { return static_cast(flag); } - -template constexpr uint8_t orFlags(Flag first, Flags... rest) { - static_assert(std::is_same::type>::value, - "All flag types must be the same!"); - return static_cast(first) | orFlags(rest...); -} - } // namespace namespace Envoy { @@ -160,13 +147,11 @@ Http2Frame Http2Frame::makeHeadersFrameNoStatus(uint32_t stream_index) { return frame; } -Http2Frame Http2Frame::makeHeadersFrameWithStatus(std::string status, uint32_t stream_index) { +Http2Frame Http2Frame::makeHeadersFrameWithStatus(std::string status, uint32_t stream_index, + HeadersFlags flags) { Http2Frame frame; - frame.buildHeader( - Type::Headers, 0, - orFlags(HeadersFlags::EndStream, - HeadersFlags::EndHeaders), // TODO: Support not hardcoding these two flags - makeNetworkOrderStreamId(stream_index)); + frame.buildHeader(Type::Headers, 0, static_cast(flags), + makeNetworkOrderStreamId(stream_index)); if (status == "200") { frame.appendStaticHeader(StaticHeaderIndex::Status200); } else if (status == "204") { @@ -323,6 +308,16 @@ Http2Frame Http2Frame::makeMalformedRequestWithZerolenHeader(uint32_t stream_ind return frame; } +Http2Frame Http2Frame::makeMalformedResponseWithZerolenHeader(uint32_t stream_index) { + Http2Frame frame; + frame.buildHeader(Type::Headers, 0, orFlags(HeadersFlags::EndStream, HeadersFlags::EndHeaders), + makeNetworkOrderStreamId(stream_index)); + frame.appendStaticHeader(StaticHeaderIndex::Status200); + frame.appendEmptyHeader(); + frame.adjustPayloadSize(); + return frame; +} + Http2Frame Http2Frame::makeRequest(uint32_t stream_index, absl::string_view host, absl::string_view path) { Http2Frame frame; diff --git a/test/common/http/http2/http2_frame.h b/test/common/http/http2/http2_frame.h index b2592891cceed..53465a6f9248a 100644 --- a/test/common/http/http2/http2_frame.h +++ b/test/common/http/http2/http2_frame.h @@ -14,6 +14,19 @@ namespace Envoy { namespace Http { namespace Http2 { +template constexpr uint8_t orFlags(Flag flag) { return static_cast(flag); } + +// All this templatized stuff is for the typesafe constexpr bitwise ORing of the "enum class" values +template struct FirstArgType { + using type = First; // NOLINT(readability-identifier-naming) +}; + +template constexpr uint8_t orFlags(Flag first, Flags... rest) { + static_assert(std::is_same::type>::value, + "All flag types must be the same!"); + return static_cast(first) | orFlags(rest...); +} + // Rudimentary facility for building and parsing of HTTP2 frames for unit tests class Http2Frame { using DataContainer = std::vector; @@ -120,8 +133,9 @@ class Http2Frame { HeadersFlags flags = HeadersFlags::None); static Http2Frame makeHeadersFrameNoStatus(uint32_t stream_index); static Http2Frame makeHeadersFrameWithStatus( - std::string status, - uint32_t stream_index); // Want to test overridden int here, so make it string + std::string status, uint32_t stream_index, + HeadersFlags flags = static_cast(orFlags(HeadersFlags::EndStream, + HeadersFlags::EndHeaders))); // TODO: MakeHeadersFrameWithStatusAndNonStaticHeaders static Http2Frame makeEmptyContinuationFrame(uint32_t stream_index, HeadersFlags flags = HeadersFlags::None); @@ -142,6 +156,7 @@ class Http2Frame { static Http2Frame makeMalformedRequestWithZerolenHeader(uint32_t stream_index, absl::string_view host, absl::string_view path); + static Http2Frame makeMalformedResponseWithZerolenHeader(uint32_t stream_index); static Http2Frame makeRequest(uint32_t stream_index, absl::string_view host, absl::string_view path); static Http2Frame makeRequest(uint32_t stream_index, absl::string_view host, diff --git a/test/common/http/mixed_conn_pool_test.cc b/test/common/http/mixed_conn_pool_test.cc index f48b37afdcf71..578070cf9bec7 100644 --- a/test/common/http/mixed_conn_pool_test.cc +++ b/test/common/http/mixed_conn_pool_test.cc @@ -21,11 +21,11 @@ namespace { // TODO(alyssawilk) replace this with the MixedConnectionPool once it lands. class ConnPoolImplForTest : public HttpConnPoolImplBase { public: - ConnPoolImplForTest(Event::MockDispatcher& dispatcher, Random::RandomGenerator& random, - Upstream::ClusterInfoConstSharedPtr cluster) + ConnPoolImplForTest(Event::MockDispatcher& dispatcher, Upstream::ClusterConnectivityState& state, + Random::RandomGenerator& random, Upstream::ClusterInfoConstSharedPtr cluster) : HttpConnPoolImplBase(Upstream::makeTestHost(cluster, "tcp://127.0.0.1:9000"), Upstream::ResourcePriority::Default, dispatcher, nullptr, nullptr, - random, {Http::Protocol::Http2, Http::Protocol::Http11}) {} + random, state, {Http::Protocol::Http2, Http::Protocol::Http11}) {} Envoy::ConnectionPool::ActiveClientPtr instantiateActiveClient() override { return nullptr; } Http::Protocol protocol() const override { return Http::Protocol::Http2; } @@ -40,12 +40,13 @@ class ConnPoolImplForTest : public HttpConnPoolImplBase { class MixedConnPoolImplTest : public testing::Test { public: MixedConnPoolImplTest() - : conn_pool_(std::make_unique(dispatcher_, random_, cluster_)) {} + : conn_pool_(std::make_unique(dispatcher_, state_, random_, cluster_)) {} ~MixedConnPoolImplTest() override { EXPECT_EQ("", TestUtility::nonZeroedGauges(cluster_->stats_store_.gauges())); } + Upstream::ClusterConnectivityState state_; NiceMock dispatcher_; std::shared_ptr cluster_{new NiceMock()}; std::unique_ptr conn_pool_; diff --git a/test/common/network/connection_impl_test.cc b/test/common/network/connection_impl_test.cc index aab097ee10b81..deadc876a03cc 100644 --- a/test/common/network/connection_impl_test.cc +++ b/test/common/network/connection_impl_test.cc @@ -1098,6 +1098,12 @@ TEST_P(ConnectionImplTest, WriteWithWatermarks) { Invoke(client_write_buffer_, &MockWatermarkBuffer::baseMove))); NiceMock os_sys_calls; TestThreadsafeSingletonInjector os_calls(&os_sys_calls); + + EXPECT_CALL(os_sys_calls, readv(_, _, _)) + .WillRepeatedly(Invoke([&](os_fd_t, const iovec*, int) -> Api::SysCallSizeResult { + return {-1, SOCKET_ERROR_AGAIN}; + })); + EXPECT_CALL(os_sys_calls, writev(_, _, _)) .WillOnce(Invoke([&](os_fd_t, const iovec*, int) -> Api::SysCallSizeResult { dispatcher_->exit(); @@ -1188,6 +1194,7 @@ TEST_P(ConnectionImplTest, WatermarkFuzzing) { EXPECT_CALL(os_sys_calls, writev(_, _, _)) .WillOnce(Invoke([&](os_fd_t, const iovec*, int) -> Api::SysCallSizeResult { client_write_buffer_->drain(bytes_to_flush); + dispatcher_->exit(); return {-1, SOCKET_ERROR_AGAIN}; })) .WillRepeatedly(Invoke([&](os_fd_t, const iovec*, int) -> Api::SysCallSizeResult { @@ -1195,7 +1202,7 @@ TEST_P(ConnectionImplTest, WatermarkFuzzing) { })); client_connection_->write(buffer_to_write, false); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + dispatcher_->run(Event::Dispatcher::RunType::Block); } EXPECT_CALL(client_callbacks_, onBelowWriteBufferLowWatermark()).Times(AnyNumber()); @@ -1832,7 +1839,7 @@ class MockTransportConnectionImplTest : public testing::Test { return new Buffer::WatermarkBuffer(below_low, above_high, above_overflow); })); - file_event_ = new Event::MockFileEvent; + file_event_ = new NiceMock; EXPECT_CALL(dispatcher_, createFileEvent_(0, _, _, _)) .WillOnce(DoAll(SaveArg<1>(&file_ready_cb_), Return(file_event_))); transport_socket_ = new NiceMock; diff --git a/test/common/network/udp_listener_impl_test.cc b/test/common/network/udp_listener_impl_test.cc index 1ee20f8e93a94..b6e4bd6705102 100644 --- a/test/common/network/udp_listener_impl_test.cc +++ b/test/common/network/udp_listener_impl_test.cc @@ -40,17 +40,21 @@ namespace { // packets are sent from a network namespace different to that of // the client. Currently, the testing framework does not support // this behavior. -// This helper allows to intercept the supportsUdpGro syscall and -// toggle the gro behavior as per individual test requirements. -class MockSupportsUdpGro : public Api::OsSysCallsImpl { +// This helper allows to intercept syscalls and +// toggle the behavior as per individual test requirements. +class OverrideOsSysCallsImpl : public Api::OsSysCallsImpl { public: MOCK_METHOD(bool, supportsUdpGro, (), (const)); + MOCK_METHOD(bool, supportsMmsg, (), (const)); }; class UdpListenerImplTest : public UdpListenerImplTestBase { public: void SetUp() override { - ON_CALL(udp_gro_syscall_, supportsUdpGro()).WillByDefault(Return(false)); + ON_CALL(override_syscall_, supportsUdpGro()).WillByDefault(Return(false)); + // Return the real version by default. + ON_CALL(override_syscall_, supportsMmsg()) + .WillByDefault(Return(os_calls.latched().supportsMmsg())); // Set listening socket options. server_socket_->addOptions(SocketOptionFactory::buildIpPacketInfoOptions()); @@ -64,8 +68,8 @@ class UdpListenerImplTest : public UdpListenerImplTestBase { ON_CALL(listener_callbacks_, udpPacketWriter()).WillByDefault(ReturnRef(*udp_packet_writer_)); } - NiceMock udp_gro_syscall_; - TestThreadsafeSingletonInjector os_calls{&udp_gro_syscall_}; + NiceMock override_syscall_; + TestThreadsafeSingletonInjector os_calls{&override_syscall_}; }; INSTANTIATE_TEST_SUITE_P(IpVersions, UdpListenerImplTest, @@ -126,6 +130,54 @@ TEST_P(UdpListenerImplTest, UseActualDstUdp) { dispatcher_->run(Event::Dispatcher::RunType::Block); } +// Test a large datagram that gets dropped using recvmmsg if supported. +TEST_P(UdpListenerImplTest, LargeDatagramRecvmmsg) { + // This will get dropped. + const std::string first(4096, 'a'); + client_.write(first, *send_to_addr_); + const std::string second("second"); + client_.write(second, *send_to_addr_); + // This will get dropped. + const std::string third(4096, 'b'); + client_.write(third, *send_to_addr_); + + EXPECT_CALL(listener_callbacks_, onReadReady()); + EXPECT_CALL(listener_callbacks_, onData(_)).WillOnce(Invoke([&](const UdpRecvData& data) -> void { + validateRecvCallbackParams(data, Api::OsSysCallsSingleton::get().supportsMmsg() ? 16u : 1u); + EXPECT_EQ(data.buffer_->toString(), second); + + dispatcher_->exit(); + })); + + dispatcher_->run(Event::Dispatcher::RunType::Block); + EXPECT_EQ(2, listener_->packetsDropped()); +} + +// Test a large datagram that gets dropped using recvmsg. +TEST_P(UdpListenerImplTest, LargeDatagramRecvmsg) { + ON_CALL(override_syscall_, supportsMmsg()).WillByDefault(Return(false)); + + // This will get dropped. + const std::string first(4096, 'a'); + client_.write(first, *send_to_addr_); + const std::string second("second"); + client_.write(second, *send_to_addr_); + // This will get dropped. + const std::string third(4096, 'b'); + client_.write(third, *send_to_addr_); + + EXPECT_CALL(listener_callbacks_, onReadReady()); + EXPECT_CALL(listener_callbacks_, onData(_)).WillOnce(Invoke([&](const UdpRecvData& data) -> void { + validateRecvCallbackParams(data, Api::OsSysCallsSingleton::get().supportsMmsg() ? 16u : 1u); + EXPECT_EQ(data.buffer_->toString(), second); + + dispatcher_->exit(); + })); + + dispatcher_->run(Event::Dispatcher::RunType::Block); + EXPECT_EQ(2, listener_->packetsDropped()); +} + /** * Tests UDP listener for read and write callbacks with actual data. */ diff --git a/test/common/secret/BUILD b/test/common/secret/BUILD index 48572641a39b2..6161773b7b8c2 100644 --- a/test/common/secret/BUILD +++ b/test/common/secret/BUILD @@ -43,12 +43,15 @@ envoy_cc_test( "//source/common/secret:sds_api_lib", "//source/common/ssl:certificate_validation_context_config_impl_lib", "//source/common/ssl:tls_certificate_config_impl_lib", + "//test/common/stats:stat_test_utility_lib", + "//test/mocks/config:config_mocks", + "//test/mocks/filesystem:filesystem_mocks", "//test/mocks/grpc:grpc_mocks", "//test/mocks/init:init_mocks", "//test/mocks/protobuf:protobuf_mocks", "//test/mocks/secret:secret_mocks", - "//test/mocks/server:instance_mocks", "//test/test_common:environment_lib", + "//test/test_common:logging_lib", "//test/test_common:registry_lib", "//test/test_common:utility_lib", "@envoy_api//envoy/config/core/v3:pkg_cc_proto", diff --git a/test/common/secret/sds_api_test.cc b/test/common/secret/sds_api_test.cc index 8d5cdb00294af..12386bbf535e6 100644 --- a/test/common/secret/sds_api_test.cc +++ b/test/common/secret/sds_api_test.cc @@ -12,29 +12,38 @@ #include "common/ssl/certificate_validation_context_config_impl.h" #include "common/ssl/tls_certificate_config_impl.h" +#include "test/common/stats/stat_test_utility.h" +#include "test/mocks/config/mocks.h" +#include "test/mocks/filesystem/mocks.h" #include "test/mocks/grpc/mocks.h" #include "test/mocks/init/mocks.h" #include "test/mocks/protobuf/mocks.h" #include "test/mocks/secret/mocks.h" -#include "test/mocks/server/instance.h" #include "test/test_common/environment.h" +#include "test/test_common/logging.h" #include "test/test_common/utility.h" #include "gmock/gmock.h" #include "gtest/gtest.h" using ::testing::_; +using ::testing::InSequence; using ::testing::Invoke; using ::testing::InvokeWithoutArgs; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::Throw; namespace Envoy { namespace Secret { namespace { -class SdsApiTest : public testing::Test { +class SdsApiTestBase { protected: - SdsApiTest() - : api_(Api::createApiForTest()), dispatcher_(api_->allocateDispatcher("test_thread")) {} + SdsApiTestBase() { + api_ = Api::createApiForTest(); + dispatcher_ = api_->allocateDispatcher("test_thread"); + } void initialize() { init_target_handle_->initialize(init_watcher_); } void setupMocks() { @@ -51,19 +60,21 @@ class SdsApiTest : public testing::Test { Event::GlobalTimeSystem time_system_; Init::TargetHandlePtr init_target_handle_; Event::DispatcherPtr dispatcher_; + Stats::TestUtil::TestStore stats_; }; +class SdsApiTest : public testing::Test, public SdsApiTestBase {}; + // Validate that SdsApi object is created and initialized successfully. TEST_F(SdsApiTest, BasicTest) { ::testing::InSequence s; const envoy::service::secret::v3::SdsDummy dummy; - NiceMock server; envoy::config::core::v3::ConfigSource config_source; setupMocks(); TlsCertificateSdsApi sds_api( - config_source, "abc.com", subscription_factory_, time_system_, validation_visitor_, - server.stats(), []() {}, *dispatcher_, *api_); + config_source, "abc.com", subscription_factory_, time_system_, validation_visitor_, stats_, + []() {}, *dispatcher_, *api_); sds_api.registerInitTarget(init_manager_); initialize(); } @@ -72,7 +83,6 @@ TEST_F(SdsApiTest, BasicTest) { // has been already initialized. This is a regression test for // https://github.com/envoyproxy/envoy/issues/12013 TEST_F(SdsApiTest, InitManagerInitialised) { - NiceMock server; std::string sds_config = R"EOF( resources: @@ -90,7 +100,7 @@ TEST_F(SdsApiTest, InitManagerInitialised) { NiceMock callbacks; TestUtility::TestOpaqueResourceDecoderImpl resource_decoder("name"); - Config::SubscriptionStats stats(Config::Utility::generateStats(server.stats())); + Config::SubscriptionStats stats(Config::Utility::generateStats(stats_)); NiceMock validation_visitor; envoy::config::core::v3::ConfigSource config_source; @@ -113,8 +123,8 @@ TEST_F(SdsApiTest, InitManagerInitialised) { EXPECT_EQ(Init::Manager::State::Initializing, init_manager.state()); TlsCertificateSdsApi sds_api( - config_source, "abc.com", subscription_factory_, time_system_, validation_visitor_, - server.stats(), []() {}, *dispatcher_, *api_); + config_source, "abc.com", subscription_factory_, time_system_, validation_visitor_, stats_, + []() {}, *dispatcher_, *api_); EXPECT_NO_THROW(sds_api.registerInitTarget(init_manager)); } @@ -122,7 +132,6 @@ TEST_F(SdsApiTest, InitManagerInitialised) { // https://github.com/envoyproxy/envoy/issues/10976. TEST_F(SdsApiTest, BadConfigSource) { ::testing::InSequence s; - NiceMock server; envoy::config::core::v3::ConfigSource config_source; EXPECT_CALL(subscription_factory_, subscriptionFromConfigSource(_, _, _, _, _)) .WillOnce(InvokeWithoutArgs([]() -> Config::SubscriptionPtr { @@ -131,19 +140,18 @@ TEST_F(SdsApiTest, BadConfigSource) { })); EXPECT_THROW_WITH_MESSAGE(TlsCertificateSdsApi( config_source, "abc.com", subscription_factory_, time_system_, - validation_visitor_, server.stats(), []() {}, *dispatcher_, *api_), + validation_visitor_, stats_, []() {}, *dispatcher_, *api_), EnvoyException, "bad config"); } // Validate that TlsCertificateSdsApi updates secrets successfully if a good secret // is passed to onConfigUpdate(). TEST_F(SdsApiTest, DynamicTlsCertificateUpdateSuccess) { - NiceMock server; envoy::config::core::v3::ConfigSource config_source; setupMocks(); TlsCertificateSdsApi sds_api( - config_source, "abc.com", subscription_factory_, time_system_, validation_visitor_, - server.stats(), []() {}, *dispatcher_, *api_); + config_source, "abc.com", subscription_factory_, time_system_, validation_visitor_, stats_, + []() {}, *dispatcher_, *api_); sds_api.registerInitTarget(init_manager_); initialize(); NiceMock secret_callback; @@ -180,15 +188,317 @@ TEST_F(SdsApiTest, DynamicTlsCertificateUpdateSuccess) { handle->remove(); } +class SdsRotationApiTest : public SdsApiTestBase { +protected: + SdsRotationApiTest() { + api_ = Api::createApiForTest(filesystem_); + setupMocks(); + EXPECT_CALL(filesystem_, splitPathFromFilename(_)) + .WillRepeatedly(Invoke([](absl::string_view path) -> Filesystem::PathSplitResult { + return Filesystem::fileSystemForTest().splitPathFromFilename(path); + })); + } + + Secret::MockSecretCallbacks secret_callback_; + Common::CallbackHandle* handle_{}; + std::vector watch_cbs_; + Event::MockDispatcher mock_dispatcher_; + Filesystem::MockInstance filesystem_; +}; + +class TlsCertificateSdsRotationApiTest : public testing::TestWithParam, + public SdsRotationApiTest { +protected: + TlsCertificateSdsRotationApiTest() + : watched_directory_(GetParam()), cert_path_("/foo/bar/cert.pem"), + key_path_("/foo/bar/key.pem"), expected_watch_path_("/foo/bar/"), trigger_path_("/foo") { + envoy::config::core::v3::ConfigSource config_source; + sds_api_ = std::make_unique( + config_source, "abc.com", subscription_factory_, time_system_, validation_visitor_, stats_, + []() {}, mock_dispatcher_, *api_); + sds_api_->registerInitTarget(init_manager_); + initialize(); + handle_ = sds_api_->addUpdateCallback([this]() { secret_callback_.onAddOrUpdateSecret(); }); + } + + ~TlsCertificateSdsRotationApiTest() override { handle_->remove(); } + + void onConfigUpdate(const std::string& cert_value, const std::string& key_value) { + const std::string yaml = fmt::format( + R"EOF( + name: "abc.com" + tls_certificate: + certificate_chain: + filename: "{}" + private_key: + filename: "{}" + )EOF", + cert_path_, key_path_); + envoy::extensions::transport_sockets::tls::v3::Secret typed_secret; + TestUtility::loadFromYaml(yaml, typed_secret); + if (watched_directory_) { + typed_secret.mutable_tls_certificate()->mutable_watched_directory()->set_path(trigger_path_); + } + const auto decoded_resources = TestUtility::decodeResources({typed_secret}); + + auto* watcher = new Filesystem::MockWatcher(); + if (watched_directory_) { + EXPECT_CALL(mock_dispatcher_, createFilesystemWatcher_()).WillOnce(Return(watcher)); + EXPECT_CALL(*watcher, addWatch(trigger_path_ + "/", Filesystem::Watcher::Events::MovedTo, _)) + .WillOnce( + Invoke([this](absl::string_view, uint32_t, Filesystem::Watcher::OnChangedCb cb) { + watch_cbs_.push_back(cb); + })); + EXPECT_CALL(filesystem_, fileReadToEnd(cert_path_)).WillOnce(Return(cert_value)); + EXPECT_CALL(filesystem_, fileReadToEnd(key_path_)).WillOnce(Return(key_value)); + EXPECT_CALL(secret_callback_, onAddOrUpdateSecret()); + } else { + EXPECT_CALL(filesystem_, fileReadToEnd(cert_path_)).WillOnce(Return(cert_value)); + EXPECT_CALL(filesystem_, fileReadToEnd(key_path_)).WillOnce(Return(key_value)); + EXPECT_CALL(secret_callback_, onAddOrUpdateSecret()); + EXPECT_CALL(mock_dispatcher_, createFilesystemWatcher_()).WillOnce(Return(watcher)); + EXPECT_CALL(*watcher, addWatch(expected_watch_path_, Filesystem::Watcher::Events::MovedTo, _)) + .Times(2) + .WillRepeatedly( + Invoke([this](absl::string_view, uint32_t, Filesystem::Watcher::OnChangedCb cb) { + watch_cbs_.push_back(cb); + })); + } + subscription_factory_.callbacks_->onConfigUpdate(decoded_resources.refvec_, ""); + } + + const bool watched_directory_; + std::string cert_path_; + std::string key_path_; + std::string expected_watch_path_; + std::string trigger_path_; + std::unique_ptr sds_api_; +}; + +INSTANTIATE_TEST_SUITE_P(TlsCertificateSdsRotationApiTestParams, TlsCertificateSdsRotationApiTest, + testing::Values(false, true)); + +class CertificateValidationContextSdsRotationApiTest : public testing::TestWithParam, + public SdsRotationApiTest { +protected: + CertificateValidationContextSdsRotationApiTest() { + envoy::config::core::v3::ConfigSource config_source; + sds_api_ = std::make_unique( + config_source, "abc.com", subscription_factory_, time_system_, validation_visitor_, stats_, + []() {}, mock_dispatcher_, *api_); + sds_api_->registerInitTarget(init_manager_); + initialize(); + handle_ = sds_api_->addUpdateCallback([this]() { secret_callback_.onAddOrUpdateSecret(); }); + } + + ~CertificateValidationContextSdsRotationApiTest() override { handle_->remove(); } + + void onConfigUpdate(const std::string& trusted_ca_path, const std::string& trusted_ca_value, + const std::string& watch_path) { + const std::string yaml = fmt::format( + R"EOF( + name: "abc.com" + validation_context: + trusted_ca: + filename: "{}" + allow_expired_certificate: true + )EOF", + trusted_ca_path); + envoy::extensions::transport_sockets::tls::v3::Secret typed_secret; + TestUtility::loadFromYaml(yaml, typed_secret); + const auto decoded_resources = TestUtility::decodeResources({typed_secret}); + + auto* watcher = new Filesystem::MockWatcher(); + EXPECT_CALL(filesystem_, fileReadToEnd(trusted_ca_path)).WillOnce(Return(trusted_ca_value)); + EXPECT_CALL(secret_callback_, onAddOrUpdateSecret()); + EXPECT_CALL(mock_dispatcher_, createFilesystemWatcher_()).WillOnce(Return(watcher)); + EXPECT_CALL(*watcher, addWatch(watch_path, Filesystem::Watcher::Events::MovedTo, _)) + .WillOnce(Invoke([this](absl::string_view, uint32_t, Filesystem::Watcher::OnChangedCb cb) { + watch_cbs_.push_back(cb); + })); + subscription_factory_.callbacks_->onConfigUpdate(decoded_resources.refvec_, ""); + } + + std::unique_ptr sds_api_; +}; + +INSTANTIATE_TEST_SUITE_P(CertificateValidationContextSdsRotationApiTestParams, + CertificateValidationContextSdsRotationApiTest, + testing::Values(false, true)); + +// Initial onConfigUpdate() of TlsCertificate secret. +TEST_P(TlsCertificateSdsRotationApiTest, InitialUpdate) { + InSequence s; + onConfigUpdate("a", "b"); + + const auto& secret = *sds_api_->secret(); + EXPECT_EQ("a", secret.certificate_chain().inline_bytes()); + EXPECT_EQ("b", secret.private_key().inline_bytes()); +} + +// Two distinct updates with onConfigUpdate() of TlsCertificate secret. +TEST_P(TlsCertificateSdsRotationApiTest, MultiUpdate) { + InSequence s; + onConfigUpdate("a", "b"); + { + const auto& secret = *sds_api_->secret(); + EXPECT_EQ("a", secret.certificate_chain().inline_bytes()); + EXPECT_EQ("b", secret.private_key().inline_bytes()); + } + + cert_path_ = "/new/foo/bar/cert.pem"; + key_path_ = "/new/foo/bar/key.pem"; + expected_watch_path_ = "/new/foo/bar/"; + onConfigUpdate("c", "d"); + { + const auto& secret = *sds_api_->secret(); + EXPECT_EQ("c", secret.certificate_chain().inline_bytes()); + EXPECT_EQ("d", secret.private_key().inline_bytes()); + } +} + +// Watch trigger without file change has no effect. +TEST_P(TlsCertificateSdsRotationApiTest, NopWatchTrigger) { + InSequence s; + onConfigUpdate("a", "b"); + + for (const auto& cb : watch_cbs_) { + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/cert.pem")).WillOnce(Return("a")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/key.pem")).WillOnce(Return("b")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/cert.pem")).WillOnce(Return("a")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/key.pem")).WillOnce(Return("b")); + cb(Filesystem::Watcher::Events::MovedTo); + } + + const auto& secret = *sds_api_->secret(); + EXPECT_EQ("a", secret.certificate_chain().inline_bytes()); + EXPECT_EQ("b", secret.private_key().inline_bytes()); +} + +// Basic rotation of TlsCertificate. +TEST_P(TlsCertificateSdsRotationApiTest, RotationWatchTrigger) { + InSequence s; + onConfigUpdate("a", "b"); + + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/cert.pem")).WillOnce(Return("c")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/key.pem")).WillOnce(Return("d")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/cert.pem")).WillOnce(Return("c")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/key.pem")).WillOnce(Return("d")); + EXPECT_CALL(secret_callback_, onAddOrUpdateSecret()); + watch_cbs_[0](Filesystem::Watcher::Events::MovedTo); + if (!watched_directory_) { + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/cert.pem")).WillOnce(Return("c")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/key.pem")).WillOnce(Return("d")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/cert.pem")).WillOnce(Return("c")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/key.pem")).WillOnce(Return("d")); + watch_cbs_[1](Filesystem::Watcher::Events::MovedTo); + } + + const auto& secret = *sds_api_->secret(); + EXPECT_EQ("c", secret.certificate_chain().inline_bytes()); + EXPECT_EQ("d", secret.private_key().inline_bytes()); +} + +// Failed rotation of TlsCertificate. +TEST_P(TlsCertificateSdsRotationApiTest, FailedRotation) { + InSequence s; + onConfigUpdate("a", "b"); + + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/cert.pem")) + .WillOnce(Throw(EnvoyException("fail"))); + EXPECT_LOG_CONTAINS("warn", "Failed to reload certificates: ", + watch_cbs_[0](Filesystem::Watcher::Events::MovedTo)); + EXPECT_EQ(1U, stats_.counter("sds.abc.com.key_rotation_failed").value()); + + const auto& secret = *sds_api_->secret(); + EXPECT_EQ("a", secret.certificate_chain().inline_bytes()); + EXPECT_EQ("b", secret.private_key().inline_bytes()); +} + +// Basic rotation of CertificateValidationContext. +TEST_P(CertificateValidationContextSdsRotationApiTest, CertificateValidationContext) { + InSequence s; + onConfigUpdate("/foo/bar/ca.pem", "a", "/foo/bar/"); + + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/ca.pem")).WillOnce(Return("c")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/ca.pem")).WillOnce(Return("c")); + EXPECT_CALL(secret_callback_, onAddOrUpdateSecret()); + watch_cbs_[0](Filesystem::Watcher::Events::MovedTo); + + const auto& secret = *sds_api_->secret(); + EXPECT_EQ("c", secret.trusted_ca().inline_bytes()); +} + +// Hash consistency verification prevents races. +TEST_P(TlsCertificateSdsRotationApiTest, RotationConsistency) { + InSequence s; + onConfigUpdate("a", "b"); + + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/cert.pem")).WillOnce(Return("a")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/key.pem")).WillOnce(Return("d")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/cert.pem")).WillOnce(Return("c")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/key.pem")).WillOnce(Return("d")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/cert.pem")).WillOnce(Return("c")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/key.pem")).WillOnce(Return("d")); + EXPECT_CALL(secret_callback_, onAddOrUpdateSecret()); + watch_cbs_[0](Filesystem::Watcher::Events::MovedTo); + if (!watched_directory_) { + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/cert.pem")).WillOnce(Return("c")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/key.pem")).WillOnce(Return("d")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/cert.pem")).WillOnce(Return("c")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/key.pem")).WillOnce(Return("d")); + watch_cbs_[1](Filesystem::Watcher::Events::MovedTo); + } + + const auto& secret = *sds_api_->secret(); + EXPECT_EQ("c", secret.certificate_chain().inline_bytes()); + EXPECT_EQ("d", secret.private_key().inline_bytes()); +} + +// Hash consistency verification failure, no callback. +TEST_P(TlsCertificateSdsRotationApiTest, RotationConsistencyExhaustion) { + InSequence s; + onConfigUpdate("a", "b"); + + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/cert.pem")).WillOnce(Return("a")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/key.pem")).WillOnce(Return("d")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/cert.pem")).WillOnce(Return("c")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/key.pem")).WillOnce(Return("d")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/cert.pem")).WillOnce(Return("d")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/key.pem")).WillOnce(Return("d")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/cert.pem")).WillOnce(Return("e")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/key.pem")).WillOnce(Return("d")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/cert.pem")).WillOnce(Return("f")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/key.pem")).WillOnce(Return("d")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/cert.pem")).WillOnce(Return("f")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/key.pem")).WillOnce(Return("g")); + // We've exhausted the bounded retries, but continue with the non-atomic rotation. + EXPECT_CALL(secret_callback_, onAddOrUpdateSecret()); + EXPECT_LOG_CONTAINS( + "warn", "Unable to atomically refresh secrets due to > 5 non-atomic rotations observed", + watch_cbs_[0](Filesystem::Watcher::Events::MovedTo)); + if (!watched_directory_) { + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/cert.pem")).WillOnce(Return("f")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/key.pem")).WillOnce(Return("g")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/cert.pem")).WillOnce(Return("f")); + EXPECT_CALL(filesystem_, fileReadToEnd("/foo/bar/key.pem")).WillOnce(Return("g")); + watch_cbs_[1](Filesystem::Watcher::Events::MovedTo); + } + + const auto& secret = *sds_api_->secret(); + EXPECT_EQ("f", secret.certificate_chain().inline_bytes()); + EXPECT_EQ("g", secret.private_key().inline_bytes()); +} + class PartialMockSds : public SdsApi { public: - PartialMockSds(NiceMock& server, NiceMock& init_manager, + PartialMockSds(Stats::Store& stats, NiceMock& init_manager, envoy::config::core::v3::ConfigSource& config_source, Config::SubscriptionFactory& subscription_factory, TimeSource& time_source, Event::Dispatcher& dispatcher, Api::Api& api) : SdsApi( - config_source, "abc.com", subscription_factory, time_source, validation_visitor_, - server.stats(), []() {}, dispatcher, api) { + config_source, "abc.com", subscription_factory, time_source, validation_visitor_, stats, + []() {}, dispatcher, api) { registerInitTarget(init_manager); } @@ -202,6 +512,7 @@ class PartialMockSds : public SdsApi { void setSecret(const envoy::extensions::transport_sockets::tls::v3::Secret&) override {} void validateConfig(const envoy::extensions::transport_sockets::tls::v3::Secret&) override {} std::vector getDataSourceFilenames() override { return {}; } + Config::WatchedDirectory* getWatchedDirectory() override { return nullptr; } NiceMock validation_visitor_; }; @@ -214,11 +525,10 @@ TEST_F(SdsApiTest, Delta) { Config::DecodedResourceImpl resource(std::move(secret), "name", {}, "version1"); std::vector resources{resource}; - NiceMock server; envoy::config::core::v3::ConfigSource config_source; Event::GlobalTimeSystem time_system; setupMocks(); - PartialMockSds sds(server, init_manager_, config_source, subscription_factory_, time_system, + PartialMockSds sds(stats_, init_manager_, config_source, subscription_factory_, time_system, *dispatcher_, *api_); initialize(); EXPECT_CALL(sds, onConfigUpdate(DecodedResourcesEq(resources), "version1")); @@ -238,12 +548,11 @@ TEST_F(SdsApiTest, Delta) { // Tests SDS's use of the delta variant of onConfigUpdate(). TEST_F(SdsApiTest, DeltaUpdateSuccess) { - NiceMock server; envoy::config::core::v3::ConfigSource config_source; setupMocks(); TlsCertificateSdsApi sds_api( - config_source, "abc.com", subscription_factory_, time_system_, validation_visitor_, - server.stats(), []() {}, *dispatcher_, *api_); + config_source, "abc.com", subscription_factory_, time_system_, validation_visitor_, stats_, + []() {}, *dispatcher_, *api_); sds_api.registerInitTarget(init_manager_); NiceMock secret_callback; @@ -284,12 +593,11 @@ TEST_F(SdsApiTest, DeltaUpdateSuccess) { // Validate that CertificateValidationContextSdsApi updates secrets successfully if // a good secret is passed to onConfigUpdate(). TEST_F(SdsApiTest, DynamicCertificateValidationContextUpdateSuccess) { - NiceMock server; envoy::config::core::v3::ConfigSource config_source; setupMocks(); CertificateValidationContextSdsApi sds_api( - config_source, "abc.com", subscription_factory_, time_system_, validation_visitor_, - server.stats(), []() {}, *dispatcher_, *api_); + config_source, "abc.com", subscription_factory_, time_system_, validation_visitor_, stats_, + []() {}, *dispatcher_, *api_); sds_api.registerInitTarget(init_manager_); NiceMock secret_callback; @@ -339,12 +647,11 @@ class MockCvcValidationCallback : public CvcValidationCallback { // a good secret is passed to onConfigUpdate(), and that merged CertificateValidationContext // provides correct information. TEST_F(SdsApiTest, DefaultCertificateValidationContextTest) { - NiceMock server; envoy::config::core::v3::ConfigSource config_source; setupMocks(); CertificateValidationContextSdsApi sds_api( - config_source, "abc.com", subscription_factory_, time_system_, validation_visitor_, - server.stats(), []() {}, *dispatcher_, *api_); + config_source, "abc.com", subscription_factory_, time_system_, validation_visitor_, stats_, + []() {}, *dispatcher_, *api_); sds_api.registerInitTarget(init_manager_); NiceMock secret_callback; @@ -428,12 +735,11 @@ class MockGenericSecretValidationCallback : public GenericSecretValidationCallba // Validate that GenericSecretSdsApi updates secrets successfully if // a good secret is passed to onConfigUpdate(). TEST_F(SdsApiTest, GenericSecretSdsApiTest) { - NiceMock server; envoy::config::core::v3::ConfigSource config_source; setupMocks(); GenericSecretSdsApi sds_api( config_source, "encryption_key", subscription_factory_, time_system_, validation_visitor_, - server.stats(), []() {}, *dispatcher_, *api_); + stats_, []() {}, *dispatcher_, *api_); sds_api.registerInitTarget(init_manager_); NiceMock secret_callback; @@ -474,12 +780,11 @@ name: "encryption_key" // Validate that SdsApi throws exception if an empty secret is passed to onConfigUpdate(). TEST_F(SdsApiTest, EmptyResource) { - NiceMock server; envoy::config::core::v3::ConfigSource config_source; setupMocks(); TlsCertificateSdsApi sds_api( - config_source, "abc.com", subscription_factory_, time_system_, validation_visitor_, - server.stats(), []() {}, *dispatcher_, *api_); + config_source, "abc.com", subscription_factory_, time_system_, validation_visitor_, stats_, + []() {}, *dispatcher_, *api_); sds_api.registerInitTarget(init_manager_); initialize(); @@ -490,12 +795,11 @@ TEST_F(SdsApiTest, EmptyResource) { // Validate that SdsApi throws exception if multiple secrets are passed to onConfigUpdate(). TEST_F(SdsApiTest, SecretUpdateWrongSize) { - NiceMock server; envoy::config::core::v3::ConfigSource config_source; setupMocks(); TlsCertificateSdsApi sds_api( - config_source, "abc.com", subscription_factory_, time_system_, validation_visitor_, - server.stats(), []() {}, *dispatcher_, *api_); + config_source, "abc.com", subscription_factory_, time_system_, validation_visitor_, stats_, + []() {}, *dispatcher_, *api_); sds_api.registerInitTarget(init_manager_); std::string yaml = @@ -521,12 +825,11 @@ TEST_F(SdsApiTest, SecretUpdateWrongSize) { // Validate that SdsApi throws exception if secret name passed to onConfigUpdate() // does not match configured name. TEST_F(SdsApiTest, SecretUpdateWrongSecretName) { - NiceMock server; envoy::config::core::v3::ConfigSource config_source; setupMocks(); TlsCertificateSdsApi sds_api( - config_source, "abc.com", subscription_factory_, time_system_, validation_visitor_, - server.stats(), []() {}, *dispatcher_, *api_); + config_source, "abc.com", subscription_factory_, time_system_, validation_visitor_, stats_, + []() {}, *dispatcher_, *api_); sds_api.registerInitTarget(init_manager_); std::string yaml = diff --git a/test/common/signal/BUILD b/test/common/signal/BUILD index c3f9cf5df8434..00b5d183480fc 100644 --- a/test/common/signal/BUILD +++ b/test/common/signal/BUILD @@ -23,3 +23,13 @@ envoy_cc_test( "//test/test_common:utility_lib", ], ) + +envoy_cc_test( + name = "fatal_action_test", + srcs = ["fatal_action_test.cc"], + deps = [ + "//source/common/signal:fatal_error_handler_lib", + "//test/mocks/server:instance_mocks", + "//test/test_common:utility_lib", + ], +) diff --git a/test/common/signal/fatal_action_test.cc b/test/common/signal/fatal_action_test.cc new file mode 100644 index 0000000000000..5105e8f49ffd6 --- /dev/null +++ b/test/common/signal/fatal_action_test.cc @@ -0,0 +1,126 @@ +#include "envoy/server/fatal_action_config.h" + +#include "common/signal/fatal_action.h" +#include "common/signal/fatal_error_handler.h" + +#include "test/mocks/server/instance.h" +#include "test/test_common/utility.h" + +#include "absl/synchronization/notification.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace FatalErrorHandler { + +extern void resetFatalActionStateForTest(); + +} // namespace FatalErrorHandler +namespace FatalAction { + +// Use this test handler instead of a mock, because fatal error handlers must be +// signal-safe and a mock might allocate memory. +class TestFatalErrorHandler : public FatalErrorHandlerInterface { + void onFatalError(std::ostream& /*os*/) const override {} + void + runFatalActionsOnTrackedObject(const FatalAction::FatalActionPtrList& actions) const override { + // Call the Fatal Actions with nullptr + for (const Server::Configuration::FatalActionPtr& action : actions) { + action->run(nullptr); + } + } +}; + +class TestFatalAction : public Server::Configuration::FatalAction { +public: + TestFatalAction(bool is_safe, int* const counter) : is_safe_(is_safe), counter_(counter) {} + void run(const ScopeTrackedObject* /*current_object*/) override { ++(*counter_); } + bool isAsyncSignalSafe() const override { return is_safe_; } + +private: + const bool is_safe_; + int* const counter_; +}; + +class FatalActionTest : public ::testing::Test { +public: + FatalActionTest() : handler_(std::make_unique()) { + FatalErrorHandler::registerFatalErrorHandler(*handler_); + } + +protected: + void TearDown() override { + // Reset module state + FatalErrorHandler::resetFatalActionStateForTest(); + FatalErrorHandler::removeFatalErrorHandler(*handler_); + } + + std::unique_ptr handler_; + FatalAction::FatalActionPtrList safe_actions_; + FatalAction::FatalActionPtrList unsafe_actions_; + int counter_ = 0; +}; + +TEST_F(FatalActionTest, ShouldNotBeAbleToRunActionsBeforeRegistration) { + // Call the actions + EXPECT_EQ(FatalErrorHandler::runSafeActions(), Status::ActionManangerUnset); + EXPECT_EQ(FatalErrorHandler::runUnsafeActions(), Status::ActionManangerUnset); +} + +TEST_F(FatalActionTest, ShouldOnlyBeAbleToRegisterFatalActionsOnce) { + // Register empty list of actions + FatalErrorHandler::registerFatalActions({}, {}, Thread::threadFactoryForTest()); + EXPECT_DEBUG_DEATH( + { FatalErrorHandler::registerFatalActions({}, {}, Thread::threadFactoryForTest()); }, ""); +} + +TEST_F(FatalActionTest, CanCallRegisteredActions) { + // Set up Fatal Actions + safe_actions_.emplace_back(std::make_unique(true, &counter_)); + unsafe_actions_.emplace_back(std::make_unique(false, &counter_)); + FatalErrorHandler::registerFatalActions(std::move(safe_actions_), std::move(unsafe_actions_), + Thread::threadFactoryForTest()); + + // Call the actions and check they increment the counter. + EXPECT_EQ(FatalErrorHandler::runSafeActions(), Status::Success); + EXPECT_EQ(counter_, 1); + + EXPECT_EQ(FatalErrorHandler::runUnsafeActions(), Status::Success); + EXPECT_EQ(counter_, 2); +} + +TEST_F(FatalActionTest, CanOnlyRunSafeActionsOnce) { + FatalErrorHandler::registerFatalActions(std::move(safe_actions_), std::move(unsafe_actions_), + Thread::threadFactoryForTest()); + ASSERT_EQ(FatalErrorHandler::runSafeActions(), Status::Success); + + EXPECT_EQ(FatalErrorHandler::runSafeActions(), Status::AlreadyRanOnThisThread); +} + +TEST_F(FatalActionTest, ShouldOnlyBeAbleToRunUnsafeActionsFromThreadThatRanSafeActions) { + FatalErrorHandler::registerFatalActions(std::move(safe_actions_), std::move(unsafe_actions_), + Thread::threadFactoryForTest()); + + absl::Notification run_unsafe_actions; + absl::Notification ran_safe_actions; + auto fatal_action_thread = + Thread::threadFactoryForTest().createThread([&run_unsafe_actions, &ran_safe_actions]() { + // Run Safe Actions and notify + EXPECT_EQ(FatalErrorHandler::runSafeActions(), Status::Success); + ran_safe_actions.Notify(); + + run_unsafe_actions.WaitForNotification(); + EXPECT_EQ(FatalErrorHandler::runUnsafeActions(), Status::Success); + }); + + // Wait for other thread to run safe actions, then try to run safe and + // unsafe actions, they should both not run for this thread. + ran_safe_actions.WaitForNotification(); + ASSERT_EQ(FatalErrorHandler::runSafeActions(), Status::RunningOnAnotherThread); + ASSERT_EQ(FatalErrorHandler::runUnsafeActions(), Status::RunningOnAnotherThread); + run_unsafe_actions.Notify(); + + fatal_action_thread->join(); +} + +} // namespace FatalAction +} // namespace Envoy diff --git a/test/common/signal/signals_test.cc b/test/common/signal/signals_test.cc index cc66d32d81d0e..3ecf49f6695ba 100644 --- a/test/common/signal/signals_test.cc +++ b/test/common/signal/signals_test.cc @@ -8,8 +8,6 @@ #include "test/common/stats/stat_test_utility.h" #include "test/test_common/utility.h" -#include "gtest/gtest.h" - namespace Envoy { #if defined(__has_feature) #if __has_feature(address_sanitizer) @@ -21,10 +19,41 @@ namespace Envoy { #define ASANITIZED /* Sanitized by GCC */ #endif +namespace FatalErrorHandler { + +extern void resetFatalActionStateForTest(); + +} // namespace FatalErrorHandler + // Use this test handler instead of a mock, because fatal error handlers must be // signal-safe and a mock might allocate memory. class TestFatalErrorHandler : public FatalErrorHandlerInterface { void onFatalError(std::ostream& os) const override { os << "HERE!"; } + void + runFatalActionsOnTrackedObject(const FatalAction::FatalActionPtrList& actions) const override { + // Run the actions + for (const auto& action : actions) { + action->run(nullptr); + } + } +}; + +// Use this to test fatal actions get called, as well as the order they run. +class EchoFatalAction : public Server::Configuration::FatalAction { +public: + EchoFatalAction(absl::string_view echo_msg) : echo_msg_(echo_msg) {} + void run(const ScopeTrackedObject* /*current_object*/) override { std::cerr << echo_msg_; } + bool isAsyncSignalSafe() const override { return true; } + +private: + const std::string echo_msg_; +}; + +// Use this to test failing while in a signal handler. +class SegfaultFatalAction : public Server::Configuration::FatalAction { +public: + void run(const ScopeTrackedObject* /*current_object*/) override { raise(SIGSEGV); } + bool isAsyncSignalSafe() const override { return false; } }; // Death tests that expect a particular output are disabled under address sanitizer. @@ -46,6 +75,7 @@ TEST(SignalsDeathTest, InvalidAddressDeathTest) { TEST(SignalsDeathTest, RegisteredHandlerTest) { TestFatalErrorHandler handler; FatalErrorHandler::registerFatalErrorHandler(handler); + SignalAction actions; // Make sure the fatal error log "HERE" registered above is logged on fatal error. EXPECT_DEATH( @@ -115,6 +145,39 @@ TEST(SignalsDeathTest, RestoredPreviousHandlerDeathTest) { EXPECT_DEATH([]() -> void { abort(); }(), "backtrace.*Abort(ed)?"); } +TEST(SignalsDeathTest, CanRunAllFatalActions) { + SignalAction actions; + TestFatalErrorHandler handler; + FatalErrorHandler::registerFatalErrorHandler(handler); + + FatalAction::FatalActionPtrList safe_actions; + FatalAction::FatalActionPtrList unsafe_actions; + + safe_actions.emplace_back(std::make_unique("Safe Action!")); + unsafe_actions.emplace_back(std::make_unique("Unsafe Action!")); + FatalErrorHandler::registerFatalActions(std::move(safe_actions), std::move(unsafe_actions), + Thread::threadFactoryForTest()); + EXPECT_DEATH([]() -> void { raise(SIGSEGV); }(), "Safe Action!.*HERE.*Unsafe Action!"); + FatalErrorHandler::removeFatalErrorHandler(handler); + FatalErrorHandler::resetFatalActionStateForTest(); +} + +TEST(SignalsDeathTest, ShouldJustExitIfFatalActionsRaiseAnotherSignal) { + SignalAction actions; + TestFatalErrorHandler handler; + FatalErrorHandler::registerFatalErrorHandler(handler); + + FatalAction::FatalActionPtrList safe_actions; + FatalAction::FatalActionPtrList unsafe_actions; + + unsafe_actions.emplace_back(std::make_unique()); + FatalErrorHandler::registerFatalActions(std::move(safe_actions), std::move(unsafe_actions), + Thread::threadFactoryForTest()); + + EXPECT_DEATH([]() -> void { raise(SIGABRT); }(), "Our FatalActions triggered a fatal signal."); + FatalErrorHandler::removeFatalErrorHandler(handler); + FatalErrorHandler::resetFatalActionStateForTest(); +} #endif TEST(SignalsDeathTest, IllegalStackAccessDeathTest) { @@ -179,6 +242,9 @@ class MemoryCheckingFatalErrorHandler : public FatalErrorHandlerInterface { allocated_after_call_ = memory_test_.consumedBytes(); } + void runFatalActionsOnTrackedObject(const FatalAction::FatalActionPtrList& + /*actions*/) const override {} + private: const Stats::TestUtil::MemoryTest& memory_test_; uint64_t& allocated_after_call_; diff --git a/test/common/stats/tag_extractor_impl_test.cc b/test/common/stats/tag_extractor_impl_test.cc index 18ff4d6ec88c8..13fd4de172c93 100644 --- a/test/common/stats/tag_extractor_impl_test.cc +++ b/test/common/stats/tag_extractor_impl_test.cc @@ -15,7 +15,21 @@ namespace Envoy { namespace Stats { TEST(TagExtractorTest, TwoSubexpressions) { - TagExtractorImpl tag_extractor("cluster_name", "^cluster\\.((.+?)\\.)"); + TagExtractorStdRegexImpl tag_extractor("cluster_name", "^cluster\\.((.+?)\\.)"); + EXPECT_EQ("cluster_name", tag_extractor.name()); + std::string name = "cluster.test_cluster.upstream_cx_total"; + TagVector tags; + IntervalSetImpl remove_characters; + ASSERT_TRUE(tag_extractor.extractTag(name, tags, remove_characters)); + std::string tag_extracted_name = StringUtil::removeCharacters(name, remove_characters); + EXPECT_EQ("cluster.upstream_cx_total", tag_extracted_name); + ASSERT_EQ(1, tags.size()); + EXPECT_EQ("test_cluster", tags.at(0).value_); + EXPECT_EQ("cluster_name", tags.at(0).name_); +} + +TEST(TagExtractorTest, RE2Variants) { + TagExtractorRe2Impl tag_extractor("cluster_name", "^cluster\\.(([^\\.]+)\\.).*"); EXPECT_EQ("cluster_name", tag_extractor.name()); std::string name = "cluster.test_cluster.upstream_cx_total"; TagVector tags; @@ -29,7 +43,7 @@ TEST(TagExtractorTest, TwoSubexpressions) { } TEST(TagExtractorTest, SingleSubexpression) { - TagExtractorImpl tag_extractor("listner_port", "^listener\\.(\\d+?\\.)"); + TagExtractorStdRegexImpl tag_extractor("listner_port", "^listener\\.(\\d+?\\.)"); std::string name = "listener.80.downstream_cx_total"; TagVector tags; IntervalSetImpl remove_characters; @@ -42,24 +56,26 @@ TEST(TagExtractorTest, SingleSubexpression) { } TEST(TagExtractorTest, substrMismatch) { - TagExtractorImpl tag_extractor("listner_port", "^listener\\.(\\d+?\\.)\\.foo\\.", ".foo."); + TagExtractorStdRegexImpl tag_extractor("listner_port", "^listener\\.(\\d+?\\.)\\.foo\\.", + ".foo."); EXPECT_TRUE(tag_extractor.substrMismatch("listener.80.downstream_cx_total")); EXPECT_FALSE(tag_extractor.substrMismatch("listener.80.downstream_cx_total.foo.bar")); } TEST(TagExtractorTest, noSubstrMismatch) { - TagExtractorImpl tag_extractor("listner_port", "^listener\\.(\\d+?\\.)\\.foo\\."); + TagExtractorStdRegexImpl tag_extractor("listner_port", "^listener\\.(\\d+?\\.)\\.foo\\."); EXPECT_FALSE(tag_extractor.substrMismatch("listener.80.downstream_cx_total")); EXPECT_FALSE(tag_extractor.substrMismatch("listener.80.downstream_cx_total.foo.bar")); } TEST(TagExtractorTest, EmptyName) { - EXPECT_THROW_WITH_MESSAGE(TagExtractorImpl::createTagExtractor("", "^listener\\.(\\d+?\\.)"), - EnvoyException, "tag_name cannot be empty"); + EXPECT_THROW_WITH_MESSAGE( + TagExtractorStdRegexImpl::createTagExtractor("", "^listener\\.(\\d+?\\.)"), EnvoyException, + "tag_name cannot be empty"); } TEST(TagExtractorTest, BadRegex) { - EXPECT_THROW_WITH_REGEX(TagExtractorImpl::createTagExtractor("cluster_name", "+invalid"), + EXPECT_THROW_WITH_REGEX(TagExtractorStdRegexImpl::createTagExtractor("cluster_name", "+invalid"), EnvoyException, "Invalid regex '\\+invalid':"); } @@ -361,7 +377,7 @@ TEST(TagExtractorTest, DefaultTagExtractors) { TEST(TagExtractorTest, ExtractRegexPrefix) { TagExtractorPtr tag_extractor; // Keep tag_extractor in this scope to prolong prefix lifetime. auto extractRegexPrefix = [&tag_extractor](const std::string& regex) -> absl::string_view { - tag_extractor = TagExtractorImpl::createTagExtractor("foo", regex); + tag_extractor = TagExtractorStdRegexImpl::createTagExtractor("foo", regex); return tag_extractor->prefixToken(); }; @@ -376,7 +392,7 @@ TEST(TagExtractorTest, ExtractRegexPrefix) { } TEST(TagExtractorTest, CreateTagExtractorNoRegex) { - EXPECT_THROW_WITH_REGEX(TagExtractorImpl::createTagExtractor("no such default tag", ""), + EXPECT_THROW_WITH_REGEX(TagExtractorStdRegexImpl::createTagExtractor("no such default tag", ""), EnvoyException, "^No regex specified for tag specifier and no default"); } diff --git a/test/common/stats/thread_local_store_speed_test.cc b/test/common/stats/thread_local_store_speed_test.cc index 3eff52a78d97c..5208fdaed9f5c 100644 --- a/test/common/stats/thread_local_store_speed_test.cc +++ b/test/common/stats/thread_local_store_speed_test.cc @@ -79,6 +79,7 @@ class ThreadLocalStorePerf { // Tests the single-threaded performance of the thread-local-store stats caches // without having initialized tls. +// NOLINTNEXTLINE(readability-identifier-naming) static void BM_StatsNoTls(benchmark::State& state) { Envoy::ThreadLocalStorePerf context; @@ -91,6 +92,7 @@ BENCHMARK(BM_StatsNoTls); // Tests the single-threaded performance of the thread-local-store stats caches // with tls. Note that this test is still single-threaded, and so there's only // one replica of the tls cache. +// NOLINTNEXTLINE(readability-identifier-naming) static void BM_StatsWithTls(benchmark::State& state) { Envoy::ThreadLocalStorePerf context; context.initThreading(); diff --git a/test/common/tcp/conn_pool_test.cc b/test/common/tcp/conn_pool_test.cc index f81d9ffcd3342..726edfed05b00 100644 --- a/test/common/tcp/conn_pool_test.cc +++ b/test/common/tcp/conn_pool_test.cc @@ -49,6 +49,7 @@ struct ConnPoolCallbacks : public Tcp::ConnectionPool::Callbacks { void onPoolReady(ConnectionPool::ConnectionDataPtr&& conn, Upstream::HostDescriptionConstSharedPtr host) override { conn_data_ = std::move(conn); + conn_data_->addUpstreamCallbacks(callbacks_); host_ = host; pool_ready_.ready(); } @@ -60,6 +61,7 @@ struct ConnPoolCallbacks : public Tcp::ConnectionPool::Callbacks { pool_failure_.ready(); } + NiceMock callbacks_; ReadyWatcher pool_failure_; ReadyWatcher pool_ready_; ConnectionPool::ConnectionDataPtr conn_data_{}; @@ -151,7 +153,8 @@ class ConnPoolBase : public Tcp::ConnectionPool::Instance { public: ConnPoolImplForTest(Event::MockDispatcher& dispatcher, Upstream::HostSharedPtr host, ConnPoolBase& parent) - : ConnPoolImpl(dispatcher, host, Upstream::ResourcePriority::Default, nullptr, nullptr), + : ConnPoolImpl(dispatcher, host, Upstream::ResourcePriority::Default, nullptr, nullptr, + state_), parent_(parent) {} void onConnReleased(Envoy::ConnectionPool::ActiveClient& client) override { @@ -165,6 +168,8 @@ class ConnPoolBase : public Tcp::ConnectionPool::Instance { } void onConnDestroyed() override { parent_.onConnDestroyedForTest(); } + + Upstream::ClusterConnectivityState state_; Event::PostCb post_cb_; ConnPoolBase& parent_; }; @@ -273,7 +278,7 @@ class TcpConnPoolImplDestructorTest : public testing::TestWithParam { host_ = Upstream::makeTestHost(cluster_, "tcp://127.0.0.1:9000"); if (test_new_connection_pool_) { conn_pool_ = std::make_unique( - dispatcher_, host_, Upstream::ResourcePriority::Default, nullptr, nullptr); + dispatcher_, host_, Upstream::ResourcePriority::Default, nullptr, nullptr, state_); } else { conn_pool_ = std::make_unique( dispatcher_, host_, Upstream::ResourcePriority::Default, nullptr, nullptr); @@ -297,6 +302,7 @@ class TcpConnPoolImplDestructorTest : public testing::TestWithParam { } bool test_new_connection_pool_; + Upstream::ClusterConnectivityState state_; Upstream::HostConstSharedPtr host_; NiceMock dispatcher_; std::shared_ptr cluster_{new NiceMock()}; @@ -452,23 +458,20 @@ TEST_P(TcpConnPoolImplTest, VerifyBufferLimits) { TEST_P(TcpConnPoolImplTest, UpstreamCallbacks) { Buffer::OwnedImpl buffer; - ConnectionPool::MockUpstreamCallbacks callbacks; - - // Create connection, set UpstreamCallbacks + // Create connection, UpstreamCallbacks set automatically ActiveTestConn c1(*this, 0, ActiveTestConn::Type::CreateConnection); - c1.callbacks_.conn_data_->addUpstreamCallbacks(callbacks); // Expect invocation when connection's ReadFilter::onData is invoked - EXPECT_CALL(callbacks, onUpstreamData(_, _)); + EXPECT_CALL(c1.callbacks_.callbacks_, onUpstreamData(_, _)); EXPECT_EQ(Network::FilterStatus::StopIteration, conn_pool_.test_conns_[0].filter_->onData(buffer, false)); - EXPECT_CALL(callbacks, onAboveWriteBufferHighWatermark()); + EXPECT_CALL(c1.callbacks_.callbacks_, onAboveWriteBufferHighWatermark()); for (auto* cb : conn_pool_.test_conns_[0].connection_->callbacks_) { cb->onAboveWriteBufferHighWatermark(); } - EXPECT_CALL(callbacks, onBelowWriteBufferLowWatermark()); + EXPECT_CALL(c1.callbacks_.callbacks_, onBelowWriteBufferLowWatermark()); for (auto* cb : conn_pool_.test_conns_[0].connection_->callbacks_) { cb->onBelowWriteBufferLowWatermark(); } @@ -482,41 +485,6 @@ TEST_P(TcpConnPoolImplTest, UpstreamCallbacks) { dispatcher_.clearDeferredDeleteList(); } -/** - * Test that upstream callback close event fires for assigned connections. - */ -TEST_P(TcpConnPoolImplTest, UpstreamCallbacksCloseEvent) { - Buffer::OwnedImpl buffer; - - ConnectionPool::MockUpstreamCallbacks callbacks; - - // Create connection, set UpstreamCallbacks - ActiveTestConn c1(*this, 0, ActiveTestConn::Type::CreateConnection); - c1.callbacks_.conn_data_->addUpstreamCallbacks(callbacks); - - EXPECT_CALL(callbacks, onEvent(Network::ConnectionEvent::RemoteClose)); - - EXPECT_CALL(conn_pool_, onConnDestroyedForTest()); - conn_pool_.test_conns_[0].connection_->raiseEvent(Network::ConnectionEvent::RemoteClose); - dispatcher_.clearDeferredDeleteList(); -} - -/** - * Test that a connection pool functions without upstream callbacks. - */ -TEST_P(TcpConnPoolImplTest, NoUpstreamCallbacks) { - Buffer::OwnedImpl buffer; - - // Create connection. - ActiveTestConn c1(*this, 0, ActiveTestConn::Type::CreateConnection); - - // Trigger connection's ReadFilter::onData -- connection pool closes connection. - EXPECT_CALL(conn_pool_, onConnDestroyedForTest()); - EXPECT_EQ(Network::FilterStatus::StopIteration, - conn_pool_.test_conns_[0].filter_->onData(buffer, false)); - dispatcher_.clearDeferredDeleteList(); -} - /** * Tests a request that generates a new connection, completes, and then a second request that uses * the same connection. @@ -990,11 +958,8 @@ TEST_P(TcpConnPoolImplTest, DrainOnClose) { ActiveTestConn c1(*this, 0, ActiveTestConn::Type::CreateConnection); - ConnectionPool::MockUpstreamCallbacks callbacks; - c1.callbacks_.conn_data_->addUpstreamCallbacks(callbacks); - EXPECT_CALL(drained, ready()); - EXPECT_CALL(callbacks, onEvent(Network::ConnectionEvent::RemoteClose)) + EXPECT_CALL(c1.callbacks_.callbacks_, onEvent(Network::ConnectionEvent::RemoteClose)) .WillOnce(Invoke([&](Network::ConnectionEvent event) -> void { EXPECT_EQ(Network::ConnectionEvent::RemoteClose, event); c1.releaseConn(); diff --git a/test/common/tcp_proxy/upstream_test.cc b/test/common/tcp_proxy/upstream_test.cc index 9464d5d259705..af2a786ed8fe1 100644 --- a/test/common/tcp_proxy/upstream_test.cc +++ b/test/common/tcp_proxy/upstream_test.cc @@ -11,96 +11,110 @@ using testing::_; using testing::AnyNumber; +using testing::Return; namespace Envoy { namespace TcpProxy { namespace { -class HttpUpstreamTest : public testing::Test { +template class HttpUpstreamTest : public testing::Test { public: HttpUpstreamTest() { EXPECT_CALL(encoder_, getStream()).Times(AnyNumber()); EXPECT_CALL(encoder_, encodeHeaders(_, false)); - upstream_ = std::make_unique(callbacks_, hostname_); + EXPECT_CALL(encoder_, http1StreamEncoderOptions()).Times(AnyNumber()); + if (typeid(T) == typeid(Http1Upstream)) { + ON_CALL(encoder_, http1StreamEncoderOptions()) + .WillByDefault(Return(Http::Http1StreamEncoderOptionsOptRef(stream_encoder_options_))); + } + EXPECT_CALL(stream_encoder_options_, enableHalfClose()).Times(AnyNumber()); + upstream_ = std::make_unique(callbacks_, hostname_); upstream_->setRequestEncoder(encoder_, true); } Http::MockRequestEncoder encoder_; + Http::MockHttp1StreamEncoderOptions stream_encoder_options_; NiceMock callbacks_; std::unique_ptr upstream_; - std::string hostname_{"default.host.com"}; + std::string hostname_{"default.host.com:443"}; }; -TEST_F(HttpUpstreamTest, WriteUpstream) { - EXPECT_CALL(encoder_, encodeData(BufferStringEqual("foo"), false)); +using testing::Types; + +typedef Types Implementations; + +TYPED_TEST_SUITE(HttpUpstreamTest, Implementations); + +TYPED_TEST(HttpUpstreamTest, WriteUpstream) { + EXPECT_CALL(this->encoder_, encodeData(BufferStringEqual("foo"), false)); Buffer::OwnedImpl buffer1("foo"); - upstream_->encodeData(buffer1, false); + this->upstream_->encodeData(buffer1, false); - EXPECT_CALL(encoder_, encodeData(BufferStringEqual("bar"), true)); + EXPECT_CALL(this->encoder_, encodeData(BufferStringEqual("bar"), true)); Buffer::OwnedImpl buffer2("bar"); - upstream_->encodeData(buffer2, true); + this->upstream_->encodeData(buffer2, true); // New upstream with no encoder - upstream_ = std::make_unique(callbacks_, hostname_); - upstream_->encodeData(buffer2, true); + this->upstream_ = std::make_unique(this->callbacks_, this->hostname_); + this->upstream_->encodeData(buffer2, true); } -TEST_F(HttpUpstreamTest, WriteDownstream) { - EXPECT_CALL(callbacks_, onUpstreamData(BufferStringEqual("foo"), false)); +TYPED_TEST(HttpUpstreamTest, WriteDownstream) { + EXPECT_CALL(this->callbacks_, onUpstreamData(BufferStringEqual("foo"), false)); Buffer::OwnedImpl buffer1("foo"); - upstream_->responseDecoder().decodeData(buffer1, false); + this->upstream_->responseDecoder().decodeData(buffer1, false); - EXPECT_CALL(callbacks_, onUpstreamData(BufferStringEqual("bar"), true)); + EXPECT_CALL(this->callbacks_, onUpstreamData(BufferStringEqual("bar"), true)); Buffer::OwnedImpl buffer2("bar"); - upstream_->responseDecoder().decodeData(buffer2, true); + this->upstream_->responseDecoder().decodeData(buffer2, true); } -TEST_F(HttpUpstreamTest, InvalidUpgradeWithEarlyFin) { - EXPECT_CALL(callbacks_, onEvent(_)); +TYPED_TEST(HttpUpstreamTest, InvalidUpgradeWithEarlyFin) { + EXPECT_CALL(this->callbacks_, onEvent(_)); Http::ResponseHeaderMapPtr headers{new Http::TestResponseHeaderMapImpl{{":status", "200"}}}; - upstream_->responseDecoder().decodeHeaders(std::move(headers), true); + this->upstream_->responseDecoder().decodeHeaders(std::move(headers), true); } -TEST_F(HttpUpstreamTest, InvalidUpgradeWithNon200) { - EXPECT_CALL(callbacks_, onEvent(_)); +TYPED_TEST(HttpUpstreamTest, InvalidUpgradeWithNon200) { + EXPECT_CALL(this->callbacks_, onEvent(_)); Http::ResponseHeaderMapPtr headers{new Http::TestResponseHeaderMapImpl{{":status", "301"}}}; - upstream_->responseDecoder().decodeHeaders(std::move(headers), false); + this->upstream_->responseDecoder().decodeHeaders(std::move(headers), false); } -TEST_F(HttpUpstreamTest, ReadDisable) { - EXPECT_CALL(encoder_.stream_, readDisable(true)); - EXPECT_TRUE(upstream_->readDisable(true)); +TYPED_TEST(HttpUpstreamTest, ReadDisable) { + EXPECT_CALL(this->encoder_.stream_, readDisable(true)); + EXPECT_TRUE(this->upstream_->readDisable(true)); - EXPECT_CALL(encoder_.stream_, readDisable(false)); - EXPECT_TRUE(upstream_->readDisable(false)); + EXPECT_CALL(this->encoder_.stream_, readDisable(false)); + EXPECT_TRUE(this->upstream_->readDisable(false)); // New upstream with no encoder - upstream_ = std::make_unique(callbacks_, hostname_); - EXPECT_FALSE(upstream_->readDisable(true)); + this->upstream_ = std::make_unique(this->callbacks_, this->hostname_); + EXPECT_FALSE(this->upstream_->readDisable(true)); } -TEST_F(HttpUpstreamTest, AddBytesSentCallbackForCoverage) { - upstream_->addBytesSentCallback([&](uint64_t) {}); +TYPED_TEST(HttpUpstreamTest, AddBytesSentCallbackForCoverage) { + this->upstream_->addBytesSentCallback([&](uint64_t) {}); } -TEST_F(HttpUpstreamTest, DownstreamDisconnect) { - EXPECT_CALL(encoder_.stream_, resetStream(Http::StreamResetReason::LocalReset)); - EXPECT_CALL(callbacks_, onEvent(_)).Times(0); - EXPECT_TRUE(upstream_->onDownstreamEvent(Network::ConnectionEvent::LocalClose) == nullptr); +TYPED_TEST(HttpUpstreamTest, DownstreamDisconnect) { + EXPECT_CALL(this->encoder_.stream_, resetStream(Http::StreamResetReason::LocalReset)); + EXPECT_CALL(this->callbacks_, onEvent(_)).Times(0); + EXPECT_TRUE(this->upstream_->onDownstreamEvent(Network::ConnectionEvent::LocalClose) == nullptr); } -TEST_F(HttpUpstreamTest, UpstreamReset) { - EXPECT_CALL(encoder_.stream_, resetStream(_)).Times(0); - EXPECT_CALL(callbacks_, onEvent(_)); - upstream_->onResetStream(Http::StreamResetReason::ConnectionTermination, ""); +TYPED_TEST(HttpUpstreamTest, UpstreamReset) { + EXPECT_CALL(this->encoder_.stream_, resetStream(_)).Times(0); + EXPECT_CALL(this->callbacks_, onEvent(_)); + this->upstream_->onResetStream(Http::StreamResetReason::ConnectionTermination, ""); } -TEST_F(HttpUpstreamTest, UpstreamWatermarks) { - EXPECT_CALL(callbacks_, onAboveWriteBufferHighWatermark()); - upstream_->onAboveWriteBufferHighWatermark(); +TYPED_TEST(HttpUpstreamTest, UpstreamWatermarks) { + EXPECT_CALL(this->callbacks_, onAboveWriteBufferHighWatermark()); + this->upstream_->onAboveWriteBufferHighWatermark(); - EXPECT_CALL(callbacks_, onBelowWriteBufferLowWatermark()); - upstream_->onBelowWriteBufferLowWatermark(); + EXPECT_CALL(this->callbacks_, onBelowWriteBufferLowWatermark()); + this->upstream_->onBelowWriteBufferLowWatermark(); } } // namespace diff --git a/test/common/upstream/cds_api_impl_test.cc b/test/common/upstream/cds_api_impl_test.cc index f052749677fb3..a914225dd9d04 100644 --- a/test/common/upstream/cds_api_impl_test.cc +++ b/test/common/upstream/cds_api_impl_test.cc @@ -54,16 +54,20 @@ class CdsApiImplTest : public testing::Test { .WillOnce(Throw(EnvoyException(exception_msg))); } - ClusterManager::ClusterInfoMap makeClusterMap(const std::vector& clusters) { - ClusterManager::ClusterInfoMap map; - for (const auto& cluster : clusters) { - map.emplace(cluster, cm_.thread_local_cluster_.cluster_); + ClusterManager::ClusterInfoMaps + makeClusterInfoMaps(const std::vector& active_clusters, + const std::vector& warming_clusters = {}) { + ClusterManager::ClusterInfoMaps maps; + for (const auto& cluster : active_clusters) { + maps.active_clusters_.emplace(cluster, cm_.thread_local_cluster_.cluster_); } - return map; + for (const auto& cluster : warming_clusters) { + maps.warming_clusters_.emplace(cluster, cm_.thread_local_cluster_.cluster_); + } + return maps; } NiceMock cm_; - Upstream::ClusterManager::ClusterInfoMap cluster_map_; Upstream::MockClusterMockPrioritySet mock_cluster_; Stats::IsolatedStoreImpl store_; CdsApiPtr cds_; @@ -92,7 +96,7 @@ version_info: '0' auto response1 = TestUtility::parseYaml(response1_yaml); - EXPECT_CALL(cm_, clusters()).WillOnce(Return(ClusterManager::ClusterInfoMap{})); + EXPECT_CALL(cm_, clusters()).WillOnce(Return(makeClusterInfoMaps({}))); expectAdd("cluster1", "0"); EXPECT_CALL(initialized_, ready()); EXPECT_EQ("", cds_->versionInfo()); @@ -108,7 +112,7 @@ version_info: '1' )EOF"; auto response2 = TestUtility::parseYaml(response2_yaml); - EXPECT_CALL(cm_, clusters()).WillOnce(Return(makeClusterMap({"cluster1"}))); + EXPECT_CALL(cm_, clusters()).WillOnce(Return(makeClusterInfoMaps({"cluster1"}))); EXPECT_CALL(cm_, removeCluster("cluster1")).WillOnce(Return(true)); const auto decoded_resources_2 = TestUtility::decodeResources(response2); @@ -126,7 +130,7 @@ TEST_F(CdsApiImplTest, ValidateDuplicateClusters) { cluster_1.set_name("duplicate_cluster"); const auto decoded_resources = TestUtility::decodeResources({cluster_1, cluster_1}); - EXPECT_CALL(cm_, clusters()).WillRepeatedly(Return(cluster_map_)); + EXPECT_CALL(cm_, clusters()).WillRepeatedly(Return(makeClusterInfoMaps({}))); EXPECT_CALL(initialized_, ready()); EXPECT_THROW_WITH_MESSAGE(cds_callbacks_->onConfigUpdate(decoded_resources.refvec_, ""), EnvoyException, @@ -139,7 +143,7 @@ TEST_F(CdsApiImplTest, EmptyConfigUpdate) { setup(); - EXPECT_CALL(cm_, clusters()).WillOnce(Return(ClusterManager::ClusterInfoMap{})); + EXPECT_CALL(cm_, clusters()).WillOnce(Return(makeClusterInfoMaps({}))); EXPECT_CALL(initialized_, ready()); cds_callbacks_->onConfigUpdate({}, ""); @@ -151,7 +155,7 @@ TEST_F(CdsApiImplTest, ConfigUpdateWith2ValidClusters) { setup(); } - EXPECT_CALL(cm_, clusters()).WillOnce(Return(ClusterManager::ClusterInfoMap{})); + EXPECT_CALL(cm_, clusters()).WillOnce(Return(makeClusterInfoMaps({}))); EXPECT_CALL(initialized_, ready()); envoy::config::cluster::v3::Cluster cluster_1; @@ -224,7 +228,7 @@ TEST_F(CdsApiImplTest, ConfigUpdateAddsSecondClusterEvenIfFirstThrows) { setup(); } - EXPECT_CALL(cm_, clusters()).WillOnce(Return(ClusterManager::ClusterInfoMap{})); + EXPECT_CALL(cm_, clusters()).WillOnce(Return(makeClusterInfoMaps({}))); EXPECT_CALL(initialized_, ready()); envoy::config::cluster::v3::Cluster cluster_1; @@ -269,7 +273,7 @@ version_info: '0' auto response1 = TestUtility::parseYaml(response1_yaml); - EXPECT_CALL(cm_, clusters()).WillOnce(Return(ClusterManager::ClusterInfoMap{})); + EXPECT_CALL(cm_, clusters()).WillOnce(Return(makeClusterInfoMaps({}))); expectAdd("cluster1", "0"); expectAdd("cluster2", "0"); EXPECT_CALL(initialized_, ready()); @@ -298,7 +302,7 @@ version_info: '1' auto response2 = TestUtility::parseYaml(response2_yaml); - EXPECT_CALL(cm_, clusters()).WillOnce(Return(makeClusterMap({"cluster1", "cluster2"}))); + EXPECT_CALL(cm_, clusters()).WillOnce(Return(makeClusterInfoMaps({"cluster1", "cluster2"}))); expectAdd("cluster1", "1"); expectAdd("cluster3", "1"); EXPECT_CALL(cm_, removeCluster("cluster2")); @@ -334,7 +338,7 @@ version_info: '0' auto response1 = TestUtility::parseYaml(response1_yaml); - EXPECT_CALL(cm_, clusters()).WillRepeatedly(Return(cluster_map_)); + EXPECT_CALL(cm_, clusters()).WillRepeatedly(Return(makeClusterInfoMaps({}))); EXPECT_CALL(initialized_, ready()); const auto decoded_resources = TestUtility::decodeResources(response1); diff --git a/test/common/upstream/cluster_manager_impl_test.cc b/test/common/upstream/cluster_manager_impl_test.cc index a4f2122c49458..21217a4217527 100644 --- a/test/common/upstream/cluster_manager_impl_test.cc +++ b/test/common/upstream/cluster_manager_impl_test.cc @@ -361,7 +361,7 @@ TEST_F(ClusterManagerImplTest, ValidClusterName) { create(parseBootstrapFromV3Yaml(yaml)); cluster_manager_->clusters() - .find("cluster:name") + .active_clusters_.find("cluster:name") ->second.get() .info() ->statsScope() @@ -1490,9 +1490,9 @@ TEST_F(ClusterManagerImplTest, DynamicAddRemove) { EXPECT_TRUE(cluster_manager_->addOrUpdateCluster(update_cluster, "")); EXPECT_EQ(cluster2->info_, cluster_manager_->get("fake_cluster")->info()); - EXPECT_EQ(1UL, cluster_manager_->clusters().size()); + EXPECT_EQ(1UL, cluster_manager_->clusters().active_clusters_.size()); Http::ConnectionPool::MockInstance* cp = new Http::ConnectionPool::MockInstance(); - EXPECT_CALL(factory_, allocateConnPool_(_, _, _)).WillOnce(Return(cp)); + EXPECT_CALL(factory_, allocateConnPool_(_, _, _, _)).WillOnce(Return(cp)); EXPECT_EQ(cp, cluster_manager_->httpConnPoolForCluster("fake_cluster", ResourcePriority::Default, Http::Protocol::Http11, nullptr)); @@ -1520,7 +1520,7 @@ TEST_F(ClusterManagerImplTest, DynamicAddRemove) { EXPECT_CALL(*cp2, addDrainedCallback(_)).WillOnce(SaveArg<0>(&drained_cb2)); EXPECT_TRUE(cluster_manager_->removeCluster("fake_cluster")); EXPECT_EQ(nullptr, cluster_manager_->get("fake_cluster")); - EXPECT_EQ(0UL, cluster_manager_->clusters().size()); + EXPECT_EQ(0UL, cluster_manager_->clusters().active_clusters_.size()); // Close the TCP connection. Success is no ASSERT or crash due to referencing // the removed cluster. @@ -1649,7 +1649,7 @@ TEST_F(ClusterManagerImplTest, CloseHttpConnectionsOnHealthFailure) { })); create(parseBootstrapFromV3Json(json)); - EXPECT_CALL(factory_, allocateConnPool_(_, _, _)).WillOnce(Return(cp1)); + EXPECT_CALL(factory_, allocateConnPool_(_, _, _, _)).WillOnce(Return(cp1)); cluster_manager_->httpConnPoolForCluster("some_cluster", ResourcePriority::Default, Http::Protocol::Http11, nullptr); @@ -1660,7 +1660,7 @@ TEST_F(ClusterManagerImplTest, CloseHttpConnectionsOnHealthFailure) { test_host->healthFlagSet(Host::HealthFlag::FAILED_OUTLIER_CHECK); outlier_detector.runCallbacks(test_host); - EXPECT_CALL(factory_, allocateConnPool_(_, _, _)).WillOnce(Return(cp2)); + EXPECT_CALL(factory_, allocateConnPool_(_, _, _, _)).WillOnce(Return(cp2)); cluster_manager_->httpConnPoolForCluster("some_cluster", ResourcePriority::High, Http::Protocol::Http11, nullptr); } @@ -1925,7 +1925,7 @@ TEST_F(ClusterManagerImplTest, DynamicHostRemove) { EXPECT_CALL(initialized, ready()); cluster_manager_->setInitializedCb([&]() -> void { initialized.ready(); }); - EXPECT_CALL(factory_, allocateConnPool_(_, _, _)) + EXPECT_CALL(factory_, allocateConnPool_(_, _, _, _)) .Times(4) .WillRepeatedly(ReturnNew()); @@ -2098,7 +2098,7 @@ TEST_F(ClusterManagerImplTest, DynamicHostRemoveWithTls) { EXPECT_CALL(initialized, ready()); cluster_manager_->setInitializedCb([&]() -> void { initialized.ready(); }); - EXPECT_CALL(factory_, allocateConnPool_(_, _, _)) + EXPECT_CALL(factory_, allocateConnPool_(_, _, _, _)) .Times(4) .WillRepeatedly(ReturnNew()); @@ -2380,7 +2380,7 @@ TEST_F(ClusterManagerImplTest, DynamicHostRemoveDefaultPriority) { dns_callback(Network::DnsResolver::ResolutionStatus::Success, TestUtility::makeDnsResponse({"127.0.0.2"})); - EXPECT_CALL(factory_, allocateConnPool_(_, _, _)) + EXPECT_CALL(factory_, allocateConnPool_(_, _, _, _)) .WillOnce(ReturnNew()); EXPECT_CALL(factory_, allocateTcpConnPool_(_)) @@ -2462,7 +2462,7 @@ TEST_F(ClusterManagerImplTest, ConnPoolDestroyWithDraining) { TestUtility::makeDnsResponse({"127.0.0.2"})); MockConnPoolWithDestroy* mock_cp = new MockConnPoolWithDestroy(); - EXPECT_CALL(factory_, allocateConnPool_(_, _, _)).WillOnce(Return(mock_cp)); + EXPECT_CALL(factory_, allocateConnPool_(_, _, _, _)).WillOnce(Return(mock_cp)); MockTcpConnPoolWithDestroy* mock_tcp = new MockTcpConnPoolWithDestroy(); EXPECT_CALL(factory_, allocateTcpConnPool_(_)).WillOnce(Return(mock_tcp)); @@ -2911,7 +2911,7 @@ TEST_F(ClusterManagerImplTest, UpstreamSocketOptionsPassedToConnPool) { Network::SocketOptionFactory::buildIpTransparentOptions(); EXPECT_CALL(context, upstreamSocketOptions()).WillOnce(Return(options_to_return)); - EXPECT_CALL(factory_, allocateConnPool_(_, _, _)).WillOnce(Return(to_create)); + EXPECT_CALL(factory_, allocateConnPool_(_, _, _, _)).WillOnce(Return(to_create)); Http::ConnectionPool::Instance* cp = cluster_manager_->httpConnPoolForCluster( "cluster_1", ResourcePriority::Default, Http::Protocol::Http11, &context); @@ -2933,12 +2933,12 @@ TEST_F(ClusterManagerImplTest, UpstreamSocketOptionsUsedInConnPoolHash) { EXPECT_CALL(context1, upstreamSocketOptions()).WillRepeatedly(Return(options1)); EXPECT_CALL(context2, upstreamSocketOptions()).WillRepeatedly(Return(options2)); - EXPECT_CALL(factory_, allocateConnPool_(_, _, _)).WillOnce(Return(to_create1)); + EXPECT_CALL(factory_, allocateConnPool_(_, _, _, _)).WillOnce(Return(to_create1)); Http::ConnectionPool::Instance* cp1 = cluster_manager_->httpConnPoolForCluster( "cluster_1", ResourcePriority::Default, Http::Protocol::Http11, &context1); - EXPECT_CALL(factory_, allocateConnPool_(_, _, _)).WillOnce(Return(to_create2)); + EXPECT_CALL(factory_, allocateConnPool_(_, _, _, _)).WillOnce(Return(to_create2)); Http::ConnectionPool::Instance* cp2 = cluster_manager_->httpConnPoolForCluster( "cluster_1", ResourcePriority::Default, Http::Protocol::Http11, &context2); @@ -2963,7 +2963,7 @@ TEST_F(ClusterManagerImplTest, UpstreamSocketOptionsNullIsOkay) { Network::Socket::OptionsSharedPtr options_to_return = nullptr; EXPECT_CALL(context, upstreamSocketOptions()).WillOnce(Return(options_to_return)); - EXPECT_CALL(factory_, allocateConnPool_(_, _, _)).WillOnce(Return(to_create)); + EXPECT_CALL(factory_, allocateConnPool_(_, _, _, _)).WillOnce(Return(to_create)); Http::ConnectionPool::Instance* cp = cluster_manager_->httpConnPoolForCluster( "cluster_1", ResourcePriority::Default, Http::Protocol::Http11, &context); @@ -3863,7 +3863,7 @@ TEST_F(ClusterManagerImplTest, ConnPoolsDrainedOnHostSetChange) { EXPECT_EQ(0, factory_.stats_.counter("cluster_manager.cluster_updated_via_merge").value()); EXPECT_EQ(0, factory_.stats_.counter("cluster_manager.update_merge_cancelled").value()); - EXPECT_CALL(factory_, allocateConnPool_(_, _, _)) + EXPECT_CALL(factory_, allocateConnPool_(_, _, _, _)) .Times(3) .WillRepeatedly(ReturnNew()); @@ -3967,7 +3967,7 @@ TEST_F(ClusterManagerImplTest, ConnPoolsNotDrainedOnHostSetChange) { 0, HostSetImpl::partitionHosts(hosts_ptr, HostsPerLocalityImpl::empty()), nullptr, hosts, {}, 100); - EXPECT_CALL(factory_, allocateConnPool_(_, _, _)) + EXPECT_CALL(factory_, allocateConnPool_(_, _, _, _)) .Times(1) .WillRepeatedly(ReturnNew()); @@ -4104,7 +4104,7 @@ TEST_F(ClusterManagerImplTest, ConnectionPoolPerDownstreamConnection) { std::vector conn_pool_vector; for (size_t i = 0; i < 3; ++i) { conn_pool_vector.push_back(new Http::ConnectionPool::MockInstance()); - EXPECT_CALL(factory_, allocateConnPool_(_, _, _)).WillOnce(Return(conn_pool_vector.back())); + EXPECT_CALL(factory_, allocateConnPool_(_, _, _, _)).WillOnce(Return(conn_pool_vector.back())); EXPECT_CALL(downstream_connection, hashKey) .WillOnce(Invoke([i](std::vector& hash_key) { hash_key.push_back(i); })); EXPECT_EQ(conn_pool_vector.back(), @@ -4177,7 +4177,7 @@ TEST_F(PrefetchTest, PrefetchOff) { // With prefetch set to 0, each request for a connection pool will only // allocate that conn pool. initialize(0); - EXPECT_CALL(factory_, allocateConnPool_(_, _, _)) + EXPECT_CALL(factory_, allocateConnPool_(_, _, _, _)) .Times(1) .WillRepeatedly(ReturnNew()); cluster_manager_->httpConnPoolForCluster("cluster_1", ResourcePriority::Default, @@ -4194,7 +4194,7 @@ TEST_F(PrefetchTest, PrefetchOn) { // prefetching, so create the pool for both the current connection and the // anticipated one. initialize(1.1); - EXPECT_CALL(factory_, allocateConnPool_(_, _, _)) + EXPECT_CALL(factory_, allocateConnPool_(_, _, _, _)) .Times(2) .WillRepeatedly(ReturnNew>()); cluster_manager_->httpConnPoolForCluster("cluster_1", ResourcePriority::Default, diff --git a/test/common/upstream/load_stats_reporter_test.cc b/test/common/upstream/load_stats_reporter_test.cc index 111e7356a064b..46105592c00a3 100644 --- a/test/common/upstream/load_stats_reporter_test.cc +++ b/test/common/upstream/load_stats_reporter_test.cc @@ -125,7 +125,8 @@ TEST_F(LoadStatsReporterTest, ExistingClusters) { foo_cluster.info_->load_report_stats_.upstream_rq_dropped_.add(2); foo_cluster.info_->eds_service_name_ = "bar"; NiceMock bar_cluster; - MockClusterManager::ClusterInfoMap cluster_info{{"foo", foo_cluster}, {"bar", bar_cluster}}; + MockClusterManager::ClusterInfoMaps cluster_info{{{"foo", foo_cluster}, {"bar", bar_cluster}}, + {}}; ON_CALL(cm_, clusters()).WillByDefault(Return(cluster_info)); deliverLoadStatsResponse({"foo"}); // Initial stats report for foo on timer tick. diff --git a/test/common/upstream/test_cluster_manager.h b/test/common/upstream/test_cluster_manager.h index 3cce3f09182d9..0c221529cb45a 100644 --- a/test/common/upstream/test_cluster_manager.h +++ b/test/common/upstream/test_cluster_manager.h @@ -77,18 +77,20 @@ class TestClusterManagerFactory : public ClusterManagerFactory { })); } - Http::ConnectionPool::InstancePtr allocateConnPool( - Event::Dispatcher&, HostConstSharedPtr host, ResourcePriority, Http::Protocol, - const Network::ConnectionSocket::OptionsSharedPtr& options, - const Network::TransportSocketOptionsSharedPtr& transport_socket_options) override { + Http::ConnectionPool::InstancePtr + allocateConnPool(Event::Dispatcher&, HostConstSharedPtr host, ResourcePriority, Http::Protocol, + const Network::ConnectionSocket::OptionsSharedPtr& options, + const Network::TransportSocketOptionsSharedPtr& transport_socket_options, + ClusterConnectivityState& state) override { return Http::ConnectionPool::InstancePtr{ - allocateConnPool_(host, options, transport_socket_options)}; + allocateConnPool_(host, options, transport_socket_options, state)}; } Tcp::ConnectionPool::InstancePtr allocateTcpConnPool(Event::Dispatcher&, HostConstSharedPtr host, ResourcePriority, const Network::ConnectionSocket::OptionsSharedPtr&, - Network::TransportSocketOptionsSharedPtr) override { + Network::TransportSocketOptionsSharedPtr, + Upstream::ClusterConnectivityState&) override { return Tcp::ConnectionPool::InstancePtr{allocateTcpConnPool_(host)}; } @@ -115,7 +117,7 @@ class TestClusterManagerFactory : public ClusterManagerFactory { (const envoy::config::bootstrap::v3::Bootstrap& bootstrap)); MOCK_METHOD(Http::ConnectionPool::Instance*, allocateConnPool_, (HostConstSharedPtr host, Network::ConnectionSocket::OptionsSharedPtr, - Network::TransportSocketOptionsSharedPtr)); + Network::TransportSocketOptionsSharedPtr, ClusterConnectivityState&)); MOCK_METHOD(Tcp::ConnectionPool::Instance*, allocateTcpConnPool_, (HostConstSharedPtr host)); MOCK_METHOD((std::pair), clusterFromProto_, (const envoy::config::cluster::v3::Cluster& cluster, ClusterManager& cm, diff --git a/test/common/upstream/utility.h b/test/common/upstream/utility.h index ef3dd210adf38..cd92eb9d37a3e 100644 --- a/test/common/upstream/utility.h +++ b/test/common/upstream/utility.h @@ -79,48 +79,48 @@ inline envoy::config::cluster::v3::Cluster defaultStaticCluster(const std::strin inline HostSharedPtr makeTestHost(ClusterInfoConstSharedPtr cluster, const std::string& hostname, const std::string& url, uint32_t weight = 1) { - return HostSharedPtr{ - new HostImpl(cluster, hostname, Network::Utility::resolveUrl(url), nullptr, weight, - envoy::config::core::v3::Locality(), - envoy::config::endpoint::v3::Endpoint::HealthCheckConfig::default_instance(), 0, - envoy::config::core::v3::UNKNOWN)}; + return std::make_shared( + cluster, hostname, Network::Utility::resolveUrl(url), nullptr, weight, + envoy::config::core::v3::Locality(), + envoy::config::endpoint::v3::Endpoint::HealthCheckConfig::default_instance(), 0, + envoy::config::core::v3::UNKNOWN); } inline HostSharedPtr makeTestHost(ClusterInfoConstSharedPtr cluster, const std::string& url, uint32_t weight = 1, uint32_t priority = 0) { - return HostSharedPtr{ - new HostImpl(cluster, "", Network::Utility::resolveUrl(url), nullptr, weight, - envoy::config::core::v3::Locality(), - envoy::config::endpoint::v3::Endpoint::HealthCheckConfig::default_instance(), - priority, envoy::config::core::v3::UNKNOWN)}; + return std::make_shared( + cluster, "", Network::Utility::resolveUrl(url), nullptr, weight, + envoy::config::core::v3::Locality(), + envoy::config::endpoint::v3::Endpoint::HealthCheckConfig::default_instance(), priority, + envoy::config::core::v3::UNKNOWN); } inline HostSharedPtr makeTestHost(ClusterInfoConstSharedPtr cluster, const std::string& url, const envoy::config::core::v3::Metadata& metadata, uint32_t weight = 1) { - return HostSharedPtr{ - new HostImpl(cluster, "", Network::Utility::resolveUrl(url), - std::make_shared(metadata), weight, - envoy::config::core::v3::Locality(), - envoy::config::endpoint::v3::Endpoint::HealthCheckConfig::default_instance(), 0, - envoy::config::core::v3::UNKNOWN)}; + return std::make_shared( + cluster, "", Network::Utility::resolveUrl(url), + std::make_shared(metadata), weight, + envoy::config::core::v3::Locality(), + envoy::config::endpoint::v3::Endpoint::HealthCheckConfig::default_instance(), 0, + envoy::config::core::v3::UNKNOWN); } inline HostSharedPtr makeTestHost(ClusterInfoConstSharedPtr cluster, const std::string& url, const envoy::config::endpoint::v3::Endpoint::HealthCheckConfig& health_check_config, uint32_t weight = 1) { - return HostSharedPtr{new HostImpl(cluster, "", Network::Utility::resolveUrl(url), nullptr, weight, + return std::make_shared(cluster, "", Network::Utility::resolveUrl(url), nullptr, weight, envoy::config::core::v3::Locality(), health_check_config, 0, - envoy::config::core::v3::UNKNOWN)}; + envoy::config::core::v3::UNKNOWN); } inline HostDescriptionConstSharedPtr makeTestHostDescription(ClusterInfoConstSharedPtr cluster, const std::string& url) { - return HostDescriptionConstSharedPtr{new HostDescriptionImpl( + return std::make_shared( cluster, "", Network::Utility::resolveUrl(url), nullptr, envoy::config::core::v3::Locality().default_instance(), - envoy::config::endpoint::v3::Endpoint::HealthCheckConfig::default_instance(), 0)}; + envoy::config::endpoint::v3::Endpoint::HealthCheckConfig::default_instance(), 0); } inline HostsPerLocalitySharedPtr makeHostsPerLocality(std::vector&& locality_hosts, diff --git a/test/config/integration/BUILD b/test/config/integration/BUILD index 1fbb9f235da1a..0ad3ed072f77f 100644 --- a/test/config/integration/BUILD +++ b/test/config/integration/BUILD @@ -42,5 +42,8 @@ filegroup( filegroup( name = "google_com_proxy_port_0", - srcs = ["google_com_proxy_port_0.yaml"], + srcs = [ + "google_com_proxy_port_0.yaml", + "google_com_proxy_port_0_with_kill_request_filter.yaml", + ], ) diff --git a/test/config/integration/google_com_proxy_port_0_with_kill_request_filter.yaml b/test/config/integration/google_com_proxy_port_0_with_kill_request_filter.yaml new file mode 100644 index 0000000000000..b9d2f06e5de20 --- /dev/null +++ b/test/config/integration/google_com_proxy_port_0_with_kill_request_filter.yaml @@ -0,0 +1,49 @@ +admin: + access_log_path: "{{ null_device_path }}" + address: + socket_address: + address: "{{ ip_any_address }}" + port_value: 0 + +static_resources: + listeners: + - name: listener_0 + address: + socket_address: + address: "{{ ip_any_address }}" + port_value: 0 + filter_chains: + - filters: + - name: http + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + stat_prefix: ingress_http + codec_type: AUTO + route_config: + name: local_route + virtual_hosts: + - name: local_service + domains: ["*"] + routes: + - match: { prefix: "/" } + route: { host_rewrite_literal: www.google.com, cluster: service_google } + http_filters: + - name: envoy.filters.http.kill_request + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.kill_request.v3.KillRequest + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + clusters: + - name: service_google + connect_timeout: 0.25s + type: LOGICAL_DNS + # Comment out the following line to test on v6 networks + dns_lookup_family: {{ dns_lookup_family }} + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: service_google + endpoints: + - lb_endpoints: + - endpoint: + address: { socket_address: { address: google.com, port_value: 443 }} diff --git a/test/exe/main_common_test.cc b/test/exe/main_common_test.cc index 8428cf6b43fe3..6cb69ee6fb7ad 100644 --- a/test/exe/main_common_test.cc +++ b/test/exe/main_common_test.cc @@ -455,4 +455,15 @@ TEST_P(MainCommonTest, ConstructDestructLogger) { Logger::Registry::getSink()->log(log_msg); } +// Verify KillRequest filter is not built into Envoy by default. +TEST_P(MainCommonTest, KillRequestFilterIsNotBuiltByDefault) { + config_file_ = TestEnvironment::temporaryFileSubstitute( + "test/config/integration/google_com_proxy_port_0_with_kill_request_filter.yaml", + TestEnvironment::ParamMap(), TestEnvironment::PortMap(), GetParam()); + argv_ = {"envoy-static", "--use-dynamic-base-id", "-c", config_file_.c_str(), nullptr}; + + EXPECT_THROW_WITH_REGEX(MainCommon main_common(argc(), argv()), EnvoyException, + "unknown type: envoy.extensions.filters.http.kill_request"); +} + } // namespace Envoy diff --git a/test/extensions/access_loggers/wasm/BUILD b/test/extensions/access_loggers/wasm/BUILD index 54ab90482a917..fc56bc9b7c396 100644 --- a/test/extensions/access_loggers/wasm/BUILD +++ b/test/extensions/access_loggers/wasm/BUILD @@ -25,6 +25,7 @@ envoy_extension_cc_test( deps = [ "//source/extensions/access_loggers/wasm:config", "//test/extensions/access_loggers/wasm/test_data:test_cpp_plugin", + "//test/extensions/common/wasm:wasm_runtime", "//test/mocks/server:server_mocks", "//test/test_common:environment_lib", "//test/test_common:utility_lib", diff --git a/test/extensions/access_loggers/wasm/config_test.cc b/test/extensions/access_loggers/wasm/config_test.cc index 744f074fdb8cd..fb570453db308 100644 --- a/test/extensions/access_loggers/wasm/config_test.cc +++ b/test/extensions/access_loggers/wasm/config_test.cc @@ -9,6 +9,7 @@ #include "extensions/access_loggers/well_known_names.h" #include "extensions/common/wasm/wasm.h" +#include "test/extensions/common/wasm/wasm_runtime.h" #include "test/mocks/server/mocks.h" #include "test/test_common/environment.h" #include "test/test_common/printers.h" @@ -39,20 +40,8 @@ class TestFactoryContext : public NiceMock {}; -// NB: this is required by VC++ which can not handle the use of macros in the macro definitions -// used by INSTANTIATE_TEST_SUITE_P. -auto testing_values = testing::Values( -#if defined(ENVOY_WASM_V8) - "v8", -#endif -#if defined(ENVOY_WASM_WAVM) - "wavm", -#endif -#if defined(ENVOY_WASM_WASMTIME) - "wasmtime", -#endif - "null"); -INSTANTIATE_TEST_SUITE_P(Runtimes, WasmAccessLogConfigTest, testing_values); +INSTANTIATE_TEST_SUITE_P(Runtimes, WasmAccessLogConfigTest, + Envoy::Extensions::Common::Wasm::runtime_values); TEST_P(WasmAccessLogConfigTest, CreateWasmFromEmpty) { auto factory = diff --git a/test/extensions/bootstrap/wasm/BUILD b/test/extensions/bootstrap/wasm/BUILD index 6a6488e2b63b8..b9c8282420c30 100644 --- a/test/extensions/bootstrap/wasm/BUILD +++ b/test/extensions/bootstrap/wasm/BUILD @@ -37,6 +37,7 @@ envoy_extension_cc_test( "//source/extensions/bootstrap/wasm:config", "//source/extensions/common/wasm:wasm_lib", "//test/extensions/bootstrap/wasm/test_data:stats_cpp_plugin", + "//test/extensions/common/wasm:wasm_runtime", "//test/mocks/server:server_mocks", "//test/mocks/upstream:upstream_mocks", "//test/test_common:environment_lib", @@ -58,6 +59,7 @@ envoy_extension_cc_test( "//source/extensions/bootstrap/wasm:config", "//source/extensions/common/wasm:wasm_lib", "//test/extensions/bootstrap/wasm/test_data:start_cpp_plugin", + "//test/extensions/common/wasm:wasm_runtime", "//test/mocks/event:event_mocks", "//test/mocks/server:server_mocks", "//test/mocks/thread_local:thread_local_mocks", @@ -85,6 +87,7 @@ envoy_extension_cc_test_binary( "//source/extensions/bootstrap/wasm:config", "//source/extensions/common/wasm:wasm_lib", "//test/extensions/bootstrap/wasm/test_data:speed_cpp_plugin", + "//test/extensions/common/wasm:wasm_runtime", "//test/mocks/server:server_mocks", "//test/mocks/upstream:upstream_mocks", "//test/test_common:environment_lib", diff --git a/test/extensions/bootstrap/wasm/config_test.cc b/test/extensions/bootstrap/wasm/config_test.cc index bd5d4b9471662..a0b7274e53fd2 100644 --- a/test/extensions/bootstrap/wasm/config_test.cc +++ b/test/extensions/bootstrap/wasm/config_test.cc @@ -6,6 +6,7 @@ #include "extensions/bootstrap/wasm/config.h" +#include "test/extensions/common/wasm/wasm_runtime.h" #include "test/mocks/event/mocks.h" #include "test/mocks/server/mocks.h" #include "test/mocks/thread_local/mocks.h" @@ -67,20 +68,8 @@ class WasmFactoryTest : public testing::TestWithParam { Server::BootstrapExtensionPtr extension_; }; -// NB: this is required by VC++ which can not handle the use of macros in the macro definitions -// used by INSTANTIATE_TEST_SUITE_P. -auto testing_values = testing::Values( -#if defined(ENVOY_WASM_V8) - "v8", -#endif -#if defined(ENVOY_WASM_WAVM) - "wavm", -#endif -#if defined(ENVOY_WASM_WASMTIME) - "wasmtime", -#endif - "null"); -INSTANTIATE_TEST_SUITE_P(Runtimes, WasmFactoryTest, testing_values); +INSTANTIATE_TEST_SUITE_P(Runtimes, WasmFactoryTest, + Envoy::Extensions::Common::Wasm::runtime_values); TEST_P(WasmFactoryTest, CreateWasmFromWasm) { auto factory = std::make_unique(); diff --git a/test/extensions/bootstrap/wasm/wasm_test.cc b/test/extensions/bootstrap/wasm/wasm_test.cc index 5384c66dcae87..757b086770b6e 100644 --- a/test/extensions/bootstrap/wasm/wasm_test.cc +++ b/test/extensions/bootstrap/wasm/wasm_test.cc @@ -3,6 +3,7 @@ #include "extensions/common/wasm/wasm.h" +#include "test/extensions/common/wasm/wasm_runtime.h" #include "test/mocks/server/mocks.h" #include "test/mocks/upstream/mocks.h" #include "test/test_common/environment.h" @@ -73,34 +74,14 @@ class WasmTestBase { std::shared_ptr wasm_; }; -#if defined(ENVOY_WASM_V8) || defined(ENVOY_WASM_WAVM) || defined(ENVOY_WASM_WASMTIME) class WasmTest : public WasmTestBase, public testing::TestWithParam { public: void createWasm() { WasmTestBase::createWasm(GetParam()); } }; -// NB: this is required by VC++ which can not handle the use of macros in the macro definitions -// used by INSTANTIATE_TEST_SUITE_P. -auto testing_values = testing::Values( -#if defined(ENVOY_WASM_V8) - "v8" -#endif -#if defined(ENVOY_WASM_V8) && (defined(ENVOY_WASM_WAVM) || defined(ENVOY_WASM_WASMTIME)) - , -#endif -#if defined(ENVOY_WASM_WAVM) - "wavm" -#endif -#if (defined(ENVOY_WASM_V8) || defined(ENVOY_WASM_WAVM)) && defined(ENVOY_WASM_WASMTIME) - , -#endif -#if defined(ENVOY_WASM_WASMTIME) - "wasmtime" -#endif -); - -INSTANTIATE_TEST_SUITE_P(Runtimes, WasmTest, testing_values); -#endif +INSTANTIATE_TEST_SUITE_P(Runtimes, WasmTest, + Envoy::Extensions::Common::Wasm::sandbox_runtime_values); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WasmTest); class WasmNullTest : public WasmTestBase, public testing::TestWithParam { public: @@ -116,22 +97,8 @@ class WasmNullTest : public WasmTestBase, public testing::TestWithParam> { public: @@ -151,24 +118,9 @@ class WasmTestMatrix : public WasmTestBase, }; INSTANTIATE_TEST_SUITE_P(RuntimesAndLanguages, WasmTestMatrix, - testing::Combine(testing::Values( -#if defined(ENVOY_WASM_V8) - "v8" -#endif -#if defined(ENVOY_WASM_V8) && (defined(ENVOY_WASM_WAVM) || defined(ENVOY_WASM_WASMTIME)) - , -#endif -#if defined(ENVOY_WASM_WAVM) - "wavm" -#endif -#if (defined(ENVOY_WASM_V8) || defined(ENVOY_WASM_WAVM)) && defined(ENVOY_WASM_WASMTIME) - , -#endif -#if defined(ENVOY_WASM_WASMTIME) - "wasmtime" -#endif - ), + testing::Combine(Envoy::Extensions::Common::Wasm::sandbox_runtime_values, testing::Values("cpp", "rust"))); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WasmTestMatrix); TEST_P(WasmTestMatrix, Logging) { plugin_configuration_ = "configure-test"; @@ -202,9 +154,7 @@ TEST_P(WasmTestMatrix, Logging) { dispatcher_->run(Event::Dispatcher::RunType::NonBlock); dispatcher_->clearDeferredDeleteList(); } -#endif -#if defined(ENVOY_WASM_V8) || defined(ENVOY_WASM_WAVM) || defined(ENVOY_WASM_WASMTIME) TEST_P(WasmTest, BadSignature) { createWasm(); const auto code = TestEnvironment::readFileToStringForTest(TestEnvironment::substitute( @@ -266,7 +216,6 @@ TEST_P(WasmTest, Asm2Wasm) { EXPECT_CALL(*context, log_(spdlog::level::info, Eq("out 0 0 0"))); EXPECT_TRUE(wasm_->configure(context, plugin_)); } -#endif TEST_P(WasmNullTest, Stats) { createWasm(); diff --git a/test/extensions/common/redis/cluster_refresh_manager_test.cc b/test/extensions/common/redis/cluster_refresh_manager_test.cc index 916a1457da312..ea07e16243847 100644 --- a/test/extensions/common/redis/cluster_refresh_manager_test.cc +++ b/test/extensions/common/redis/cluster_refresh_manager_test.cc @@ -33,8 +33,8 @@ class ClusterRefreshManagerTest : public testing::Test { : cluster_name_("fake_cluster"), refresh_manager_(std::make_shared( dispatcher_, cm_, time_system_)) { time_system_.setMonotonicTime(std::chrono::seconds(1)); - map_.emplace("fake_cluster", mock_cluster_); - ON_CALL(cm_, clusters()).WillByDefault(Return(map_)); + cluster_maps_.active_clusters_.emplace("fake_cluster", mock_cluster_); + ON_CALL(cm_, clusters()).WillByDefault(Return(cluster_maps_)); } ~ClusterRefreshManagerTest() override = default; @@ -104,7 +104,7 @@ class ClusterRefreshManagerTest : public testing::Test { const std::string cluster_name_; NiceMock dispatcher_; NiceMock cm_; - Upstream::ClusterManager::ClusterInfoMap map_; + Upstream::ClusterManager::ClusterInfoMaps cluster_maps_; Upstream::MockClusterMockPrioritySet mock_cluster_; Event::SimulatedTimeSystem time_system_; std::shared_ptr refresh_manager_; diff --git a/test/extensions/common/wasm/BUILD b/test/extensions/common/wasm/BUILD index 4e586cb7902f3..b26be4cdb7e51 100644 --- a/test/extensions/common/wasm/BUILD +++ b/test/extensions/common/wasm/BUILD @@ -2,6 +2,7 @@ load( "//bazel:envoy_build_system.bzl", "envoy_cc_test", "envoy_cc_test_binary", + "envoy_cc_test_library", "envoy_package", ) load( @@ -21,6 +22,7 @@ envoy_cc_test( ]), deps = [ "//source/extensions/common/wasm:wasm_lib", + "//test/extensions/common/wasm:wasm_runtime", "//test/test_common:environment_lib", "//test/test_common:registry_lib", "//test/test_common:utility_lib", @@ -44,6 +46,7 @@ envoy_cc_test( "//source/common/stats:stats_lib", "//source/extensions/common/crypto:utility_lib", "//source/extensions/common/wasm:wasm_lib", + "//test/extensions/common/wasm:wasm_runtime", "//test/extensions/common/wasm/test_data:test_context_cpp_plugin", "//test/extensions/common/wasm/test_data:test_cpp_plugin", "//test/mocks/server:server_mocks", @@ -63,8 +66,21 @@ envoy_cc_test_binary( deps = [ "//source/common/event:dispatcher_lib", "//source/extensions/common/wasm:wasm_lib", + "//test/extensions/common/wasm:wasm_runtime", "//test/mocks/server:server_mocks", "//test/mocks/upstream:upstream_mocks", "//test/test_common:environment_lib", ], ) + +envoy_cc_test_library( + name = "wasm_runtime", + srcs = ["wasm_runtime.cc"], + hdrs = ["wasm_runtime.h"], + deps = [ + "//source/extensions/wasm_runtime/null:config", + "//source/extensions/wasm_runtime/v8:config", + "//source/extensions/wasm_runtime/wasmtime:config", + "//source/extensions/wasm_runtime/wavm:config", + ], +) diff --git a/test/extensions/common/wasm/wasm_runtime.cc b/test/extensions/common/wasm/wasm_runtime.cc new file mode 100644 index 0000000000000..a8451c70df642 --- /dev/null +++ b/test/extensions/common/wasm/wasm_runtime.cc @@ -0,0 +1,41 @@ +#include "test/extensions/common/wasm/wasm_runtime.h" + +namespace Envoy { +namespace Extensions { +namespace Common { +namespace Wasm { + +std::vector runtimes() { + std::vector runtimes = sandboxRuntimes(); + runtimes.push_back("null"); + return runtimes; +} + +std::vector sandboxRuntimes() { + std::vector runtimes; +#if defined(ENVOY_WASM_V8) + runtimes.push_back("v8"); +#endif +#if defined(ENVOY_WASM_WAVM) + runtimes.push_back("wavm"); +#endif +#if defined(ENVOY_WASM_WASMTIME) + runtimes.push_back("wasmtime"); +#endif + return runtimes; +} + +std::vector> runtimesAndLanguages() { + std::vector> values; + for (const auto& runtime : sandboxRuntimes()) { + values.push_back(std::make_tuple(runtime, "cpp")); + values.push_back(std::make_tuple(runtime, "rust")); + } + values.push_back(std::make_tuple("null", "cpp")); + return values; +} + +} // namespace Wasm +} // namespace Common +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/common/wasm/wasm_runtime.h b/test/extensions/common/wasm/wasm_runtime.h new file mode 100644 index 0000000000000..ef248d85310b2 --- /dev/null +++ b/test/extensions/common/wasm/wasm_runtime.h @@ -0,0 +1,26 @@ +#pragma once + +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace Common { +namespace Wasm { + +// All WASM runtimes. +std::vector runtimes(); + +// All sandboxed WASM runtimes. +std::vector sandboxRuntimes(); + +// Testable runtime and language combinations +std::vector> runtimesAndLanguages(); + +inline auto runtime_values = testing::ValuesIn(runtimes()); +inline auto sandbox_runtime_values = testing::ValuesIn(sandboxRuntimes()); +inline auto runtime_and_language_values = testing::ValuesIn(runtimesAndLanguages()); + +} // namespace Wasm +} // namespace Common +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/common/wasm/wasm_test.cc b/test/extensions/common/wasm/wasm_test.cc index 6d903abdbec29..cd56089daf5f6 100644 --- a/test/extensions/common/wasm/wasm_test.cc +++ b/test/extensions/common/wasm/wasm_test.cc @@ -6,6 +6,7 @@ #include "extensions/common/wasm/wasm.h" +#include "test/extensions/common/wasm/wasm_runtime.h" #include "test/mocks/server/mocks.h" #include "test/mocks/stats/mocks.h" #include "test/mocks/upstream/mocks.h" @@ -89,20 +90,7 @@ class WasmCommonTest : public testing::TestWithParam { } }; -// NB: this is required by VC++ which can not handle the use of macros in the macro definitions -// used by INSTANTIATE_TEST_SUITE_P. -auto test_values = testing::Values( -#if defined(ENVOY_WASM_V8) - "v8", -#endif -#if defined(ENVOY_WASM_WAVM) - "wavm", -#endif -#if defined(ENVOY_WASM_WASMTIME) - "wasmtime", -#endif - "null"); -INSTANTIATE_TEST_SUITE_P(Runtimes, WasmCommonTest, test_values); +INSTANTIATE_TEST_SUITE_P(Runtimes, WasmCommonTest, Envoy::Extensions::Common::Wasm::runtime_values); TEST_P(WasmCommonTest, EnvoyWasm) { auto envoy_wasm = std::make_unique(); @@ -969,7 +957,8 @@ class WasmCommonContextTest std::unique_ptr context_; }; -INSTANTIATE_TEST_SUITE_P(Runtimes, WasmCommonContextTest, test_values); +INSTANTIATE_TEST_SUITE_P(Runtimes, WasmCommonContextTest, + Envoy::Extensions::Common::Wasm::runtime_values); TEST_P(WasmCommonContextTest, OnDnsResolve) { std::string code; diff --git a/test/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter_test.cc b/test/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter_test.cc index 1ec37be541b42..8082a846db893 100644 --- a/test/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter_test.cc +++ b/test/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter_test.cc @@ -1270,6 +1270,78 @@ INSTANTIATE_TEST_SUITE_P( })", R"({"id":"101","gender":"MALE","last_name":"Shakespeare"})"})); +struct GrpcJsonTranscoderFilterUnescapeTestParam { + std::string config_json_; + std::string expected_arg_; +}; + +class GrpcJsonTranscoderFilterUnescapeTest + : public testing::TestWithParam, + public GrpcJsonTranscoderFilterTestBase { +protected: + GrpcJsonTranscoderFilterUnescapeTest() { + envoy::extensions::filters::http::grpc_json_transcoder::v3::GrpcJsonTranscoder proto_config; + TestUtility::loadFromJson(TestEnvironment::substitute(GetParam().config_json_), proto_config); + config_ = std::make_unique(proto_config, *api_); + filter_ = std::make_unique(*config_); + filter_->setDecoderFilterCallbacks(decoder_callbacks_); + filter_->setEncoderFilterCallbacks(encoder_callbacks_); + } + + std::unique_ptr config_; + std::unique_ptr filter_; + NiceMock decoder_callbacks_; + NiceMock encoder_callbacks_; +}; + +TEST_P(GrpcJsonTranscoderFilterUnescapeTest, UnescapeSpec) { + Http::TestRequestHeaderMapImpl request_headers{ + {"content-type", "text/plain"}, {":method", "POST"}, {":path", "/wildcard/%2f%23/%20%2523"}}; + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, false)); + + Buffer::OwnedImpl request_data{"{}"}; + EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(request_data, true)); + + Grpc::Decoder decoder; + std::vector frames; + decoder.decode(request_data, frames); + + EXPECT_EQ(1, frames.size()); + + bookstore::EchoBodyRequest expected_request; + expected_request.set_arg(GetParam().expected_arg_); + + bookstore::EchoBodyRequest request; + request.ParseFromString(frames[0].data_->toString()); + + EXPECT_EQ(expected_request.ByteSize(), frames[0].length_); + EXPECT_TRUE(MessageDifferencer::Equals(expected_request, request)); +} + +INSTANTIATE_TEST_SUITE_P(GrpcJsonTranscoderFilterUnescapeOptions, + GrpcJsonTranscoderFilterUnescapeTest, + ::testing::Values( + GrpcJsonTranscoderFilterUnescapeTestParam{ + R"({ + "proto_descriptor": "{{ test_rundir }}/test/proto/bookstore.descriptor", + "services": ["bookstore.Bookstore"] + })", + "%2f%23/ %23"}, + GrpcJsonTranscoderFilterUnescapeTestParam{ + R"({ + "proto_descriptor": "{{ test_rundir }}/test/proto/bookstore.descriptor", + "services": ["bookstore.Bookstore"], + "url_unescape_spec": "ALL_CHARACTERS_EXCEPT_SLASH" + })", + "%2f#/ %23"}, + GrpcJsonTranscoderFilterUnescapeTestParam{ + R"({ + "proto_descriptor": "{{ test_rundir }}/test/proto/bookstore.descriptor", + "services": ["bookstore.Bookstore"], + "url_unescape_spec": "ALL_CHARACTERS" + })", + "/#/ %23"})); + } // namespace } // namespace GrpcJsonTranscoder } // namespace HttpFilters diff --git a/test/extensions/filters/http/jwt_authn/authenticator_test.cc b/test/extensions/filters/http/jwt_authn/authenticator_test.cc index e9ceb23cbbbdd..fbb732a632983 100644 --- a/test/extensions/filters/http/jwt_authn/authenticator_test.cc +++ b/test/extensions/filters/http/jwt_authn/authenticator_test.cc @@ -303,6 +303,23 @@ TEST_F(AuthenticatorTest, TestExpiredJWT) { expectVerifyStatus(Status::JwtExpired, headers); } +// This test verifies when a JWT is expired but with a big clock skew. +TEST_F(AuthenticatorTest, TestExpiredJWTWithABigClockSkew) { + auto& provider = (*proto_config_.mutable_providers())[std::string(ProviderName)]; + // Token is expired at 1205005587, but add clock skew at another 1205005587. + provider.set_clock_skew_seconds(1205005587); + createAuthenticator(); + + EXPECT_CALL(*raw_fetcher_, fetch(_, _, _)) + .WillOnce(Invoke([this](const envoy::config::core::v3::HttpUri&, Tracing::Span&, + JwksFetcher::JwksReceiver& receiver) { + receiver.onJwksSuccess(std::move(jwks_)); + })); + + Http::TestRequestHeaderMapImpl headers{{"Authorization", "Bearer " + std::string(ExpiredToken)}}; + expectVerifyStatus(Status::Ok, headers); +} + // This test verifies when a JWT is not yet valid, JwtNotYetValid status is returned. TEST_F(AuthenticatorTest, TestNotYetValidJWT) { EXPECT_CALL(*raw_fetcher_, fetch(_, _, _)).Times(0); diff --git a/test/extensions/filters/http/kill_request/BUILD b/test/extensions/filters/http/kill_request/BUILD new file mode 100644 index 0000000000000..31d3857c26ae2 --- /dev/null +++ b/test/extensions/filters/http/kill_request/BUILD @@ -0,0 +1,49 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_package", +) +load( + "//test/extensions:extensions_build_system.bzl", + "envoy_extension_cc_test", +) + +licenses(["notice"]) # Apache 2 + +envoy_package() + +envoy_extension_cc_test( + name = "kill_request_filter_test", + srcs = ["kill_request_filter_test.cc"], + extension_name = "envoy.filters.http.kill_request", + deps = [ + "//include/envoy/http:metadata_interface", + "//source/common/buffer:buffer_lib", + "//source/extensions/filters/http/kill_request:kill_request_filter_lib", + "//test/mocks:common_lib", + "//test/test_common:utility_lib", + "@envoy_api//envoy/extensions/filters/http/kill_request/v3:pkg_cc_proto", + "@envoy_api//envoy/type/v3:pkg_cc_proto", + ], +) + +envoy_extension_cc_test( + name = "kill_request_config_test", + srcs = ["kill_request_config_test.cc"], + extension_name = "envoy.filters.http.kill_request", + deps = [ + "//source/extensions/filters/http/kill_request:kill_request_config", + "//test/mocks/server:factory_context_mocks", + "@envoy_api//envoy/extensions/filters/http/kill_request/v3:pkg_cc_proto", + "@envoy_api//envoy/type/v3:pkg_cc_proto", + ], +) + +envoy_extension_cc_test( + name = "kill_request_filter_integration_test", + srcs = ["kill_request_filter_integration_test.cc"], + extension_name = "envoy.filters.http.kill_request", + deps = [ + "//source/extensions/filters/http/kill_request:kill_request_config", + "//test/integration:http_protocol_integration_lib", + ], +) diff --git a/test/extensions/filters/http/kill_request/kill_request_config_test.cc b/test/extensions/filters/http/kill_request/kill_request_config_test.cc new file mode 100644 index 0000000000000..a803ae45a3473 --- /dev/null +++ b/test/extensions/filters/http/kill_request/kill_request_config_test.cc @@ -0,0 +1,46 @@ +#include "envoy/extensions/filters/http/kill_request/v3/kill_request.pb.h" +#include "envoy/extensions/filters/http/kill_request/v3/kill_request.pb.validate.h" +#include "envoy/type/v3/percent.pb.h" + +#include "extensions/filters/http/kill_request/kill_request_config.h" + +#include "test/mocks/server/factory_context.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace KillRequest { +namespace { + +using testing::_; + +TEST(KillRequestConfigTest, KillRequestFilterWithCorrectProto) { + envoy::extensions::filters::http::kill_request::v3::KillRequest kill_request; + kill_request.mutable_probability()->set_numerator(100); + + NiceMock context; + KillRequestFilterFactory factory; + Http::FilterFactoryCb cb = factory.createFilterFactoryFromProto(kill_request, "stats", context); + Http::MockFilterChainFactoryCallbacks filter_callback; + EXPECT_CALL(filter_callback, addStreamFilter(_)); + cb(filter_callback); +} + +TEST(KillRequestConfigTest, KillRequestFilterWithEmptyProto) { + NiceMock context; + KillRequestFilterFactory factory; + Http::FilterFactoryCb cb = + factory.createFilterFactoryFromProto(*factory.createEmptyConfigProto(), "stats", context); + Http::MockFilterChainFactoryCallbacks filter_callback; + EXPECT_CALL(filter_callback, addStreamFilter(_)); + cb(filter_callback); +} + +} // namespace +} // namespace KillRequest +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/filters/http/kill_request/kill_request_filter_integration_test.cc b/test/extensions/filters/http/kill_request/kill_request_filter_integration_test.cc new file mode 100644 index 0000000000000..35b011a858b5e --- /dev/null +++ b/test/extensions/filters/http/kill_request/kill_request_filter_integration_test.cc @@ -0,0 +1,95 @@ +#include "test/integration/http_protocol_integration.h" + +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace KillRequest { +namespace { + +class KillRequestFilterIntegrationTest : public Event::TestUsingSimulatedTime, + public HttpProtocolIntegrationTest { +protected: + void initializeFilter(const std::string& filter_config) { + config_helper_.addFilter(filter_config); + initialize(); + } + + const std::string filter_config_ = + R"EOF( +name: envoy.filters.http.kill_request +typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.kill_request.v3.KillRequest + probability: + numerator: 100 +)EOF"; +}; + +// Tests should run with all protocols. +class KillRequestFilterIntegrationTestAllProtocols : public KillRequestFilterIntegrationTest {}; +INSTANTIATE_TEST_SUITE_P(Protocols, KillRequestFilterIntegrationTestAllProtocols, + testing::ValuesIn(HttpProtocolIntegrationTest::getProtocolTestParams()), + HttpProtocolIntegrationTest::protocolTestParamsToString); + +// Request abort controlled via header configuration. +TEST_P(KillRequestFilterIntegrationTestAllProtocols, KillRequestCrashEnvoy) { + initializeFilter(filter_config_); + codec_client_ = makeHttpConnection(makeClientConnection(lookupPort("http"))); + Http::TestRequestHeaderMapImpl request_headers{{":method", "GET"}, + {":path", "/test/long/url"}, + {":scheme", "http"}, + {":authority", "host"}, + {"x-envoy-kill-request", "true"}}; + + EXPECT_DEATH(sendRequestAndWaitForResponse(request_headers, 0, default_response_headers_, 1024), + ""); +} + +TEST_P(KillRequestFilterIntegrationTestAllProtocols, KillRequestDisabledWhenHeaderIsMissing) { + initializeFilter(filter_config_); + codec_client_ = makeHttpConnection(makeClientConnection(lookupPort("http"))); + auto response = + sendRequestAndWaitForResponse(default_request_headers_, 0, default_response_headers_, 1024); +} + +TEST_P(KillRequestFilterIntegrationTestAllProtocols, KillRequestDisabledWhenHeaderValueIsInvalid) { + initializeFilter(filter_config_); + codec_client_ = makeHttpConnection(makeClientConnection(lookupPort("http"))); + Http::TestRequestHeaderMapImpl request_headers{{":method", "GET"}, + {":path", "/test/long/url"}, + {":scheme", "http"}, + {":authority", "host"}, + {"x-envoy-kill-request", "invalid"}}; + + auto response = + sendRequestAndWaitForResponse(request_headers, 0, default_response_headers_, 1024); +} + +TEST_P(KillRequestFilterIntegrationTestAllProtocols, KillRequestDisabledByZeroProbability) { + const std::string zero_probability_filter_config = + R"EOF( +name: envoy.filters.http.kill_request +typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.kill_request.v3.KillRequest + probability: + numerator: 0 +)EOF"; + + initializeFilter(zero_probability_filter_config); + codec_client_ = makeHttpConnection(makeClientConnection(lookupPort("http"))); + Http::TestRequestHeaderMapImpl request_headers{{":method", "GET"}, + {":path", "/test/long/url"}, + {":scheme", "http"}, + {":authority", "host"}, + {"x-envoy-kill-request", "true"}}; + + auto response = + sendRequestAndWaitForResponse(request_headers, 0, default_response_headers_, 1024); +} + +} // namespace +} // namespace KillRequest +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/filters/http/kill_request/kill_request_filter_test.cc b/test/extensions/filters/http/kill_request/kill_request_filter_test.cc new file mode 100644 index 0000000000000..ff101f241c0fb --- /dev/null +++ b/test/extensions/filters/http/kill_request/kill_request_filter_test.cc @@ -0,0 +1,125 @@ +#include "envoy/extensions/filters/http/kill_request/v3/kill_request.pb.h" +#include "envoy/http/metadata_interface.h" +#include "envoy/type/v3/percent.pb.h" + +#include "common/buffer/buffer_impl.h" + +#include "extensions/filters/http/kill_request/kill_request_filter.h" + +#include "test/mocks/common.h" +#include "test/test_common/utility.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace KillRequest { +namespace { + +using ::testing::Return; + +class KillRequestFilterTest : public testing::Test { +protected: + void + setUpTest(const envoy::extensions::filters::http::kill_request::v3::KillRequest& kill_request) { + filter_ = std::make_unique(kill_request, random_generator_); + } + + std::unique_ptr filter_; + testing::NiceMock random_generator_; + Http::TestRequestHeaderMapImpl request_headers_; +}; + +TEST_F(KillRequestFilterTest, KillRequestCrashEnvoy) { + envoy::extensions::filters::http::kill_request::v3::KillRequest kill_request; + kill_request.mutable_probability()->set_numerator(1); + setUpTest(kill_request); + request_headers_.addCopy("x-envoy-kill-request", "true"); + + ON_CALL(random_generator_, random()).WillByDefault(Return(0)); + EXPECT_DEATH(filter_->decodeHeaders(request_headers_, false), ""); +} + +TEST_F(KillRequestFilterTest, KillRequestWithMillionDenominatorCrashEnvoy) { + envoy::extensions::filters::http::kill_request::v3::KillRequest kill_request; + kill_request.mutable_probability()->set_numerator(1); + kill_request.mutable_probability()->set_denominator(envoy::type::v3::FractionalPercent::MILLION); + setUpTest(kill_request); + request_headers_.addCopy("x-envoy-kill-request", "yes"); + + ON_CALL(random_generator_, random()).WillByDefault(Return(0)); + EXPECT_DEATH(filter_->decodeHeaders(request_headers_, false), ""); +} + +TEST_F(KillRequestFilterTest, KillRequestDisabledWhenIsKillRequestEnabledReturnsFalse) { + envoy::extensions::filters::http::kill_request::v3::KillRequest kill_request; + kill_request.mutable_probability()->set_numerator(0); + setUpTest(kill_request); + request_headers_.addCopy("x-envoy-kill-request", "true"); + + ON_CALL(random_generator_, random()).WillByDefault(Return(1)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers_, false)); +} + +TEST_F(KillRequestFilterTest, KillRequestDisabledWhenHeaderIsMissing) { + envoy::extensions::filters::http::kill_request::v3::KillRequest kill_request; + kill_request.mutable_probability()->set_numerator(100); + setUpTest(kill_request); + + ON_CALL(random_generator_, random()).WillByDefault(Return(0)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers_, false)); +} + +TEST_F(KillRequestFilterTest, KillRequestDisabledWhenHeaderValueIsInvalid) { + envoy::extensions::filters::http::kill_request::v3::KillRequest kill_request; + kill_request.mutable_probability()->set_numerator(100); + setUpTest(kill_request); + request_headers_.addCopy("x-envoy-kill-request", "invalid"); + + ON_CALL(random_generator_, random()).WillByDefault(Return(0)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers_, false)); +} + +TEST_F(KillRequestFilterTest, DecodeDataReturnsContinue) { + envoy::extensions::filters::http::kill_request::v3::KillRequest kill_request; + setUpTest(kill_request); + Buffer::OwnedImpl data; + EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data, false)); +} + +TEST_F(KillRequestFilterTest, DecodeTrailersReturnsContinue) { + envoy::extensions::filters::http::kill_request::v3::KillRequest kill_request; + setUpTest(kill_request); + Http::TestRequestTrailerMapImpl request_trailers; + EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(request_trailers)); +} + +TEST_F(KillRequestFilterTest, Encode100ContinueHeadersReturnsContinue) { + envoy::extensions::filters::http::kill_request::v3::KillRequest kill_request; + setUpTest(kill_request); + Http::TestResponseHeaderMapImpl response_headers; + EXPECT_EQ(Http::FilterHeadersStatus::Continue, + filter_->encode100ContinueHeaders(response_headers)); +} + +TEST_F(KillRequestFilterTest, EncodeTrailersReturnsContinue) { + envoy::extensions::filters::http::kill_request::v3::KillRequest kill_request; + setUpTest(kill_request); + Http::TestResponseTrailerMapImpl response_trailers; + EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->encodeTrailers(response_trailers)); +} + +TEST_F(KillRequestFilterTest, EncodeMetadataReturnsContinue) { + envoy::extensions::filters::http::kill_request::v3::KillRequest kill_request; + setUpTest(kill_request); + Http::MetadataMap metadata_map; + EXPECT_EQ(Http::FilterMetadataStatus::Continue, filter_->encodeMetadata(metadata_map)); +} + +} // namespace +} // namespace KillRequest +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/filters/http/lua/lua_filter_test.cc b/test/extensions/filters/http/lua/lua_filter_test.cc index 310bafc36b399..d07420f4d8e4f 100644 --- a/test/extensions/filters/http/lua/lua_filter_test.cc +++ b/test/extensions/filters/http/lua/lua_filter_test.cc @@ -1884,7 +1884,7 @@ TEST_F(LuaHttpFilterTest, InspectStreamInfoDowstreamSslConnection) { Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}}; - auto connection_info = std::make_shared(); + const auto connection_info = std::make_shared(); EXPECT_CALL(decoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(stream_info_)); EXPECT_CALL(stream_info_, downstreamSslConnection()).WillRepeatedly(Return(connection_info)); @@ -1992,6 +1992,35 @@ TEST_F(LuaHttpFilterTest, InspectStreamInfoDowstreamSslConnectionOnPlainConnecti EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); } +// Should survive from multiple streamInfo():downstreamSslConnection() calls. +// This is a regression test for #14091. +TEST_F(LuaHttpFilterTest, SurviveMultipleDownstreamSslConnectionCalls) { + const std::string SCRIPT{R"EOF( + function envoy_on_request(request_handle) + if request_handle:streamInfo():downstreamSslConnection() ~= nil then + request_handle:logTrace("downstreamSslConnection is present") + end + end + )EOF"}; + + setup(SCRIPT); + + const auto connection_info = std::make_shared(); + EXPECT_CALL(decoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(stream_info_)); + EXPECT_CALL(stream_info_, downstreamSslConnection()).WillRepeatedly(Return(connection_info)); + + for (uint64_t i = 0; i < 200; i++) { + EXPECT_CALL(*filter_, + scriptLog(spdlog::level::trace, StrEq("downstreamSslConnection is present"))); + + Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}}; + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + + filter_->onDestroy(); + setupFilter(); + } +} + TEST_F(LuaHttpFilterTest, ImportPublicKey) { const std::string SCRIPT{R"EOF( function string.fromhex(str) diff --git a/test/extensions/filters/http/oauth2/oauth_integration_test.cc b/test/extensions/filters/http/oauth2/oauth_integration_test.cc index 0788c5d2b3b9a..f1ec679be0915 100644 --- a/test/extensions/filters/http/oauth2/oauth_integration_test.cc +++ b/test/extensions/filters/http/oauth2/oauth_integration_test.cc @@ -91,8 +91,6 @@ TEST_F(OauthIntegrationTest, UnauthenticatedFlow) { {":authority", "authority"}}; auto encoder_decoder = codec_client_->startRequest(headers); - Buffer::OwnedImpl buffer; - encoder_decoder.first.encodeData(buffer, true); request_encoder_ = &encoder_decoder.first; auto response = std::move(encoder_decoder.second); @@ -144,4 +142,4 @@ TEST_F(OauthIntegrationTest, AuthenticationFlow) { } // namespace Oauth } // namespace HttpFilters } // namespace Extensions -} // namespace Envoy \ No newline at end of file +} // namespace Envoy diff --git a/test/extensions/filters/http/wasm/BUILD b/test/extensions/filters/http/wasm/BUILD index f8392be38a7a9..055529c224ce7 100644 --- a/test/extensions/filters/http/wasm/BUILD +++ b/test/extensions/filters/http/wasm/BUILD @@ -34,6 +34,7 @@ envoy_extension_cc_test( deps = [ "//source/common/http:message_lib", "//source/extensions/filters/http/wasm:wasm_filter_lib", + "//test/extensions/common/wasm:wasm_runtime", "//test/extensions/filters/http/wasm/test_data:test_cpp_plugin", "//test/mocks/network:connection_mocks", "//test/mocks/router:router_mocks", @@ -58,6 +59,7 @@ envoy_extension_cc_test( "//source/extensions/common/crypto:utility_lib", "//source/extensions/common/wasm:wasm_lib", "//source/extensions/filters/http/wasm:config", + "//test/extensions/common/wasm:wasm_runtime", "//test/mocks/server:server_mocks", "//test/test_common:environment_lib", "@envoy_api//envoy/extensions/filters/http/wasm/v3:pkg_cc_proto", diff --git a/test/extensions/filters/http/wasm/config_test.cc b/test/extensions/filters/http/wasm/config_test.cc index 552aa61a9387a..5d5d92afb6b58 100644 --- a/test/extensions/filters/http/wasm/config_test.cc +++ b/test/extensions/filters/http/wasm/config_test.cc @@ -11,6 +11,7 @@ #include "extensions/common/wasm/wasm.h" #include "extensions/filters/http/wasm/config.h" +#include "test/extensions/common/wasm/wasm_runtime.h" #include "test/mocks/http/mocks.h" #include "test/mocks/server/mocks.h" #include "test/test_common/environment.h" @@ -29,7 +30,6 @@ using Common::Wasm::WasmException; namespace HttpFilters { namespace Wasm { -#if defined(ENVOY_WASM_V8) || defined(ENVOY_WASM_WAVM) || defined(ENVOY_WASM_WASMTIME) class WasmFilterConfigTest : public Event::TestUsingSimulatedTime, public testing::TestWithParam { protected: @@ -65,27 +65,9 @@ class WasmFilterConfigTest : public Event::TestUsingSimulatedTime, Event::TimerCb retry_timer_cb_; }; -// NB: this is required by VC++ which can not handle the use of macros in the macro definitions -// used by INSTANTIATE_TEST_SUITE_P. -auto testing_values = testing::Values( -#if defined(ENVOY_WASM_V8) - "v8" -#endif -#if defined(ENVOY_WASM_V8) && (defined(ENVOY_WASM_WAVM) || defined(ENVOY_WASM_WASMTIME)) - , -#endif -#if defined(ENVOY_WASM_WAVM) - "wavm" -#endif -#if (defined(ENVOY_WASM_V8) || defined(ENVOY_WASM_WAVM)) && defined(ENVOY_WASM_WASMTIME) - , -#endif -#if defined(ENVOY_WASM_WASMTIME) - "wasmtime" -#endif -); - -INSTANTIATE_TEST_SUITE_P(Runtimes, WasmFilterConfigTest, testing_values); +INSTANTIATE_TEST_SUITE_P(Runtimes, WasmFilterConfigTest, + Envoy::Extensions::Common::Wasm::sandbox_runtime_values); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WasmFilterConfigTest); TEST_P(WasmFilterConfigTest, JsonLoadFromFileWasm) { const std::string json = TestEnvironment::substitute(absl::StrCat(R"EOF( @@ -832,7 +814,6 @@ TEST_P(WasmFilterConfigTest, YamlLoadFromRemoteSuccessBadcodeFailOpen) { // The filter is not registered. cb(filter_callback); } -#endif } // namespace Wasm } // namespace HttpFilters diff --git a/test/extensions/filters/http/wasm/wasm_filter_test.cc b/test/extensions/filters/http/wasm/wasm_filter_test.cc index 9999d453c75f6..fddde58db40bf 100644 --- a/test/extensions/filters/http/wasm/wasm_filter_test.cc +++ b/test/extensions/filters/http/wasm/wasm_filter_test.cc @@ -2,6 +2,7 @@ #include "extensions/filters/http/wasm/wasm_filter.h" +#include "test/extensions/common/wasm/wasm_runtime.h" #include "test/mocks/network/connection.h" #include "test/mocks/router/mocks.h" #include "test/test_common/wasm_base.h" @@ -95,20 +96,8 @@ class WasmHttpFilterTest : public Common::Wasm::WasmHttpFilterTestBase< Grpc::MockAsyncClientManager async_client_manager_; }; -// NB: this is required by VC++ which can not handle the use of macros in the macro definitions -// used by INSTANTIATE_TEST_SUITE_P. -auto testing_values = testing::Values( -#if defined(ENVOY_WASM_V8) - std::make_tuple("v8", "cpp"), std::make_tuple("v8", "rust"), -#endif -#if defined(ENVOY_WASM_WAVM) - std::make_tuple("wavm", "cpp"), std::make_tuple("wavm", "rust"), -#endif -#if defined(ENVOY_WASM_WASMTIME) - std::make_tuple("wasmtime", "cpp"), std::make_tuple("wasmtime", "rust"), -#endif - std::make_tuple("null", "cpp")); -INSTANTIATE_TEST_SUITE_P(RuntimesAndLanguages, WasmHttpFilterTest, testing_values); +INSTANTIATE_TEST_SUITE_P(RuntimesAndLanguages, WasmHttpFilterTest, + Envoy::Extensions::Common::Wasm::runtime_and_language_values); // Bad code in initial config. TEST_P(WasmHttpFilterTest, BadCode) { @@ -1263,9 +1252,11 @@ TEST_P(WasmHttpFilterTest, GrpcStreamOpenAtShutdown) { } // Test metadata access including CEL expressions. -// TODO: re-enable this on Windows if and when the CEL `Antlr` parser compiles on Windows. -#if defined(ENVOY_WASM_V8) || defined(ENVOY_WASM_WAVM) || defined(ENVOY_WASM_WASMTIME) TEST_P(WasmHttpFilterTest, Metadata) { +#ifdef WIN32 + // TODO: re-enable this on Windows if and when the CEL `Antlr` parser compiles on Windows. + GTEST_SKIP() << "Skipping on Windows"; +#endif setupTest("", "metadata"); setupFilter(); envoy::config::core::v3::Node node_data; @@ -1319,7 +1310,6 @@ TEST_P(WasmHttpFilterTest, Metadata) { filter().onDestroy(); filter().onDestroy(); // Does nothing. } -#endif TEST_P(WasmHttpFilterTest, Property) { if (std::get<1>(GetParam()) == "rust") { diff --git a/test/extensions/filters/listener/tls_inspector/tls_inspector_benchmark.cc b/test/extensions/filters/listener/tls_inspector/tls_inspector_benchmark.cc index 5bed094fc34c8..00f1e37aa50c8 100644 --- a/test/extensions/filters/listener/tls_inspector/tls_inspector_benchmark.cc +++ b/test/extensions/filters/listener/tls_inspector/tls_inspector_benchmark.cc @@ -41,6 +41,8 @@ class FastMockListenerFilterCallbacks : public Network::MockListenerFilterCallba class FastMockFileEvent : public Event::FileEvent { void activate(uint32_t) override {} void setEnabled(uint32_t) override {} + void unregisterEventIfEmulatedEdge(uint32_t) override {} + void registerEventIfEmulatedEdge(uint32_t) override {} }; class FastMockDispatcher : public Event::MockDispatcher { diff --git a/test/extensions/filters/network/mongo_proxy/proxy_test.cc b/test/extensions/filters/network/mongo_proxy/proxy_test.cc index 5b20f6cd51064..c43ebe8ca8972 100644 --- a/test/extensions/filters/network/mongo_proxy/proxy_test.cc +++ b/test/extensions/filters/network/mongo_proxy/proxy_test.cc @@ -626,8 +626,8 @@ TEST_F(MongoProxyFilterTest, ConnectionDestroyLocal) { EXPECT_CALL(*delay_timer, disableTimer()); read_filter_callbacks_.connection_.raiseEvent(Network::ConnectionEvent::RemoteClose); - EXPECT_EQ(1U, store_.counter("test.cx_destroy_local_with_active_rq").value()); - EXPECT_EQ(0U, store_.counter("test.cx_destroy_remote_with_active_rq").value()); + EXPECT_EQ(0U, store_.counter("test.cx_destroy_local_with_active_rq").value()); + EXPECT_EQ(1U, store_.counter("test.cx_destroy_remote_with_active_rq").value()); } TEST_F(MongoProxyFilterTest, ConnectionDestroyRemote) { @@ -650,8 +650,8 @@ TEST_F(MongoProxyFilterTest, ConnectionDestroyRemote) { EXPECT_CALL(*delay_timer, disableTimer()); read_filter_callbacks_.connection_.raiseEvent(Network::ConnectionEvent::LocalClose); - EXPECT_EQ(1U, store_.counter("test.cx_destroy_remote_with_active_rq").value()); - EXPECT_EQ(0U, store_.counter("test.cx_destroy_local_with_active_rq").value()); + EXPECT_EQ(0U, store_.counter("test.cx_destroy_remote_with_active_rq").value()); + EXPECT_EQ(1U, store_.counter("test.cx_destroy_local_with_active_rq").value()); } } // namespace MongoProxy diff --git a/test/extensions/filters/network/postgres_proxy/postgres_decoder_test.cc b/test/extensions/filters/network/postgres_proxy/postgres_decoder_test.cc index e787a18f2d5bf..1643cc83d2fa9 100644 --- a/test/extensions/filters/network/postgres_proxy/postgres_decoder_test.cc +++ b/test/extensions/filters/network/postgres_proxy/postgres_decoder_test.cc @@ -523,6 +523,7 @@ class FakeBuffer : public Buffer::Instance { MOCK_METHOD(void, copyOut, (size_t, uint64_t, void*), (const, override)); MOCK_METHOD(void, drain, (uint64_t), (override)); MOCK_METHOD(Buffer::RawSliceVector, getRawSlices, (absl::optional), (const, override)); + MOCK_METHOD(Buffer::RawSlice, frontSlice, (), (const, override)); MOCK_METHOD(Buffer::SliceDataPtr, extractMutableFrontSlice, (), (override)); MOCK_METHOD(uint64_t, length, (), (const, override)); MOCK_METHOD(void*, linearize, (uint32_t), (override)); diff --git a/test/extensions/filters/network/wasm/BUILD b/test/extensions/filters/network/wasm/BUILD index d21eba6c08534..bfbd34124d5fa 100644 --- a/test/extensions/filters/network/wasm/BUILD +++ b/test/extensions/filters/network/wasm/BUILD @@ -29,6 +29,7 @@ envoy_extension_cc_test( "//source/extensions/common/crypto:utility_lib", "//source/extensions/common/wasm:wasm_lib", "//source/extensions/filters/network/wasm:config", + "//test/extensions/common/wasm:wasm_runtime", "//test/extensions/filters/network/wasm/test_data:test_cpp_plugin", "//test/mocks/server:server_mocks", "//test/test_common:environment_lib", @@ -46,6 +47,7 @@ envoy_extension_cc_test( extension_name = "envoy.filters.network.wasm", deps = [ "//source/extensions/filters/network/wasm:wasm_filter_lib", + "//test/extensions/common/wasm:wasm_runtime", "//test/extensions/filters/network/wasm/test_data:test_cpp_plugin", "//test/mocks/network:network_mocks", "//test/mocks/server:server_mocks", diff --git a/test/extensions/filters/network/wasm/config_test.cc b/test/extensions/filters/network/wasm/config_test.cc index 68541490a82ca..6d93a167f674a 100644 --- a/test/extensions/filters/network/wasm/config_test.cc +++ b/test/extensions/filters/network/wasm/config_test.cc @@ -8,6 +8,7 @@ #include "extensions/filters/network/wasm/config.h" #include "extensions/filters/network/wasm/wasm_filter.h" +#include "test/extensions/common/wasm/wasm_runtime.h" #include "test/mocks/server/mocks.h" #include "test/test_common/environment.h" @@ -56,20 +57,8 @@ class WasmNetworkFilterConfigTest : public testing::TestWithParam { Event::TimerCb retry_timer_cb_; }; -// NB: this is required by VC++ which can not handle the use of macros in the macro definitions -// used by INSTANTIATE_TEST_SUITE_P. -auto testing_values = testing::Values( -#if defined(ENVOY_WASM_V8) - "v8", -#endif -#if defined(ENVOY_WASM_WAVM) - "wavm", -#endif -#if defined(ENVOY_WASM_WASMTIME) - "wasmtime", -#endif - "null"); -INSTANTIATE_TEST_SUITE_P(Runtimes, WasmNetworkFilterConfigTest, testing_values); +INSTANTIATE_TEST_SUITE_P(Runtimes, WasmNetworkFilterConfigTest, + Envoy::Extensions::Common::Wasm::runtime_values); TEST_P(WasmNetworkFilterConfigTest, YamlLoadFromFileWasm) { if (GetParam() == "null") { diff --git a/test/extensions/filters/network/wasm/wasm_filter_test.cc b/test/extensions/filters/network/wasm/wasm_filter_test.cc index 517d37cee3b51..c9bd6e7f8348e 100644 --- a/test/extensions/filters/network/wasm/wasm_filter_test.cc +++ b/test/extensions/filters/network/wasm/wasm_filter_test.cc @@ -3,6 +3,7 @@ #include "extensions/common/wasm/wasm.h" #include "extensions/filters/network/wasm/wasm_filter.h" +#include "test/extensions/common/wasm/wasm_runtime.h" #include "test/mocks/network/mocks.h" #include "test/mocks/server/mocks.h" #include "test/test_common/wasm_base.h" @@ -82,20 +83,8 @@ class WasmNetworkFilterTest : public Common::Wasm::WasmNetworkFilterTestBase< std::string code_; }; -// NB: this is required by VC++ which can not handle the use of macros in the macro definitions -// used by INSTANTIATE_TEST_SUITE_P. -auto testing_values = testing::Values( -#if defined(ENVOY_WASM_V8) - std::make_tuple("v8", "cpp"), std::make_tuple("v8", "rust"), -#endif -#if defined(ENVOY_WASM_WAVM) - std::make_tuple("wavm", "cpp"), std::make_tuple("wavm", "rust"), -#endif -#if defined(ENVOY_WASM_WASMTIME) - std::make_tuple("wasmtime", "cpp"), std::make_tuple("wasmtime", "rust"), -#endif - std::make_tuple("null", "cpp")); -INSTANTIATE_TEST_SUITE_P(RuntimesAndLanguages, WasmNetworkFilterTest, testing_values); +INSTANTIATE_TEST_SUITE_P(RuntimesAndLanguages, WasmNetworkFilterTest, + Envoy::Extensions::Common::Wasm::runtime_and_language_values); // Bad code in initial config. TEST_P(WasmNetworkFilterTest, BadCode) { @@ -174,15 +163,11 @@ TEST_P(WasmNetworkFilterTest, CloseStream) { // Create context. EXPECT_CALL(filter(), log_(spdlog::level::trace, Eq(absl::string_view("onNewConnection 2")))); EXPECT_EQ(Network::FilterStatus::Continue, filter().onNewConnection()); - EXPECT_CALL(filter(), - log_(spdlog::level::trace, Eq(absl::string_view("onDownstreamConnectionClose 2 1")))); EXPECT_CALL(filter(), log_(spdlog::level::trace, Eq(absl::string_view("onDownstreamConnectionClose 2 2")))); filter().onEvent(static_cast(9999)); // Does nothing. filter().onEvent(Network::ConnectionEvent::RemoteClose); - filter().closeStream(proxy_wasm::WasmStreamType::Downstream); - filter().closeStream(proxy_wasm::WasmStreamType::Upstream); } TEST_P(WasmNetworkFilterTest, SegvFailOpen) { diff --git a/test/extensions/quic_listeners/quiche/BUILD b/test/extensions/quic_listeners/quiche/BUILD index 92aad3fe9a2e5..4375b705ca7de 100644 --- a/test/extensions/quic_listeners/quiche/BUILD +++ b/test/extensions/quic_listeners/quiche/BUILD @@ -84,6 +84,7 @@ envoy_cc_test( "//test/mocks/network:network_mocks", "//test/test_common:utility_lib", "@com_googlesource_quiche//:quic_core_http_spdy_session_lib", + "@com_googlesource_quiche//:quic_test_tools_qpack_qpack_test_utils_lib", "@com_googlesource_quiche//:quic_test_tools_session_peer_lib", ], ) @@ -105,6 +106,7 @@ envoy_cc_test( "//test/mocks/network:network_mocks", "//test/test_common:utility_lib", "@com_googlesource_quiche//:quic_core_http_spdy_session_lib", + "@com_googlesource_quiche//:quic_test_tools_qpack_qpack_test_utils_lib", ], ) @@ -290,5 +292,6 @@ envoy_cc_test_library( "//test/test_common:environment_lib", "@com_googlesource_quiche//:quic_core_http_spdy_session_lib", "@com_googlesource_quiche//:quic_test_tools_first_flight_lib", + "@com_googlesource_quiche//:quic_test_tools_qpack_qpack_encoder_test_utils_lib", ], ) diff --git a/test/extensions/quic_listeners/quiche/envoy_quic_client_session_test.cc b/test/extensions/quic_listeners/quiche/envoy_quic_client_session_test.cc index c95a61e5ace82..e03c6ab3ba64c 100644 --- a/test/extensions/quic_listeners/quiche/envoy_quic_client_session_test.cc +++ b/test/extensions/quic_listeners/quiche/envoy_quic_client_session_test.cc @@ -49,9 +49,9 @@ class TestEnvoyQuicClientConnection : public EnvoyQuicClientConnection { Network::ConnectionSocketPtr&& connection_socket) : EnvoyQuicClientConnection(server_connection_id, helper, alarm_factory, &writer, false, supported_versions, dispatcher, std::move(connection_socket)) { - SetDefaultEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); SetEncrypter(quic::ENCRYPTION_FORWARD_SECURE, std::make_unique(quic::Perspective::IS_CLIENT)); + SetDefaultEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); } MOCK_METHOD(void, SendConnectionClosePacket, (quic::QuicErrorCode, const std::string&)); diff --git a/test/extensions/quic_listeners/quiche/envoy_quic_client_stream_test.cc b/test/extensions/quic_listeners/quiche/envoy_quic_client_stream_test.cc index 7711b7c88bf0f..01871dcfff99d 100644 --- a/test/extensions/quic_listeners/quiche/envoy_quic_client_stream_test.cc +++ b/test/extensions/quic_listeners/quiche/envoy_quic_client_stream_test.cc @@ -48,11 +48,11 @@ class EnvoyQuicClientStreamTest : public testing::TestWithParam { quic_session_.ActivateStream(std::unique_ptr(quic_stream_)); EXPECT_CALL(quic_session_, ShouldYield(_)).WillRepeatedly(testing::Return(false)); EXPECT_CALL(quic_session_, WritevData(_, _, _, _, _, _)) - .WillRepeatedly(Invoke([](quic::QuicStreamId, size_t write_length, quic::QuicStreamOffset, - quic::StreamSendingState state, bool, - quiche::QuicheOptional) { - return quic::QuicConsumedData{write_length, state != quic::NO_FIN}; - })); + .WillRepeatedly( + Invoke([](quic::QuicStreamId, size_t write_length, quic::QuicStreamOffset, + quic::StreamSendingState state, bool, absl::optional) { + return quic::QuicConsumedData{write_length, state != quic::NO_FIN}; + })); EXPECT_CALL(writer_, WritePacket(_, _, _, _, _)) .WillRepeatedly(Invoke([](const char*, size_t buf_len, const quic::QuicIpAddress&, const quic::QuicSocketAddress&, quic::PerPacketOptions*) { @@ -69,6 +69,7 @@ class EnvoyQuicClientStreamTest : public testing::TestWithParam { response_headers_.OnHeader(":status", "200"); response_headers_.OnHeaderBlockEnd(/*uncompressed_header_bytes=*/0, /*compressed_header_bytes=*/0); + spdy_response_headers_[":status"] = "200"; trailers_.OnHeaderBlockStart(); trailers_.OnHeader("key1", "value1"); @@ -77,6 +78,7 @@ class EnvoyQuicClientStreamTest : public testing::TestWithParam { trailers_.OnHeader(":final-offset", absl::StrCat("", response_body_.length())); } trailers_.OnHeaderBlockEnd(/*uncompressed_header_bytes=*/0, /*compressed_header_bytes=*/0); + spdy_trailers_["key1"] = "value1"; } void TearDown() override { @@ -87,6 +89,41 @@ class EnvoyQuicClientStreamTest : public testing::TestWithParam { } } + std::string bodyToStreamPayload(const std::string& body) { + if (!quic::VersionUsesHttp3(quic_version_.transport_version)) { + return body; + } + return bodyToHttp3StreamPayload(body); + } + + size_t receiveResponse(const std::string& payload, bool fin) { + EXPECT_CALL(stream_decoder_, decodeHeaders_(_, /*end_stream=*/false)) + .WillOnce(Invoke([](const Http::ResponseHeaderMapPtr& headers, bool) { + EXPECT_EQ("200", headers->getStatusValue()); + })); + + EXPECT_CALL(stream_decoder_, decodeData(_, _)) + .WillOnce(Invoke([&](Buffer::Instance& buffer, bool finished_reading) { + EXPECT_EQ(payload, buffer.toString()); + EXPECT_EQ(fin, finished_reading); + })); + if (quic::VersionUsesHttp3(quic_version_.transport_version)) { + std::string data = absl::StrCat(spdyHeaderToHttp3StreamPayload(spdy_response_headers_), + bodyToStreamPayload(payload)); + quic::QuicStreamFrame frame(stream_id_, fin, 0, data); + quic_stream_->OnStreamFrame(frame); + EXPECT_TRUE(quic_stream_->FinishedReadingHeaders()); + return data.length(); + } + quic_stream_->OnStreamHeaderList(/*fin=*/false, response_headers_.uncompressed_header_bytes(), + response_headers_); + + quic::QuicStreamFrame frame(stream_id_, fin, 0, payload); + quic_stream_->OnStreamFrame(frame); + EXPECT_TRUE(quic_stream_->FinishedReadingHeaders()); + return payload.length(); + } + protected: Api::ApiPtr api_; Event::DispatcherPtr dispatcher_; @@ -107,7 +144,9 @@ class EnvoyQuicClientStreamTest : public testing::TestWithParam { Http::TestRequestHeaderMapImpl request_headers_; Http::TestRequestTrailerMapImpl request_trailers_; quic::QuicHeaderList response_headers_; + spdy::SpdyHeaderBlock spdy_response_headers_; quic::QuicHeaderList trailers_; + spdy::SpdyHeaderBlock spdy_trailers_; Buffer::OwnedImpl request_body_{"Hello world"}; std::string response_body_{"OK\n"}; }; @@ -115,44 +154,35 @@ class EnvoyQuicClientStreamTest : public testing::TestWithParam { INSTANTIATE_TEST_SUITE_P(EnvoyQuicClientStreamTests, EnvoyQuicClientStreamTest, testing::ValuesIn({true, false})); -TEST_P(EnvoyQuicClientStreamTest, PostRequestAndResponse) { - EXPECT_EQ(absl::nullopt, quic_stream_->http1StreamEncoderOptions()); - const auto result = quic_stream_->encodeHeaders(request_headers_, false); +TEST_P(EnvoyQuicClientStreamTest, GetRequestAndHeaderOnlyResponse) { + const auto result = quic_stream_->encodeHeaders(request_headers_, /*end_stream=*/true); EXPECT_TRUE(result.ok()); - quic_stream_->encodeData(request_body_, false); - quic_stream_->encodeTrailers(request_trailers_); - EXPECT_CALL(stream_decoder_, decodeHeaders_(_, /*end_stream=*/false)) + EXPECT_CALL(stream_decoder_, decodeHeaders_(_, /*end_stream=*/!quic::VersionUsesHttp3( + quic_version_.transport_version))) .WillOnce(Invoke([](const Http::ResponseHeaderMapPtr& headers, bool) { EXPECT_EQ("200", headers->getStatusValue()); })); - quic_stream_->OnStreamHeaderList(/*fin=*/false, response_headers_.uncompressed_header_bytes(), - response_headers_); - EXPECT_TRUE(quic_stream_->FinishedReadingHeaders()); - - EXPECT_CALL(stream_decoder_, decodeData(_, _)) - .Times(testing::AtMost(2)) - .WillOnce(Invoke([&](Buffer::Instance& buffer, bool finished_reading) { - EXPECT_EQ(response_body_, buffer.toString()); - EXPECT_FALSE(finished_reading); - })) - // Depends on QUIC version, there may be an empty STREAM_FRAME with FIN. But - // since there is trailers, finished_reading should always be false. - .WillOnce(Invoke([](Buffer::Instance& buffer, bool finished_reading) { - EXPECT_FALSE(finished_reading); - EXPECT_EQ(0, buffer.length()); - })); - std::string data = response_body_; if (quic::VersionUsesHttp3(quic_version_.transport_version)) { - std::unique_ptr data_buffer; - quic::QuicByteCount data_frame_header_length = - quic::HttpEncoder::SerializeDataFrameHeader(response_body_.length(), &data_buffer); - quiche::QuicheStringPiece data_frame_header(data_buffer.get(), data_frame_header_length); - data = absl::StrCat(data_frame_header, response_body_); + EXPECT_CALL(stream_decoder_, decodeData(BufferStringEqual(""), /*end_stream=*/true)); + std::string payload = spdyHeaderToHttp3StreamPayload(spdy_response_headers_); + quic::QuicStreamFrame frame(stream_id_, true, 0, payload); + quic_stream_->OnStreamFrame(frame); + } else { + quic_stream_->OnStreamHeaderList(/*fin=*/true, response_headers_.uncompressed_header_bytes(), + response_headers_); } - quic::QuicStreamFrame frame(stream_id_, false, 0, data); - quic_stream_->OnStreamFrame(frame); + EXPECT_TRUE(quic_stream_->FinishedReadingHeaders()); +} + +TEST_P(EnvoyQuicClientStreamTest, PostRequestAndResponse) { + EXPECT_EQ(absl::nullopt, quic_stream_->http1StreamEncoderOptions()); + const auto result = quic_stream_->encodeHeaders(request_headers_, false); + EXPECT_TRUE(result.ok()); + quic_stream_->encodeData(request_body_, false); + quic_stream_->encodeTrailers(request_trailers_); + size_t offset = receiveResponse(response_body_, false); EXPECT_CALL(stream_decoder_, decodeTrailers_(_)) .WillOnce(Invoke([](const Http::ResponseTrailerMapPtr& headers) { Http::LowerCaseString key1("key1"); @@ -160,7 +190,22 @@ TEST_P(EnvoyQuicClientStreamTest, PostRequestAndResponse) { EXPECT_EQ("value1", headers->get(key1)[0]->value().getStringView()); EXPECT_TRUE(headers->get(key2).empty()); })); - quic_stream_->OnStreamHeaderList(/*fin=*/true, trailers_.uncompressed_header_bytes(), trailers_); + if (quic::VersionUsesHttp3(quic_version_.transport_version)) { + std::string more_response_body{"bbb"}; + EXPECT_CALL(stream_decoder_, decodeData(_, _)) + .WillOnce(Invoke([&](Buffer::Instance& buffer, bool finished_reading) { + EXPECT_EQ(more_response_body, buffer.toString()); + EXPECT_EQ(false, finished_reading); + })); + std::string payload = absl::StrCat(bodyToStreamPayload(more_response_body), + spdyHeaderToHttp3StreamPayload(spdy_trailers_)); + quic::QuicStreamFrame frame(stream_id_, true, offset, payload); + quic_stream_->OnStreamFrame(frame); + } else { + quic_stream_->OnStreamHeaderList( + /*fin=*/!quic::VersionUsesHttp3(quic_version_.transport_version), + trailers_.uncompressed_header_bytes(), trailers_); + } } TEST_P(EnvoyQuicClientStreamTest, OutOfOrderTrailers) { @@ -186,7 +231,7 @@ TEST_P(EnvoyQuicClientStreamTest, OutOfOrderTrailers) { std::unique_ptr data_buffer; quic::QuicByteCount data_frame_header_length = quic::HttpEncoder::SerializeDataFrameHeader(response_body_.length(), &data_buffer); - quiche::QuicheStringPiece data_frame_header(data_buffer.get(), data_frame_header_length); + absl::string_view data_frame_header(data_buffer.get(), data_frame_header_length); data = absl::StrCat(data_frame_header, response_body_); } quic::QuicStreamFrame frame(stream_id_, false, 0, data); @@ -286,11 +331,11 @@ TEST_P(EnvoyQuicClientStreamTest, HeadersContributeToWatermarkIquic) { // Make the stream blocked by congestion control. EXPECT_CALL(quic_session_, WritevData(_, _, _, _, _, _)) - .WillOnce(Invoke([](quic::QuicStreamId, size_t /*write_length*/, quic::QuicStreamOffset, - quic::StreamSendingState state, bool, - quiche::QuicheOptional) { - return quic::QuicConsumedData{0u, state != quic::NO_FIN}; - })); + .WillOnce( + Invoke([](quic::QuicStreamId, size_t /*write_length*/, quic::QuicStreamOffset, + quic::StreamSendingState state, bool, absl::optional) { + return quic::QuicConsumedData{0u, state != quic::NO_FIN}; + })); const auto result = quic_stream_->encodeHeaders(request_headers_, /*end_stream=*/false); EXPECT_TRUE(result.ok()); @@ -305,11 +350,11 @@ TEST_P(EnvoyQuicClientStreamTest, HeadersContributeToWatermarkIquic) { // Unblock writing now, and this will write out 16kB data and cause stream to // be blocked by the flow control limit. EXPECT_CALL(quic_session_, WritevData(_, _, _, _, _, _)) - .WillOnce(Invoke([](quic::QuicStreamId, size_t write_length, quic::QuicStreamOffset, - quic::StreamSendingState state, bool, - quiche::QuicheOptional) { - return quic::QuicConsumedData{write_length, state != quic::NO_FIN}; - })); + .WillOnce( + Invoke([](quic::QuicStreamId, size_t write_length, quic::QuicStreamOffset, + quic::StreamSendingState state, bool, absl::optional) { + return quic::QuicConsumedData{write_length, state != quic::NO_FIN}; + })); EXPECT_CALL(stream_callbacks_, onBelowWriteBufferLowWatermark()); quic_session_.OnCanWrite(); EXPECT_TRUE(quic_stream_->IsFlowControlBlocked()); @@ -319,20 +364,20 @@ TEST_P(EnvoyQuicClientStreamTest, HeadersContributeToWatermarkIquic) { 32 * 1024); quic_stream_->OnWindowUpdateFrame(window_update1); EXPECT_CALL(quic_session_, WritevData(_, _, _, _, _, _)) - .WillOnce(Invoke([](quic::QuicStreamId, size_t write_length, quic::QuicStreamOffset, - quic::StreamSendingState state, bool, - quiche::QuicheOptional) { - return quic::QuicConsumedData{write_length, state != quic::NO_FIN}; - })); + .WillOnce( + Invoke([](quic::QuicStreamId, size_t write_length, quic::QuicStreamOffset, + quic::StreamSendingState state, bool, absl::optional) { + return quic::QuicConsumedData{write_length, state != quic::NO_FIN}; + })); quic_session_.OnCanWrite(); // No data should be buffered at this point. EXPECT_CALL(quic_session_, WritevData(_, _, _, _, _, _)) - .WillOnce(Invoke([](quic::QuicStreamId, size_t, quic::QuicStreamOffset, - quic::StreamSendingState state, bool, - quiche::QuicheOptional) { - return quic::QuicConsumedData{0u, state != quic::NO_FIN}; - })); + .WillOnce( + Invoke([](quic::QuicStreamId, size_t, quic::QuicStreamOffset, + quic::StreamSendingState state, bool, absl::optional) { + return quic::QuicConsumedData{0u, state != quic::NO_FIN}; + })); // Send more data. If watermark bytes counting were not cleared in previous // OnCanWrite, this write would have caused the stream to exceed its high watermark. std::string request1(16 * 1024 - 3, 'a'); @@ -345,5 +390,18 @@ TEST_P(EnvoyQuicClientStreamTest, HeadersContributeToWatermarkIquic) { EXPECT_CALL(stream_callbacks_, onResetStream(_, _)); } +TEST_P(EnvoyQuicClientStreamTest, ResetStream) { + EXPECT_CALL(stream_callbacks_, onResetStream(Http::StreamResetReason::LocalReset, _)); + quic_stream_->resetStream(Http::StreamResetReason::LocalReset); + EXPECT_TRUE(quic_stream_->rst_sent()); +} + +TEST_P(EnvoyQuicClientStreamTest, ReceiveResetStream) { + EXPECT_CALL(stream_callbacks_, onResetStream(Http::StreamResetReason::RemoteReset, _)); + quic_stream_->OnStreamReset(quic::QuicRstStreamFrame( + quic::kInvalidControlFrameId, quic_stream_->id(), quic::QUIC_STREAM_NO_ERROR, 0)); + EXPECT_TRUE(quic_stream_->rst_received()); +} + } // namespace Quic } // namespace Envoy diff --git a/test/extensions/quic_listeners/quiche/envoy_quic_proof_source_test.cc b/test/extensions/quic_listeners/quiche/envoy_quic_proof_source_test.cc index cbf66f511f503..8a493a8e89545 100644 --- a/test/extensions/quic_listeners/quiche/envoy_quic_proof_source_test.cc +++ b/test/extensions/quic_listeners/quiche/envoy_quic_proof_source_test.cc @@ -25,7 +25,7 @@ namespace Quic { class TestGetProofCallback : public quic::ProofSource::Callback { public: TestGetProofCallback(bool& called, bool should_succeed, const std::string& server_config, - quic::QuicTransportVersion& version, quiche::QuicheStringPiece chlo_hash, + quic::QuicTransportVersion& version, absl::string_view chlo_hash, Network::FilterChain& filter_chain) : called_(called), should_succeed_(should_succeed), server_config_(server_config), version_(version), chlo_hash_(chlo_hash), expected_filter_chain_(filter_chain) { @@ -100,7 +100,7 @@ class TestGetProofCallback : public quic::ProofSource::Callback { bool should_succeed_; const std::string& server_config_; const quic::QuicTransportVersion& version_; - quiche::QuicheStringPiece chlo_hash_; + absl::string_view chlo_hash_; Network::FilterChain& expected_filter_chain_; NiceMock store_; Event::GlobalTimeSystem time_system_; @@ -178,7 +178,7 @@ class EnvoyQuicProofSourceTest : public ::testing::Test { quic::QuicSocketAddress server_address_; quic::QuicSocketAddress client_address_; quic::QuicTransportVersion version_{quic::QUIC_VERSION_UNSUPPORTED}; - quiche::QuicheStringPiece chlo_hash_{"aaaaa"}; + absl::string_view chlo_hash_{"aaaaa"}; std::string server_config_{"Server Config"}; std::string expected_certs_{quic::test::kTestCertificateChainPem}; std::string pkey_{quic::test::kTestCertificatePrivateKeyPem}; diff --git a/test/extensions/quic_listeners/quiche/envoy_quic_proof_verifier_test.cc b/test/extensions/quic_listeners/quiche/envoy_quic_proof_verifier_test.cc index 4a1dfe144dd3c..9cdc169cd6f55 100644 --- a/test/extensions/quic_listeners/quiche/envoy_quic_proof_verifier_test.cc +++ b/test/extensions/quic_listeners/quiche/envoy_quic_proof_verifier_test.cc @@ -163,7 +163,7 @@ TEST_F(EnvoyQuicProofVerifierTest, VerifyProofFailureEmptyCertChain) { std::unique_ptr cert_view = quic::CertificateView::ParseSingleCertificate(leaf_cert_); quic::QuicTransportVersion version{quic::QUIC_VERSION_UNSUPPORTED}; - quiche::QuicheStringPiece chlo_hash{"aaaaa"}; + absl::string_view chlo_hash{"aaaaa"}; std::string server_config{"Server Config"}; const std::string ocsp_response; const std::string cert_sct; @@ -181,7 +181,7 @@ TEST_F(EnvoyQuicProofVerifierTest, VerifyProofFailureInvalidLeafCert) { std::unique_ptr cert_view = quic::CertificateView::ParseSingleCertificate(leaf_cert_); quic::QuicTransportVersion version{quic::QUIC_VERSION_UNSUPPORTED}; - quiche::QuicheStringPiece chlo_hash{"aaaaa"}; + absl::string_view chlo_hash{"aaaaa"}; std::string server_config{"Server Config"}; const std::string ocsp_response; const std::string cert_sct; @@ -197,7 +197,7 @@ TEST_F(EnvoyQuicProofVerifierTest, VerifyProofFailureInvalidLeafCert) { TEST_F(EnvoyQuicProofVerifierTest, VerifyProofFailureUnsupportedECKey) { configCertVerificationDetails(true); quic::QuicTransportVersion version{quic::QUIC_VERSION_UNSUPPORTED}; - quiche::QuicheStringPiece chlo_hash{"aaaaa"}; + absl::string_view chlo_hash{"aaaaa"}; std::string server_config{"Server Config"}; const std::string ocsp_response; const std::string cert_sct; @@ -236,7 +236,7 @@ TEST_F(EnvoyQuicProofVerifierTest, VerifyProofFailureInvalidSignature) { std::unique_ptr cert_view = quic::CertificateView::ParseSingleCertificate(leaf_cert_); quic::QuicTransportVersion version{quic::QUIC_VERSION_UNSUPPORTED}; - quiche::QuicheStringPiece chlo_hash{"aaaaa"}; + absl::string_view chlo_hash{"aaaaa"}; std::string server_config{"Server Config"}; const std::string ocsp_response; const std::string cert_sct; diff --git a/test/extensions/quic_listeners/quiche/envoy_quic_server_session_test.cc b/test/extensions/quic_listeners/quiche/envoy_quic_server_session_test.cc index 05307c6b9b7c2..4fc37685788a3 100644 --- a/test/extensions/quic_listeners/quiche/envoy_quic_server_session_test.cc +++ b/test/extensions/quic_listeners/quiche/envoy_quic_server_session_test.cc @@ -61,6 +61,7 @@ class TestEnvoyQuicServerConnection : public EnvoyQuicServerConnection { const quic::ParsedQuicVersionVector& supported_versions, Network::Socket& listen_socket) : EnvoyQuicServerConnection(quic::test::TestConnectionId(), + quic::QuicSocketAddress(quic::QuicIpAddress::Any4(), 12345), quic::QuicSocketAddress(quic::QuicIpAddress::Loopback4(), 12345), helper, alarm_factory, &writer, /*owns_writer=*/false, supported_versions, listen_socket) {} @@ -201,10 +202,10 @@ class EnvoyQuicServerSessionTest : public testing::TestWithParam { crypto_stream_ = test_crypto_stream; } quic::test::QuicServerSessionBasePeer::SetCryptoStream(&envoy_quic_session_, crypto_stream); - quic_connection_->SetDefaultEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); quic_connection_->SetEncrypter( quic::ENCRYPTION_FORWARD_SECURE, std::make_unique(quic::Perspective::IS_SERVER)); + quic_connection_->SetDefaultEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); } bool installReadFilter() { diff --git a/test/extensions/quic_listeners/quiche/envoy_quic_server_stream_test.cc b/test/extensions/quic_listeners/quiche/envoy_quic_server_stream_test.cc index 42ba39344f4b0..3e37ba3e1d39d 100644 --- a/test/extensions/quic_listeners/quiche/envoy_quic_server_stream_test.cc +++ b/test/extensions/quic_listeners/quiche/envoy_quic_server_stream_test.cc @@ -51,6 +51,7 @@ class EnvoyQuicServerStreamTest : public testing::TestWithParam { POOL_GAUGE(listener_config_.listenerScope()), POOL_HISTOGRAM(listener_config_.listenerScope()))}), quic_connection_(quic::test::TestConnectionId(), + quic::QuicSocketAddress(quic::QuicIpAddress::Any6(), 123), quic::QuicSocketAddress(quic::QuicIpAddress::Any6(), 12345), connection_helper_, alarm_factory_, &writer_, /*owns_writer=*/false, {quic_version_}, *listener_config_.socket_), @@ -66,11 +67,11 @@ class EnvoyQuicServerStreamTest : public testing::TestWithParam { quic_session_.ActivateStream(std::unique_ptr(quic_stream_)); EXPECT_CALL(quic_session_, ShouldYield(_)).WillRepeatedly(testing::Return(false)); EXPECT_CALL(quic_session_, WritevData(_, _, _, _, _, _)) - .WillRepeatedly(Invoke([](quic::QuicStreamId, size_t write_length, quic::QuicStreamOffset, - quic::StreamSendingState state, bool, - quiche::QuicheOptional) { - return quic::QuicConsumedData{write_length, state != quic::NO_FIN}; - })); + .WillRepeatedly( + Invoke([](quic::QuicStreamId, size_t write_length, quic::QuicStreamOffset, + quic::StreamSendingState state, bool, absl::optional) { + return quic::QuicConsumedData{write_length, state != quic::NO_FIN}; + })); EXPECT_CALL(writer_, WritePacket(_, _, _, _, _)) .WillRepeatedly(Invoke([](const char*, size_t buf_len, const quic::QuicIpAddress&, const quic::QuicSocketAddress&, quic::PerPacketOptions*) { @@ -88,14 +89,16 @@ class EnvoyQuicServerStreamTest : public testing::TestWithParam { request_headers_.OnHeader(":path", "/"); request_headers_.OnHeaderBlockEnd(/*uncompressed_header_bytes=*/0, /*compressed_header_bytes=*/0); + spdy_request_headers_[":authority"] = host_; + spdy_request_headers_[":method"] = "POST"; + spdy_request_headers_[":path"] = "/"; trailers_.OnHeaderBlockStart(); trailers_.OnHeader("key1", "value1"); - if (!quic::VersionUsesHttp3(quic_version_.transport_version)) { - // ":final-offset" is required and stripped off by quic. - trailers_.OnHeader(":final-offset", absl::StrCat("", request_body_.length())); - } + // ":final-offset" is required and stripped off by quic. + trailers_.OnHeader(":final-offset", absl::StrCat("", request_body_.length())); trailers_.OnHeaderBlockEnd(/*uncompressed_header_bytes=*/0, /*compressed_header_bytes=*/0); + spdy_trailers_["key1"] = "value1"; } void TearDown() override { @@ -105,27 +108,20 @@ class EnvoyQuicServerStreamTest : public testing::TestWithParam { } std::string bodyToStreamPayload(const std::string& body) { - std::string data = body; - if (quic::VersionUsesHttp3(quic_version_.transport_version)) { - std::unique_ptr data_buffer; - quic::QuicByteCount data_frame_header_length = - quic::HttpEncoder::SerializeDataFrameHeader(body.length(), &data_buffer); - quiche::QuicheStringPiece data_frame_header(data_buffer.get(), data_frame_header_length); - data = absl::StrCat(data_frame_header, body); + if (!quic::VersionUsesHttp3(quic_version_.transport_version)) { + return body; } - return data; + return bodyToHttp3StreamPayload(body); } - size_t sendRequest(const std::string& payload, bool fin, size_t decoder_buffer_high_watermark) { + size_t receiveRequest(const std::string& payload, bool fin, + size_t decoder_buffer_high_watermark) { EXPECT_CALL(stream_decoder_, decodeHeaders_(_, /*end_stream=*/false)) .WillOnce(Invoke([this](const Http::RequestHeaderMapPtr& headers, bool) { EXPECT_EQ(host_, headers->getHostValue()); EXPECT_EQ("/", headers->getPathValue()); EXPECT_EQ(Http::Headers::get().MethodValues.Post, headers->getMethodValue()); })); - quic_stream_->OnStreamHeaderList(/*fin=*/false, request_headers_.uncompressed_header_bytes(), - request_headers_); - EXPECT_TRUE(quic_stream_->FinishedReadingHeaders()); EXPECT_CALL(stream_decoder_, decodeData(_, _)) .WillOnce(Invoke([&](Buffer::Instance& buffer, bool finished_reading) { @@ -135,10 +131,21 @@ class EnvoyQuicServerStreamTest : public testing::TestWithParam { quic_stream_->readDisable(true); } })); - std::string data = bodyToStreamPayload(payload); - quic::QuicStreamFrame frame(stream_id_, fin, 0, data); + if (quic::VersionUsesHttp3(quic_version_.transport_version)) { + std::string data = absl::StrCat(spdyHeaderToHttp3StreamPayload(spdy_request_headers_), + bodyToStreamPayload(payload)); + quic::QuicStreamFrame frame(stream_id_, fin, 0, data); + quic_stream_->OnStreamFrame(frame); + EXPECT_TRUE(quic_stream_->FinishedReadingHeaders()); + return data.length(); + } + quic_stream_->OnStreamHeaderList(/*fin=*/false, request_headers_.uncompressed_header_bytes(), + request_headers_); + + quic::QuicStreamFrame frame(stream_id_, fin, 0, payload); quic_stream_->OnStreamFrame(frame); - return data.length(); + EXPECT_TRUE(quic_stream_->FinishedReadingHeaders()); + return payload.length(); } protected: @@ -158,9 +165,11 @@ class EnvoyQuicServerStreamTest : public testing::TestWithParam { Http::MockRequestDecoder stream_decoder_; Http::MockStreamCallbacks stream_callbacks_; quic::QuicHeaderList request_headers_; + spdy::SpdyHeaderBlock spdy_request_headers_; Http::TestResponseHeaderMapImpl response_headers_; Http::TestResponseTrailerMapImpl response_trailers_; quic::QuicHeaderList trailers_; + spdy::SpdyHeaderBlock spdy_trailers_; std::string host_{"www.abc.com"}; std::string request_body_{"Hello world"}; }; @@ -177,27 +186,40 @@ TEST_P(EnvoyQuicServerStreamTest, GetRequestAndResponse) { request_headers.OnHeaderBlockEnd(/*uncompressed_header_bytes=*/0, /*compressed_header_bytes=*/0); - EXPECT_CALL(stream_decoder_, decodeHeaders_(_, /*end_stream=*/true)) + EXPECT_CALL(stream_decoder_, decodeHeaders_(_, /*end_stream=*/!quic::VersionUsesHttp3( + quic_version_.transport_version))) .WillOnce(Invoke([this](const Http::RequestHeaderMapPtr& headers, bool) { EXPECT_EQ(host_, headers->getHostValue()); EXPECT_EQ("/", headers->getPathValue()); EXPECT_EQ(Http::Headers::get().MethodValues.Get, headers->getMethodValue()); })); - quic_stream_->OnStreamHeaderList(/*fin=*/true, request_headers.uncompressed_header_bytes(), - request_headers); + if (quic::VersionUsesHttp3(quic_version_.transport_version)) { + EXPECT_CALL(stream_decoder_, decodeData(BufferStringEqual(""), /*end_stream=*/true)); + spdy::SpdyHeaderBlock spdy_headers; + spdy_headers[":authority"] = host_; + spdy_headers[":method"] = "GET"; + spdy_headers[":path"] = "/"; + std::string payload = spdyHeaderToHttp3StreamPayload(spdy_headers); + quic::QuicStreamFrame frame(stream_id_, true, 0, payload); + quic_stream_->OnStreamFrame(frame); + } else { + quic_stream_->OnStreamHeaderList(/*fin=*/true, request_headers.uncompressed_header_bytes(), + request_headers); + } EXPECT_TRUE(quic_stream_->FinishedReadingHeaders()); quic_stream_->encodeHeaders(response_headers_, /*end_stream=*/true); } TEST_P(EnvoyQuicServerStreamTest, PostRequestAndResponse) { EXPECT_EQ(absl::nullopt, quic_stream_->http1StreamEncoderOptions()); - sendRequest(request_body_, true, request_body_.size() * 2); + receiveRequest(request_body_, true, request_body_.size() * 2); quic_stream_->encodeHeaders(response_headers_, /*end_stream=*/false); quic_stream_->encodeTrailers(response_trailers_); } TEST_P(EnvoyQuicServerStreamTest, DecodeHeadersBodyAndTrailers) { - sendRequest(request_body_, false, request_body_.size() * 2); + size_t offset = receiveRequest(request_body_, false, request_body_.size() * 2); + EXPECT_CALL(stream_decoder_, decodeTrailers_(_)) .WillOnce(Invoke([](const Http::RequestTrailerMapPtr& headers) { Http::LowerCaseString key1("key1"); @@ -205,7 +227,14 @@ TEST_P(EnvoyQuicServerStreamTest, DecodeHeadersBodyAndTrailers) { EXPECT_EQ("value1", headers->get(key1)[0]->value().getStringView()); EXPECT_TRUE(headers->get(key2).empty()); })); - quic_stream_->OnStreamHeaderList(/*fin=*/true, trailers_.uncompressed_header_bytes(), trailers_); + if (quic::VersionUsesHttp3(quic_version_.transport_version)) { + std::string payload = spdyHeaderToHttp3StreamPayload(spdy_trailers_); + quic::QuicStreamFrame frame(stream_id_, true, offset, payload); + quic_stream_->OnStreamFrame(frame); + } else { + quic_stream_->OnStreamHeaderList(/*fin=*/true, trailers_.uncompressed_header_bytes(), + trailers_); + } EXPECT_CALL(stream_callbacks_, onResetStream(_, _)); } @@ -227,8 +256,7 @@ TEST_P(EnvoyQuicServerStreamTest, OutOfOrderTrailers) { // Trailer should be delivered to HCM later after body arrives. quic_stream_->OnStreamHeaderList(/*fin=*/true, trailers_.uncompressed_header_bytes(), trailers_); - std::string data = bodyToStreamPayload(request_body_); - quic::QuicStreamFrame frame(stream_id_, false, 0, data); + quic::QuicStreamFrame frame(stream_id_, false, 0, request_body_); EXPECT_CALL(stream_decoder_, decodeData(_, _)) .WillOnce(Invoke([this](Buffer::Instance& buffer, bool finished_reading) { EXPECT_EQ(request_body_, buffer.toString()); @@ -245,10 +273,29 @@ TEST_P(EnvoyQuicServerStreamTest, OutOfOrderTrailers) { quic_stream_->OnStreamFrame(frame); } +TEST_P(EnvoyQuicServerStreamTest, ResetStreamByHCM) { + receiveRequest(request_body_, false, request_body_.size() * 2); + EXPECT_CALL(stream_callbacks_, onResetStream(_, _)); + quic_stream_->resetStream(Http::StreamResetReason::LocalReset); + EXPECT_TRUE(quic_stream_->rst_sent()); +} + +TEST_P(EnvoyQuicServerStreamTest, EarlyResponseWithReset) { + receiveRequest(request_body_, false, request_body_.size() * 2); + // Write response headers with FIN before finish receiving request. + quic_stream_->encodeHeaders(response_headers_, true); + // Resetting the stream now means stop reading and sending QUIC_STREAM_NO_ERROR. + EXPECT_CALL(stream_callbacks_, onResetStream(_, _)); + quic_stream_->resetStream(Http::StreamResetReason::LocalReset); + EXPECT_TRUE(quic_stream_->rst_sent()); + EXPECT_TRUE(quic_stream_->reading_stopped()); + EXPECT_EQ(quic::QUIC_STREAM_NO_ERROR, quic_stream_->stream_error()); +} + TEST_P(EnvoyQuicServerStreamTest, ReadDisableUponLargePost) { std::string large_request(1024, 'a'); // Sending such large request will cause read to be disabled. - size_t payload_offset = sendRequest(large_request, false, 512); + size_t payload_offset = receiveRequest(large_request, false, 512); EXPECT_FALSE(quic_stream_->HasBytesToRead()); // Disable reading one more time. quic_stream_->readDisable(true); @@ -324,7 +371,7 @@ TEST_P(EnvoyQuicServerStreamTest, ReadDisableAndReEnableImmediately) { // Tests that the stream with a send buffer whose high limit is 16k and low // limit is 8k sends over 32kB response. TEST_P(EnvoyQuicServerStreamTest, WatermarkSendBuffer) { - sendRequest(request_body_, true, request_body_.size() * 2); + receiveRequest(request_body_, true, request_body_.size() * 2); // Bump connection flow control window large enough not to cause connection // level flow control blocked. @@ -386,7 +433,7 @@ TEST_P(EnvoyQuicServerStreamTest, HeadersContributeToWatermarkIquic) { return; } - sendRequest(request_body_, true, request_body_.size() * 2); + receiveRequest(request_body_, true, request_body_.size() * 2); // Bump connection flow control window large enough not to cause connection level flow control // blocked @@ -397,11 +444,11 @@ TEST_P(EnvoyQuicServerStreamTest, HeadersContributeToWatermarkIquic) { // Make the stream blocked by congestion control. EXPECT_CALL(quic_session_, WritevData(_, _, _, _, _, _)) - .WillOnce(Invoke([](quic::QuicStreamId, size_t /*write_length*/, quic::QuicStreamOffset, - quic::StreamSendingState state, bool, - quiche::QuicheOptional) { - return quic::QuicConsumedData{0u, state != quic::NO_FIN}; - })); + .WillOnce( + Invoke([](quic::QuicStreamId, size_t /*write_length*/, quic::QuicStreamOffset, + quic::StreamSendingState state, bool, absl::optional) { + return quic::QuicConsumedData{0u, state != quic::NO_FIN}; + })); quic_stream_->encodeHeaders(response_headers_, /*end_stream=*/false); // Encode 16kB -10 bytes request body. Because the high watermark is 16KB, with previously @@ -415,11 +462,11 @@ TEST_P(EnvoyQuicServerStreamTest, HeadersContributeToWatermarkIquic) { // Unblock writing now, and this will write out 16kB data and cause stream to // be blocked by the flow control limit. EXPECT_CALL(quic_session_, WritevData(_, _, _, _, _, _)) - .WillOnce(Invoke([](quic::QuicStreamId, size_t write_length, quic::QuicStreamOffset, - quic::StreamSendingState state, bool, - quiche::QuicheOptional) { - return quic::QuicConsumedData{write_length, state != quic::NO_FIN}; - })); + .WillOnce( + Invoke([](quic::QuicStreamId, size_t write_length, quic::QuicStreamOffset, + quic::StreamSendingState state, bool, absl::optional) { + return quic::QuicConsumedData{write_length, state != quic::NO_FIN}; + })); EXPECT_CALL(stream_callbacks_, onBelowWriteBufferLowWatermark()); quic_session_.OnCanWrite(); EXPECT_TRUE(quic_stream_->IsFlowControlBlocked()); @@ -429,20 +476,20 @@ TEST_P(EnvoyQuicServerStreamTest, HeadersContributeToWatermarkIquic) { 32 * 1024); quic_stream_->OnWindowUpdateFrame(window_update1); EXPECT_CALL(quic_session_, WritevData(_, _, _, _, _, _)) - .WillOnce(Invoke([](quic::QuicStreamId, size_t write_length, quic::QuicStreamOffset, - quic::StreamSendingState state, bool, - quiche::QuicheOptional) { - return quic::QuicConsumedData{write_length, state != quic::NO_FIN}; - })); + .WillOnce( + Invoke([](quic::QuicStreamId, size_t write_length, quic::QuicStreamOffset, + quic::StreamSendingState state, bool, absl::optional) { + return quic::QuicConsumedData{write_length, state != quic::NO_FIN}; + })); quic_session_.OnCanWrite(); // No data should be buffered at this point. EXPECT_CALL(quic_session_, WritevData(_, _, _, _, _, _)) - .WillRepeatedly(Invoke([](quic::QuicStreamId, size_t, quic::QuicStreamOffset, - quic::StreamSendingState state, bool, - quiche::QuicheOptional) { - return quic::QuicConsumedData{0u, state != quic::NO_FIN}; - })); + .WillRepeatedly( + Invoke([](quic::QuicStreamId, size_t, quic::QuicStreamOffset, + quic::StreamSendingState state, bool, absl::optional) { + return quic::QuicConsumedData{0u, state != quic::NO_FIN}; + })); // Send more data. If watermark bytes counting were not cleared in previous // OnCanWrite, this write would have caused the stream to exceed its high watermark. std::string response1(16 * 1024 - 3, 'a'); diff --git a/test/extensions/quic_listeners/quiche/integration/quic_http_integration_test.cc b/test/extensions/quic_listeners/quiche/integration/quic_http_integration_test.cc index d6121ff2ec6ab..4c6309620f3da 100644 --- a/test/extensions/quic_listeners/quiche/integration/quic_http_integration_test.cc +++ b/test/extensions/quic_listeners/quiche/integration/quic_http_integration_test.cc @@ -531,5 +531,11 @@ TEST_P(QuicHttpIntegrationTest, CertVerificationFailure) { EXPECT_EQ(failure_reason, codec_client_->connection()->transportFailureReason()); } +TEST_P(QuicHttpIntegrationTest, RequestResponseWithTrailers) { + config_helper_.addConfigModifier(setEnableUpstreamTrailersHttp1()); + testTrailers(/*request_size=*/10, /*response_size=*/10, /*request_trailers_present=*/true, + /*response_trailers_present=*/true); +} + } // namespace Quic } // namespace Envoy diff --git a/test/extensions/quic_listeners/quiche/platform/BUILD b/test/extensions/quic_listeners/quiche/platform/BUILD index 420e812b85a7c..7dbb08d821cc8 100644 --- a/test/extensions/quic_listeners/quiche/platform/BUILD +++ b/test/extensions/quic_listeners/quiche/platform/BUILD @@ -9,16 +9,6 @@ licenses(["notice"]) # Apache 2 envoy_package() -envoy_cc_test( - name = "quiche_platform_test", - srcs = ["quiche_platform_test.cc"], - external_deps = ["quiche_common_platform"], - deps = [ - "@com_googlesource_quiche//:quiche_common_platform", - "@com_googlesource_quiche//:quiche_common_platform_endian", - ], -) - envoy_cc_test( name = "http2_platform_test", srcs = ["http2_platform_test.cc"], @@ -63,7 +53,6 @@ envoy_cc_test( "@com_googlesource_quiche//:quic_platform_mem_slice_span", "@com_googlesource_quiche//:quic_platform_mem_slice_storage", "@com_googlesource_quiche//:quic_platform_mock_log", - "@com_googlesource_quiche//:quic_platform_port_utils", "@com_googlesource_quiche//:quic_platform_sleep", "@com_googlesource_quiche//:quic_platform_system_event_loop", "@com_googlesource_quiche//:quic_platform_test", @@ -150,17 +139,6 @@ envoy_cc_test_library( deps = ["@com_googlesource_quiche//:quic_platform_base"], ) -envoy_cc_test_library( - name = "quic_platform_port_utils_impl_lib", - srcs = ["quic_port_utils_impl.cc"], - hdrs = ["quic_port_utils_impl.h"], - tags = ["nofips"], - deps = [ - "//source/common/network:utility_lib", - "//test/test_common:environment_lib", - ], -) - envoy_cc_test_library( name = "quic_platform_test_mem_slice_vector_impl_lib", hdrs = ["quic_test_mem_slice_vector_impl.h"], diff --git a/test/extensions/quic_listeners/quiche/platform/http2_platform_test.cc b/test/extensions/quic_listeners/quiche/platform/http2_platform_test.cc index 069a79eab0efe..35aee5d273738 100644 --- a/test/extensions/quic_listeners/quiche/platform/http2_platform_test.cc +++ b/test/extensions/quic_listeners/quiche/platform/http2_platform_test.cc @@ -72,20 +72,14 @@ TEST(Http2PlatformTest, Http2Log) { HTTP2_DLOG_EVERY_N(ERROR, 2) << "DLOG_EVERY_N(ERROR, 2)"; } -TEST(Http2PlatformTest, Http2StringPiece) { - std::string s = "bar"; - quiche::QuicheStringPiece sp(s); - EXPECT_EQ('b', sp[0]); -} - TEST(Http2PlatformTest, Http2Macro) { EXPECT_DEBUG_DEATH(HTTP2_UNREACHABLE(), ""); EXPECT_DEATH(HTTP2_DIE_IF_NULL(nullptr), ""); } TEST(Http2PlatformTest, Http2Flags) { - auto& flag_registry = quiche::FlagRegistry::GetInstance(); - flag_registry.ResetFlags(); + auto& flag_registry = quiche::FlagRegistry::getInstance(); + flag_registry.resetFlags(); EXPECT_FALSE(GetHttp2ReloadableFlag(http2_testonly_default_false)); SetHttp2ReloadableFlag(http2_testonly_default_false, true); EXPECT_TRUE(GetHttp2ReloadableFlag(http2_testonly_default_false)); @@ -93,22 +87,22 @@ TEST(Http2PlatformTest, Http2Flags) { for (std::string s : {"1", "t", "true", "TRUE", "y", "yes", "Yes"}) { SetHttp2ReloadableFlag(http2_testonly_default_false, false); EXPECT_FALSE(GetHttp2ReloadableFlag(http2_testonly_default_false)); - EXPECT_TRUE(flag_registry.FindFlag("http2_reloadable_flag_http2_testonly_default_false") - ->SetValueFromString(s)); + EXPECT_TRUE(flag_registry.findFlag("FLAGS_quic_reloadable_flag_http2_testonly_default_false") + ->setValueFromString(s)); EXPECT_TRUE(GetHttp2ReloadableFlag(http2_testonly_default_false)); } for (std::string s : {"0", "f", "false", "FALSE", "n", "no", "No"}) { SetHttp2ReloadableFlag(http2_testonly_default_false, true); EXPECT_TRUE(GetHttp2ReloadableFlag(http2_testonly_default_false)); - EXPECT_TRUE(flag_registry.FindFlag("http2_reloadable_flag_http2_testonly_default_false") - ->SetValueFromString(s)); + EXPECT_TRUE(flag_registry.findFlag("FLAGS_quic_reloadable_flag_http2_testonly_default_false") + ->setValueFromString(s)); EXPECT_FALSE(GetHttp2ReloadableFlag(http2_testonly_default_false)); } for (std::string s : {"some", "invalid", "values", ""}) { SetHttp2ReloadableFlag(http2_testonly_default_false, false); EXPECT_FALSE(GetHttp2ReloadableFlag(http2_testonly_default_false)); - EXPECT_FALSE(flag_registry.FindFlag("http2_reloadable_flag_http2_testonly_default_false") - ->SetValueFromString(s)); + EXPECT_FALSE(flag_registry.findFlag("FLAGS_quic_reloadable_flag_http2_testonly_default_false") + ->setValueFromString(s)); EXPECT_FALSE(GetHttp2ReloadableFlag(http2_testonly_default_false)); } } diff --git a/test/extensions/quic_listeners/quiche/platform/quic_platform_test.cc b/test/extensions/quic_listeners/quiche/platform/quic_platform_test.cc index 68141aa940394..902ad1a9ea0f9 100644 --- a/test/extensions/quic_listeners/quiche/platform/quic_platform_test.cc +++ b/test/extensions/quic_listeners/quiche/platform/quic_platform_test.cc @@ -30,7 +30,6 @@ #include "gtest/gtest.h" #include "quiche/common/platform/api/quiche_string_piece.h" #include "quiche/epoll_server/fake_simple_epoll_server.h" -#include "quiche/quic/platform/api/quic_aligned.h" #include "quiche/quic/platform/api/quic_bug_tracker.h" #include "quiche/quic/platform/api/quic_cert_utils.h" #include "quiche/quic/platform/api/quic_client_stats.h" @@ -42,7 +41,6 @@ #include "quiche/quic/platform/api/quic_flags.h" #include "quiche/quic/platform/api/quic_hostname_utils.h" #include "quiche/quic/platform/api/quic_logging.h" -#include "quiche/quic/platform/api/quic_macros.h" #include "quiche/quic/platform/api/quic_map_util.h" #include "quiche/quic/platform/api/quic_mem_slice.h" #include "quiche/quic/platform/api/quic_mem_slice_span.h" @@ -50,7 +48,6 @@ #include "quiche/quic/platform/api/quic_mock_log.h" #include "quiche/quic/platform/api/quic_mutex.h" #include "quiche/quic/platform/api/quic_pcc_sender.h" -#include "quiche/quic/platform/api/quic_port_utils.h" #include "quiche/quic/platform/api/quic_ptr_util.h" #include "quiche/quic/platform/api/quic_server_stats.h" #include "quiche/quic/platform/api/quic_sleep.h" @@ -92,8 +89,6 @@ class QuicPlatformTest : public testing::Test { const int verbosity_log_threshold_; }; -TEST_F(QuicPlatformTest, QuicAlignOf) { EXPECT_LT(0, QUIC_ALIGN_OF(int)); } - enum class TestEnum { ZERO = 0, ONE, TWO, COUNT }; TEST_F(QuicPlatformTest, QuicBugTracker) { @@ -468,9 +463,9 @@ TEST_F(QuicPlatformTest, QuicCertUtils) { unsigned char* der = nullptr; int len = i2d_X509(x509_cert.get(), &der); ASSERT_GT(len, 0); - quiche::QuicheStringPiece out; + absl::string_view out; QuicCertUtils::ExtractSubjectNameFromDERCert( - quiche::QuicheStringPiece(reinterpret_cast(der), len), &out); + absl::string_view(reinterpret_cast(der), len), &out); EXPECT_EQ("0z1\v0\t\x6\x3U\x4\x6\x13\x2US1\x13" "0\x11\x6\x3U\x4\b\f\nCalifornia1\x16" "0\x14\x6\x3U\x4\a\f\rSan Francisco1\r" @@ -566,8 +561,8 @@ TEST_F(QuicPlatformTest, MonotonicityWithFakeEpollClock) { } TEST_F(QuicPlatformTest, QuicFlags) { - auto& flag_registry = quiche::FlagRegistry::GetInstance(); - flag_registry.ResetFlags(); + auto& flag_registry = quiche::FlagRegistry::getInstance(); + flag_registry.resetFlags(); EXPECT_FALSE(GetQuicReloadableFlag(quic_testonly_default_false)); EXPECT_TRUE(GetQuicReloadableFlag(quic_testonly_default_true)); @@ -583,14 +578,15 @@ TEST_F(QuicPlatformTest, QuicFlags) { SetQuicFlag(FLAGS_quic_time_wait_list_seconds, 100); EXPECT_EQ(100, GetQuicFlag(FLAGS_quic_time_wait_list_seconds)); - flag_registry.ResetFlags(); + flag_registry.resetFlags(); EXPECT_FALSE(GetQuicReloadableFlag(quic_testonly_default_false)); EXPECT_TRUE(GetQuicRestartFlag(quic_testonly_default_true)); EXPECT_EQ(200, GetQuicFlag(FLAGS_quic_time_wait_list_seconds)); - flag_registry.FindFlag("quic_reloadable_flag_quic_testonly_default_false") - ->SetValueFromString("true"); - flag_registry.FindFlag("quic_restart_flag_quic_testonly_default_true")->SetValueFromString("0"); - flag_registry.FindFlag("quic_time_wait_list_seconds")->SetValueFromString("100"); + flag_registry.findFlag("FLAGS_quic_reloadable_flag_quic_testonly_default_false") + ->setValueFromString("true"); + flag_registry.findFlag("FLAGS_quic_restart_flag_quic_testonly_default_true") + ->setValueFromString("0"); + flag_registry.findFlag("FLAGS_quic_time_wait_list_seconds")->setValueFromString("100"); EXPECT_TRUE(GetQuicReloadableFlag(quic_testonly_default_false)); EXPECT_FALSE(GetQuicRestartFlag(quic_testonly_default_true)); EXPECT_EQ(100, GetQuicFlag(FLAGS_quic_time_wait_list_seconds)); @@ -661,35 +657,6 @@ TEST_F(FileUtilsTest, ReadFileContents) { EXPECT_EQ(data, output); } -TEST_F(QuicPlatformTest, PickUnsedPort) { - int port = QuicPickServerPortForTestsOrDie(); - std::vector supported_versions = - Envoy::TestEnvironment::getIpVersionsForTest(); - for (auto ip_version : supported_versions) { - Envoy::Network::Address::InstanceConstSharedPtr addr = - Envoy::Network::Test::getCanonicalLoopbackAddress(ip_version); - Envoy::Network::Address::InstanceConstSharedPtr addr_with_port = - Envoy::Network::Utility::getAddressWithPort(*addr, port); - Envoy::Network::SocketImpl sock(Envoy::Network::Socket::Type::Datagram, addr_with_port); - // binding of given port should success. - EXPECT_EQ(0, sock.bind(addr_with_port).rc_); - } -} - -TEST_F(QuicPlatformTest, FailToPickUnsedPort) { - Envoy::Api::MockOsSysCalls os_sys_calls; - Envoy::TestThreadsafeSingletonInjector os_calls(&os_sys_calls); - // Actually create sockets. - EXPECT_CALL(os_sys_calls, socket(_, _, _)).WillRepeatedly([](int domain, int type, int protocol) { - os_fd_t fd = ::socket(domain, type, protocol); - return Envoy::Api::SysCallSocketResult{fd, errno}; - }); - // Fail bind call's to mimic port exhaustion. - EXPECT_CALL(os_sys_calls, bind(_, _, _)) - .WillRepeatedly(Return(Envoy::Api::SysCallIntResult{-1, SOCKET_ERROR_ADDR_IN_USE})); - EXPECT_DEATH(QuicPickServerPortForTestsOrDie(), "Failed to pick a port for test."); -} - TEST_F(QuicPlatformTest, TestEnvoyQuicBufferAllocator) { QuicStreamBufferAllocator allocator; Envoy::Stats::TestUtil::MemoryTest memory_test; @@ -711,14 +678,6 @@ TEST_F(QuicPlatformTest, TestSystemEventLoop) { QuicSystemEventLoop("dummy"); } -QUIC_MUST_USE_RESULT bool dummyTestFunction() { return false; } - -TEST_F(QuicPlatformTest, TestQuicMacros) { - // Just make sure it compiles. - EXPECT_FALSE(dummyTestFunction()); - int a QUIC_UNUSED; -} - TEST(EnvoyQuicMemSliceTest, ConstructMemSliceFromBuffer) { std::string str(512, 'b'); // Fragment needs to out-live buffer. diff --git a/test/extensions/quic_listeners/quiche/platform/quic_test_output_impl.cc b/test/extensions/quic_listeners/quiche/platform/quic_test_output_impl.cc index 556f6cd3e18a3..9eaf8532aa492 100644 --- a/test/extensions/quic_listeners/quiche/platform/quic_test_output_impl.cc +++ b/test/extensions/quic_listeners/quiche/platform/quic_test_output_impl.cc @@ -19,7 +19,7 @@ namespace quic { namespace { -void QuicRecordTestOutputToFile(const std::string& filename, quiche::QuicheStringPiece data) { +void quicRecordTestOutputToFile(const std::string& filename, absl::string_view data) { const char* output_dir_env = std::getenv("QUIC_TEST_OUTPUT_DIR"); if (output_dir_env == nullptr) { QUIC_LOG(WARNING) << "Could not save test output since QUIC_TEST_OUTPUT_DIR is not set"; @@ -64,11 +64,13 @@ void QuicRecordTestOutputToFile(const std::string& filename, quiche::QuicheStrin } } // namespace -void QuicSaveTestOutputImpl(quiche::QuicheStringPiece filename, quiche::QuicheStringPiece data) { - QuicRecordTestOutputToFile(filename.data(), data); +// NOLINTNEXTLINE(readability-identifier-naming) +void QuicSaveTestOutputImpl(absl::string_view filename, absl::string_view data) { + quicRecordTestOutputToFile(filename.data(), data); } -bool QuicLoadTestOutputImpl(quiche::QuicheStringPiece filename, std::string* data) { +// NOLINTNEXTLINE(readability-identifier-naming) +bool QuicLoadTestOutputImpl(absl::string_view filename, std::string* data) { const char* read_dir_env = std::getenv("QUIC_TEST_OUTPUT_DIR"); if (read_dir_env == nullptr) { QUIC_LOG(WARNING) << "Could not load test output since QUIC_TEST_OUTPUT_DIR is not set"; @@ -96,7 +98,8 @@ bool QuicLoadTestOutputImpl(quiche::QuicheStringPiece filename, std::string* dat return true; } -void QuicRecordTraceImpl(quiche::QuicheStringPiece identifier, quiche::QuicheStringPiece data) { +// NOLINTNEXTLINE(readability-identifier-naming) +void QuicRecordTraceImpl(absl::string_view identifier, absl::string_view data) { const testing::TestInfo* test_info = testing::UnitTest::GetInstance()->current_test_info(); std::string timestamp = absl::FormatTime("%Y%m%d%H%M%S", absl::Now(), absl::LocalTimeZone()); @@ -104,7 +107,7 @@ void QuicRecordTraceImpl(quiche::QuicheStringPiece identifier, quiche::QuicheStr std::string filename = fmt::sprintf("%s.%s.%s.%s.qtr", test_info->name(), test_info->test_case_name(), identifier.data(), timestamp); - QuicRecordTestOutputToFile(filename, data); + quicRecordTestOutputToFile(filename, data); } } // namespace quic diff --git a/test/extensions/quic_listeners/quiche/platform/quic_test_output_impl.h b/test/extensions/quic_listeners/quiche/platform/quic_test_output_impl.h index a1c6c7305d484..fcf0c47b3a75a 100644 --- a/test/extensions/quic_listeners/quiche/platform/quic_test_output_impl.h +++ b/test/extensions/quic_listeners/quiche/platform/quic_test_output_impl.h @@ -6,14 +6,16 @@ // consumed or referenced directly by other Envoy code. It serves purely as a // porting layer for QUICHE. -#include "quiche/common/platform/api/quiche_string_piece.h" +#include "absl/strings/string_view.h" namespace quic { +// NOLINTNEXTLINE(readability-identifier-naming) +void QuicSaveTestOutputImpl(absl::string_view filename, absl::string_view data); -void QuicSaveTestOutputImpl(quiche::QuicheStringPiece filename, quiche::QuicheStringPiece data); +// NOLINTNEXTLINE(readability-identifier-naming) +bool QuicLoadTestOutputImpl(absl::string_view filename, std::string* data); -bool QuicLoadTestOutputImpl(quiche::QuicheStringPiece filename, std::string* data); - -void QuicRecordTraceImpl(quiche::QuicheStringPiece identifier, quiche::QuicheStringPiece data); +// NOLINTNEXTLINE(readability-identifier-naming) +void QuicRecordTraceImpl(absl::string_view identifier, absl::string_view data); } // namespace quic diff --git a/test/extensions/quic_listeners/quiche/platform/quiche_platform_test.cc b/test/extensions/quic_listeners/quiche/platform/quiche_platform_test.cc deleted file mode 100644 index a733894b5505c..0000000000000 --- a/test/extensions/quic_listeners/quiche/platform/quiche_platform_test.cc +++ /dev/null @@ -1,39 +0,0 @@ -// NOLINT(namespace-envoy) - -// This file is part of the QUICHE platform implementation, and is not to be -// consumed or referenced directly by other Envoy code. It serves purely as a -// porting layer for QUICHE. - -#include "gtest/gtest.h" -#include "quiche/common/platform/api/quiche_arraysize.h" -#include "quiche/common/platform/api/quiche_endian.h" -#include "quiche/common/platform/api/quiche_optional.h" -#include "quiche/common/platform/api/quiche_ptr_util.h" -#include "quiche/common/platform/api/quiche_string_piece.h" - -namespace quiche { - -TEST(QuichePlatformTest, Arraysize) { - int array[] = {0, 1, 2, 3, 4}; - EXPECT_EQ(5, QUICHE_ARRAYSIZE(array)); -} - -TEST(QuichePlatformTest, StringPiece) { - std::string s = "bar"; - QuicheStringPiece sp(s); - EXPECT_EQ('b', sp[0]); -} - -TEST(QuichePlatformTest, WrapUnique) { - auto p = QuicheWrapUnique(new int(6)); - EXPECT_EQ(6, *p); -} - -TEST(QuichePlatformTest, TestQuicheOptional) { - QuicheOptional maybe_a; - EXPECT_FALSE(maybe_a.has_value()); - maybe_a = 1; - EXPECT_EQ(1, *maybe_a); -} - -} // namespace quiche diff --git a/test/extensions/quic_listeners/quiche/platform/spdy_platform_test.cc b/test/extensions/quic_listeners/quiche/platform/spdy_platform_test.cc index 56453e232c1ac..eeae58c0ab26e 100644 --- a/test/extensions/quic_listeners/quiche/platform/spdy_platform_test.cc +++ b/test/extensions/quic_listeners/quiche/platform/spdy_platform_test.cc @@ -8,7 +8,6 @@ #include "gtest/gtest.h" #include "quiche/spdy/platform/api/spdy_bug_tracker.h" #include "quiche/spdy/platform/api/spdy_containers.h" -#include "quiche/spdy/platform/api/spdy_endianness_util.h" #include "quiche/spdy/platform/api/spdy_estimate_memory_usage.h" #include "quiche/spdy/platform/api/spdy_flags.h" #include "quiche/spdy/platform/api/spdy_logging.h" @@ -47,11 +46,6 @@ TEST(SpdyPlatformTest, SpdyHashSet) { EXPECT_EQ(0, hset.count("qux")); } -TEST(SpdyPlatformTest, SpdyEndianness) { - EXPECT_EQ(0x1234, spdy::SpdyNetToHost16(spdy::SpdyHostToNet16(0x1234))); - EXPECT_EQ(0x12345678, spdy::SpdyNetToHost32(spdy::SpdyHostToNet32(0x12345678))); -} - TEST(SpdyPlatformTest, SpdyEstimateMemoryUsage) { std::string s = "foo"; // Stubbed out to always return 0. @@ -92,19 +86,19 @@ TEST(SpdyPlatformTest, SpdyTestHelpers) { } TEST(SpdyPlatformTest, SpdyFlags) { - auto& flag_registry = quiche::FlagRegistry::GetInstance(); - flag_registry.ResetFlags(); + auto& flag_registry = quiche::FlagRegistry::getInstance(); + flag_registry.resetFlags(); EXPECT_FALSE(GetSpdyReloadableFlag(spdy_testonly_default_false)); EXPECT_FALSE(GetSpdyRestartFlag(spdy_testonly_default_false)); - flag_registry.FindFlag("spdy_reloadable_flag_spdy_testonly_default_false") - ->SetValueFromString("true"); + flag_registry.findFlag("FLAGS_quic_reloadable_flag_spdy_testonly_default_false") + ->setValueFromString("true"); EXPECT_TRUE(GetSpdyReloadableFlag(spdy_testonly_default_false)); EXPECT_FALSE(GetSpdyRestartFlag(spdy_testonly_default_false)); - flag_registry.ResetFlags(); - flag_registry.FindFlag("spdy_restart_flag_spdy_testonly_default_false") - ->SetValueFromString("yes"); + flag_registry.resetFlags(); + flag_registry.findFlag("FLAGS_quic_restart_flag_spdy_testonly_default_false") + ->setValueFromString("yes"); EXPECT_FALSE(GetSpdyReloadableFlag(spdy_testonly_default_false)); EXPECT_TRUE(GetSpdyRestartFlag(spdy_testonly_default_false)); } diff --git a/test/extensions/quic_listeners/quiche/quic_io_handle_wrapper_test.cc b/test/extensions/quic_listeners/quiche/quic_io_handle_wrapper_test.cc index da1d7b1aeae5d..7a711ef39d655 100644 --- a/test/extensions/quic_listeners/quiche/quic_io_handle_wrapper_test.cc +++ b/test/extensions/quic_listeners/quiche/quic_io_handle_wrapper_test.cc @@ -77,18 +77,19 @@ TEST_F(QuicIoHandleWrapperTest, DelegateIoHandleCalls) { addr = wrapper_->peerAddress(); Network::IoHandle::RecvMsgOutput output(1, nullptr); - EXPECT_CALL(os_sys_calls_, recvmsg(fd, _, 0)).WillOnce(Invoke([](os_fd_t, msghdr* msg, int) { - sockaddr_storage ss; - auto ipv6_addr = reinterpret_cast(&ss); - memset(ipv6_addr, 0, sizeof(sockaddr_in6)); - ipv6_addr->sin6_family = AF_INET6; - ipv6_addr->sin6_addr = in6addr_loopback; - ipv6_addr->sin6_port = htons(54321); - *reinterpret_cast(msg->msg_name) = *ipv6_addr; - msg->msg_namelen = sizeof(sockaddr_in6); - msg->msg_controllen = 0; - return Api::SysCallSizeResult{5u, 0}; - })); + EXPECT_CALL(os_sys_calls_, recvmsg(fd, _, MSG_TRUNC)) + .WillOnce(Invoke([](os_fd_t, msghdr* msg, int) { + sockaddr_storage ss; + auto ipv6_addr = reinterpret_cast(&ss); + memset(ipv6_addr, 0, sizeof(sockaddr_in6)); + ipv6_addr->sin6_family = AF_INET6; + ipv6_addr->sin6_addr = in6addr_loopback; + ipv6_addr->sin6_port = htons(54321); + *reinterpret_cast(msg->msg_name) = *ipv6_addr; + msg->msg_namelen = sizeof(sockaddr_in6); + msg->msg_controllen = 0; + return Api::SysCallSizeResult{5u, 0}; + })); wrapper_->recvmsg(&slice, 1, /*self_port=*/12345, output); size_t num_packet_per_call = 1u; @@ -97,7 +98,7 @@ TEST_F(QuicIoHandleWrapperTest, DelegateIoHandleCalls) { absl::FixedArray({Buffer::RawSlice{data, 5}})); EXPECT_CALL(os_sys_calls_, recvmmsg(fd, _, num_packet_per_call, _, nullptr)) .WillOnce(Invoke([](os_fd_t, struct mmsghdr*, unsigned int, int, struct timespec*) { - return Api::SysCallIntResult{1u, 0}; + return Api::SysCallIntResult{-1, SOCKET_ERROR_AGAIN}; })); wrapper_->recvmmsg(slices, /*self_port=*/12345, output2); diff --git a/test/extensions/quic_listeners/quiche/test_proof_source.h b/test/extensions/quic_listeners/quiche/test_proof_source.h index a249b43144fdc..bbedfd6c7b00b 100644 --- a/test/extensions/quic_listeners/quiche/test_proof_source.h +++ b/test/extensions/quic_listeners/quiche/test_proof_source.h @@ -36,7 +36,7 @@ class TestProofSource : public EnvoyQuicProofSourceBase { void signPayload(const quic::QuicSocketAddress& /*server_address*/, const quic::QuicSocketAddress& /*client_address*/, const std::string& /*hostname*/, uint16_t /*signature_algorithm*/, - quiche::QuicheStringPiece in, + absl::string_view in, std::unique_ptr callback) override { callback->Run(true, absl::StrCat("Fake signature for { ", in, " }"), std::make_unique(filter_chain_)); diff --git a/test/extensions/quic_listeners/quiche/test_utils.h b/test/extensions/quic_listeners/quiche/test_utils.h index 102f7608e50b9..f59720130c70d 100644 --- a/test/extensions/quic_listeners/quiche/test_utils.h +++ b/test/extensions/quic_listeners/quiche/test_utils.h @@ -13,6 +13,8 @@ #include "quiche/quic/core/quic_utils.h" #include "quiche/quic/test_tools/crypto_test_utils.h" #include "quiche/quic/test_tools/quic_config_peer.h" +#include "quiche/quic/test_tools/qpack/qpack_test_utils.h" +#include "quiche/quic/test_tools/qpack/qpack_encoder_test_utils.h" #if defined(__GNUC__) #pragma GCC diagnostic pop @@ -46,7 +48,7 @@ class MockEnvoyQuicSession : public quic::QuicSpdySession, public QuicFilterMana MOCK_METHOD(quic::QuicConsumedData, WritevData, (quic::QuicStreamId id, size_t write_length, quic::QuicStreamOffset offset, quic::StreamSendingState state, quic::TransmissionType type, - quiche::QuicheOptional level)); + absl::optional level)); MOCK_METHOD(bool, ShouldYield, (quic::QuicStreamId id)); absl::string_view requestedServerName() const override { @@ -90,7 +92,7 @@ class MockEnvoyQuicClientSession : public quic::QuicSpdyClientSession, MOCK_METHOD(quic::QuicConsumedData, WritevData, (quic::QuicStreamId id, size_t write_length, quic::QuicStreamOffset offset, quic::StreamSendingState state, quic::TransmissionType type, - quiche::QuicheOptional level)); + absl::optional level)); MOCK_METHOD(bool, ShouldYield, (quic::QuicStreamId id)); absl::string_view requestedServerName() const override { @@ -167,6 +169,29 @@ enum class QuicVersionType { Iquic, }; +std::string spdyHeaderToHttp3StreamPayload(const spdy::SpdyHeaderBlock& header) { + quic::test::NoopQpackStreamSenderDelegate encoder_stream_sender_delegate; + quic::test::NoopDecoderStreamErrorDelegate decoder_stream_error_delegate; + auto qpack_encoder = std::make_unique(&decoder_stream_error_delegate); + qpack_encoder->set_qpack_stream_sender_delegate(&encoder_stream_sender_delegate); + // QpackEncoder does not use the dynamic table by default, + // therefore the value of |stream_id| does not matter. + std::string payload = qpack_encoder->EncodeHeaderList(/* stream_id = */ 0, header, nullptr); + std::unique_ptr headers_buffer; + quic::QuicByteCount headers_frame_header_length = + quic::HttpEncoder::SerializeHeadersFrameHeader(payload.length(), &headers_buffer); + absl::string_view headers_frame_header(headers_buffer.get(), headers_frame_header_length); + return absl::StrCat(headers_frame_header, payload); +} + +std::string bodyToHttp3StreamPayload(const std::string& body) { + std::unique_ptr data_buffer; + quic::QuicByteCount data_frame_header_length = + quic::HttpEncoder::SerializeDataFrameHeader(body.length(), &data_buffer); + absl::string_view data_frame_header(data_buffer.get(), data_frame_header_length); + return absl::StrCat(data_frame_header, body); +} + // A test suite with variation of ip version and a knob to turn on/off IETF QUIC implementation. class QuicMultiVersionTest : public testing::TestWithParam> {}; diff --git a/test/extensions/stats_sinks/hystrix/hystrix_test.cc b/test/extensions/stats_sinks/hystrix/hystrix_test.cc index 29e7c79d02da5..38f88019602cf 100644 --- a/test/extensions/stats_sinks/hystrix/hystrix_test.cc +++ b/test/extensions/stats_sinks/hystrix/hystrix_test.cc @@ -128,9 +128,9 @@ class HystrixSinkTest : public testing::Test { void createClusterAndCallbacks() { // Set cluster. - cluster_map_.emplace(cluster1_name_, cluster1_.cluster_); + cluster_maps_.active_clusters_.emplace(cluster1_name_, cluster1_.cluster_); ON_CALL(server_, clusterManager()).WillByDefault(ReturnRef(cluster_manager_)); - ON_CALL(cluster_manager_, clusters()).WillByDefault(Return(cluster_map_)); + ON_CALL(cluster_manager_, clusters()).WillByDefault(Return(cluster_maps_)); ON_CALL(callbacks_, encodeData(_, _)).WillByDefault(Invoke([&](Buffer::Instance& data, bool) { // Set callbacks to send data to buffer. This will append to the end of the buffer, so @@ -141,15 +141,15 @@ class HystrixSinkTest : public testing::Test { void addClusterToMap(const std::string& cluster_name, NiceMock& cluster) { - cluster_map_.emplace(cluster_name, cluster); - // Redefining since cluster_map_ is returned by value. - ON_CALL(cluster_manager_, clusters()).WillByDefault(Return(cluster_map_)); + cluster_maps_.active_clusters_.emplace(cluster_name, cluster); + // Redefining since cluster_maps_ is returned by value. + ON_CALL(cluster_manager_, clusters()).WillByDefault(Return(cluster_maps_)); } void removeClusterFromMap(const std::string& cluster_name) { - cluster_map_.erase(cluster_name); - // Redefining since cluster_map_ is returned by value. - ON_CALL(cluster_manager_, clusters()).WillByDefault(Return(cluster_map_)); + cluster_maps_.active_clusters_.erase(cluster_name); + // Redefining since cluster_maps_ is returned by value. + ON_CALL(cluster_manager_, clusters()).WillByDefault(Return(cluster_maps_)); } void addSecondClusterHelper(Buffer::OwnedImpl& buffer) { @@ -245,7 +245,7 @@ class HystrixSinkTest : public testing::Test { NiceMock callbacks_; NiceMock server_; - Upstream::ClusterManager::ClusterInfoMap cluster_map_; + Upstream::ClusterManager::ClusterInfoMaps cluster_maps_; Buffer::OwnedImpl cluster_stats_buffer_; std::unique_ptr sink_; diff --git a/test/extensions/stats_sinks/wasm/BUILD b/test/extensions/stats_sinks/wasm/BUILD index 6135c8cfcf0a4..b0911d7aaa9f6 100644 --- a/test/extensions/stats_sinks/wasm/BUILD +++ b/test/extensions/stats_sinks/wasm/BUILD @@ -24,6 +24,7 @@ envoy_extension_cc_test( extension_name = "envoy.stat_sinks.wasm", deps = [ "//source/extensions/stat_sinks/wasm:config", + "//test/extensions/common/wasm:wasm_runtime", "//test/extensions/stats_sinks/wasm/test_data:test_context_cpp_plugin", "//test/mocks/server:server_mocks", "@envoy_api//envoy/extensions/stat_sinks/wasm/v3:pkg_cc_proto", @@ -41,6 +42,7 @@ envoy_extension_cc_test( deps = [ "//source/common/stats:stats_lib", "//source/extensions/common/wasm:wasm_lib", + "//test/extensions/common/wasm:wasm_runtime", "//test/extensions/stats_sinks/wasm/test_data:test_context_cpp_plugin", "//test/mocks/stats:stats_mocks", "//test/test_common:wasm_lib", diff --git a/test/extensions/stats_sinks/wasm/config_test.cc b/test/extensions/stats_sinks/wasm/config_test.cc index d9b1263215afd..012f4ecc2c982 100644 --- a/test/extensions/stats_sinks/wasm/config_test.cc +++ b/test/extensions/stats_sinks/wasm/config_test.cc @@ -8,6 +8,7 @@ #include "extensions/stat_sinks/wasm/wasm_stat_sink_impl.h" #include "extensions/stat_sinks/well_known_names.h" +#include "test/extensions/common/wasm/wasm_runtime.h" #include "test/mocks/server/mocks.h" #include "test/test_common/environment.h" #include "test/test_common/printers.h" @@ -65,20 +66,8 @@ class WasmStatSinkConfigTest : public testing::TestWithParam { Stats::SinkPtr sink_; }; -// NB: this is required by VC++ which can not handle the use of macros in the macro definitions -// used by INSTANTIATE_TEST_SUITE_P. -auto testing_values = testing::Values( -#if defined(ENVOY_WASM_V8) - "v8", -#endif -#if defined(ENVOY_WASM_WAVM) - "wavm", -#endif -#if defined(ENVOY_WASM_WASMTIME) - "wasmtime", -#endif - "null"); -INSTANTIATE_TEST_SUITE_P(Runtimes, WasmStatSinkConfigTest, testing_values); +INSTANTIATE_TEST_SUITE_P(Runtimes, WasmStatSinkConfigTest, + Envoy::Extensions::Common::Wasm::runtime_values); TEST_P(WasmStatSinkConfigTest, CreateWasmFromEmpty) { envoy::extensions::stat_sinks::wasm::v3::Wasm config; diff --git a/test/extensions/stats_sinks/wasm/wasm_stat_sink_test.cc b/test/extensions/stats_sinks/wasm/wasm_stat_sink_test.cc index 716925bfd12fc..db9f4108aedd5 100644 --- a/test/extensions/stats_sinks/wasm/wasm_stat_sink_test.cc +++ b/test/extensions/stats_sinks/wasm/wasm_stat_sink_test.cc @@ -2,6 +2,7 @@ #include "extensions/common/wasm/wasm.h" +#include "test/extensions/common/wasm/wasm_runtime.h" #include "test/mocks/upstream/mocks.h" #include "test/test_common/wasm_base.h" @@ -54,20 +55,8 @@ class WasmCommonContextTest std::unique_ptr context_; }; -// NB: this is required by VC++ which can not handle the use of macros in the macro definitions -// used by INSTANTIATE_TEST_SUITE_P. -auto testing_values = testing::Values( -#if defined(ENVOY_WASM_V8) - "v8", -#endif -#if defined(ENVOY_WASM_WAVM) - "wavm", -#endif -#if defined(ENVOY_WASM_WASMTIME) - "wasmtime", -#endif - "null"); -INSTANTIATE_TEST_SUITE_P(Runtimes, WasmCommonContextTest, testing_values); +INSTANTIATE_TEST_SUITE_P(Runtimes, WasmCommonContextTest, + Envoy::Extensions::Common::Wasm::runtime_values); TEST_P(WasmCommonContextTest, OnStat) { std::string code; diff --git a/test/extensions/transport_sockets/tls/ssl_socket_test.cc b/test/extensions/transport_sockets/tls/ssl_socket_test.cc index 403a08b61c3a5..774b57116d58e 100644 --- a/test/extensions/transport_sockets/tls/ssl_socket_test.cc +++ b/test/extensions/transport_sockets/tls/ssl_socket_test.cc @@ -4724,6 +4724,7 @@ TEST_P(SslSocketTest, DownstreamNotReadySslSocket) { auto transport_socket = server_ssl_socket_factory.createTransportSocket(nullptr); EXPECT_EQ(EMPTY_STRING, transport_socket->protocol()); EXPECT_EQ(nullptr, transport_socket->ssl()); + EXPECT_EQ(true, transport_socket->canFlushClose()); Buffer::OwnedImpl buffer; Network::IoResult result = transport_socket->doRead(buffer); EXPECT_EQ(Network::PostIoAction::Close, result.action_); @@ -4759,6 +4760,7 @@ TEST_P(SslSocketTest, UpstreamNotReadySslSocket) { auto transport_socket = client_ssl_socket_factory.createTransportSocket(nullptr); EXPECT_EQ(EMPTY_STRING, transport_socket->protocol()); EXPECT_EQ(nullptr, transport_socket->ssl()); + EXPECT_EQ(true, transport_socket->canFlushClose()); Buffer::OwnedImpl buffer; Network::IoResult result = transport_socket->doRead(buffer); EXPECT_EQ(Network::PostIoAction::Close, result.action_); diff --git a/test/integration/BUILD b/test/integration/BUILD index db3e796099c6e..bdda083b3999a 100644 --- a/test/integration/BUILD +++ b/test/integration/BUILD @@ -1069,10 +1069,14 @@ envoy_cc_test( ":http_integration_lib", "//source/common/buffer:buffer_lib", "//source/common/http:codec_client_lib", + "//source/extensions/access_loggers/file:config", "//source/extensions/filters/listener/proxy_protocol:config", + "//source/extensions/filters/network/tcp_proxy:config", "//test/test_common:utility_lib", "@envoy_api//envoy/config/bootstrap/v3:pkg_cc_proto", "@envoy_api//envoy/config/cluster/v3:pkg_cc_proto", + "@envoy_api//envoy/extensions/access_loggers/file/v3:pkg_cc_proto", + "@envoy_api//envoy/extensions/filters/network/tcp_proxy/v3:pkg_cc_proto", ], ) @@ -1139,8 +1143,13 @@ envoy_cc_test( "sds_dynamic_integration_test.cc", ], data = [ + "sds_dynamic_key_rotation_setup.sh", "//test/config/integration/certs", ], + # TODO(envoyproxy/windows-dev): The key rotation in SdsDynamicKeyRotationIntegrationTest via + # TestEnvironment::renameFile() fails on Windows. The renameFile() implementation does not + # correctly handle symlinks. + tags = ["fails_on_windows"], deps = [ ":http_integration_lib", "//source/common/config:api_version_lib", @@ -1591,3 +1600,19 @@ envoy_cc_test( "@envoy_api//envoy/config/core/v3:pkg_cc_proto", ], ) + +envoy_cc_test( + name = "cluster_upstream_extension_integration_test", + srcs = [ + "cluster_upstream_extension_integration_test.cc", + ], + deps = [ + ":http_integration_lib", + "//source/common/config:api_version_lib", + "//source/common/protobuf", + "//test/integration/upstreams:per_host_upstream_config", + "//test/test_common:utility_lib", + "@envoy_api//envoy/config/bootstrap/v3:pkg_cc_proto", + "@envoy_api//envoy/extensions/filters/network/http_connection_manager/v3:pkg_cc_proto", + ], +) diff --git a/test/integration/ads_integration_test.cc b/test/integration/ads_integration_test.cc index 3fc55beb56e20..24468b45f20f7 100644 --- a/test/integration/ads_integration_test.cc +++ b/test/integration/ads_integration_test.cc @@ -553,8 +553,9 @@ TEST_P(AdsIntegrationTest, CdsPausedDuringWarming) { // Send the second warming cluster. sendDiscoveryResponse( - Config::TypeUrl::get().Cluster, {buildCluster("warming_cluster_2")}, - {buildCluster("warming_cluster_2")}, {}, "3"); + Config::TypeUrl::get().Cluster, + {buildCluster("warming_cluster_1"), buildCluster("warming_cluster_2")}, + {buildCluster("warming_cluster_1"), buildCluster("warming_cluster_2")}, {}, "3"); test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 2); // We would've got a Cluster discovery request with version 2 here, had the CDS not been paused. @@ -586,6 +587,87 @@ TEST_P(AdsIntegrationTest, CdsPausedDuringWarming) { {"warming_cluster_2", "warming_cluster_1"}, {}, {})); } +TEST_P(AdsIntegrationTest, RemoveWarmingCluster) { + initialize(); + + // Send initial configuration, validate we can process a request. + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "", {}, {}, {}, true)); + sendDiscoveryResponse(Config::TypeUrl::get().Cluster, + {buildCluster("cluster_0")}, + {buildCluster("cluster_0")}, {}, "1"); + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().ClusterLoadAssignment, "", + {"cluster_0"}, {"cluster_0"}, {})); + + sendDiscoveryResponse( + Config::TypeUrl::get().ClusterLoadAssignment, {buildClusterLoadAssignment("cluster_0")}, + {buildClusterLoadAssignment("cluster_0")}, {}, "1"); + + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "1", {}, {}, {})); + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Listener, "", {}, {}, {})); + sendDiscoveryResponse( + Config::TypeUrl::get().Listener, {buildListener("listener_0", "route_config_0")}, + {buildListener("listener_0", "route_config_0")}, {}, "1"); + + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().ClusterLoadAssignment, "1", + {"cluster_0"}, {}, {})); + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().RouteConfiguration, "", + {"route_config_0"}, {"route_config_0"}, {})); + sendDiscoveryResponse( + Config::TypeUrl::get().RouteConfiguration, {buildRouteConfig("route_config_0", "cluster_0")}, + {buildRouteConfig("route_config_0", "cluster_0")}, {}, "1"); + + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Listener, "1", {}, {}, {})); + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().RouteConfiguration, "1", + {"route_config_0"}, {}, {})); + + test_server_->waitForCounterGe("listener_manager.listener_create_success", 1); + makeSingleRequest(); + + // Send the first warming cluster. + sendDiscoveryResponse( + Config::TypeUrl::get().Cluster, {buildCluster("warming_cluster_1")}, + {buildCluster("warming_cluster_1")}, {"cluster_0"}, "2"); + + test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 1); + + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().ClusterLoadAssignment, "1", + {"warming_cluster_1"}, {"warming_cluster_1"}, {"cluster_0"})); + + // Send the second warming cluster and remove the first cluster. + sendDiscoveryResponse(Config::TypeUrl::get().Cluster, + {buildCluster("warming_cluster_2")}, + {buildCluster("warming_cluster_2")}, + // Delta: remove warming_cluster_1. + {"warming_cluster_1"}, "3"); + test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 1); + // We would've got a Cluster discovery request with version 2 here, had the CDS not been paused. + + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().ClusterLoadAssignment, "1", + {"warming_cluster_2"}, {"warming_cluster_2"}, + {"warming_cluster_1"})); + + // Finish warming the clusters. Note that the first warming cluster is not included in the + // response. + sendDiscoveryResponse( + Config::TypeUrl::get().ClusterLoadAssignment, + {buildClusterLoadAssignment("warming_cluster_2")}, + {buildClusterLoadAssignment("warming_cluster_2")}, {"cluster_0"}, "2"); + + // Validate that all clusters are warmed. + test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 0); + test_server_->waitForGaugeEq("cluster_manager.active_clusters", 3); + + // CDS is resumed and EDS response was acknowledged. + if (sotw_or_delta_ == Grpc::SotwOrDelta::Delta) { + // Envoy will ACK both Cluster messages. Since they arrived while CDS was paused, they aren't + // sent until CDS is unpaused. Since version 3 has already arrived by the time the version 2 + // ACK goes out, they're both acknowledging version 3. + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "3", {}, {}, {})); + } + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "3", {}, {}, {})); + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().ClusterLoadAssignment, "2", + {"warming_cluster_2"}, {}, {})); +} // Validate that warming listeners are removed when left out of SOTW update. TEST_P(AdsIntegrationTest, RemoveWarmingListener) { initialize(); @@ -696,8 +778,9 @@ TEST_P(AdsIntegrationTest, ClusterWarmingOnNamedResponse) { // Send the second warming cluster. sendDiscoveryResponse( - Config::TypeUrl::get().Cluster, {buildCluster("warming_cluster_2")}, - {buildCluster("warming_cluster_2")}, {}, "3"); + Config::TypeUrl::get().Cluster, + {buildCluster("warming_cluster_1"), buildCluster("warming_cluster_2")}, + {buildCluster("warming_cluster_1"), buildCluster("warming_cluster_2")}, {}, "3"); test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 2); EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().ClusterLoadAssignment, "1", @@ -1359,8 +1442,8 @@ TEST_P(AdsClusterV2Test, CdsPausedDuringWarming) { // Send the second warming cluster. sendDiscoveryResponse( - cds_type_url, {buildCluster("warming_cluster_2")}, {buildCluster("warming_cluster_2")}, {}, - "3", true); + cds_type_url, {buildCluster("warming_cluster_1"), buildCluster("warming_cluster_2")}, + {buildCluster("warming_cluster_1"), buildCluster("warming_cluster_2")}, {}, "3", true); test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 2); // We would've got a Cluster discovery request with version 2 here, had the CDS not been paused. @@ -1438,4 +1521,21 @@ TEST_P(AdsClusterV2Test, XdsBatching) { initialize(); } +// Regression test for https://github.com/envoyproxy/envoy/issues/13681. +TEST_P(AdsClusterV2Test, TypeUrlAnnotationRegression) { + initialize(); + const auto cds_type_url = Config::getTypeUrl( + envoy::config::core::v3::ApiVersion::V2); + + EXPECT_TRUE(compareDiscoveryRequest(cds_type_url, "", {}, {}, {}, true)); + auto cluster = buildCluster("cluster_0"); + auto* bias = cluster.mutable_least_request_lb_config()->mutable_active_request_bias(); + bias->set_default_value(1.1); + bias->set_runtime_key("foo"); + sendDiscoveryResponse(cds_type_url, {cluster}, {cluster}, {}, + "1", true); + + test_server_->waitForCounterGe("cluster_manager.cds.update_rejected", 1); +} + } // namespace Envoy diff --git a/test/integration/autonomous_upstream.h b/test/integration/autonomous_upstream.h index 6f82fac9a5f6b..385d275ea5be5 100644 --- a/test/integration/autonomous_upstream.h +++ b/test/integration/autonomous_upstream.h @@ -30,11 +30,11 @@ class AutonomousStream : public FakeStream { AutonomousUpstream& upstream, bool allow_incomplete_streams); ~AutonomousStream() override; - void setEndStream(bool set) EXCLUSIVE_LOCKS_REQUIRED(lock_) override; + void setEndStream(bool set) ABSL_EXCLUSIVE_LOCKS_REQUIRED(lock_) override; private: AutonomousUpstream& upstream_; - void sendResponse() EXCLUSIVE_LOCKS_REQUIRED(lock_); + void sendResponse() ABSL_EXCLUSIVE_LOCKS_REQUIRED(lock_); const bool allow_incomplete_streams_{false}; std::unique_ptr pre_response_headers_metadata_; }; diff --git a/test/integration/base_integration_test.cc b/test/integration/base_integration_test.cc index b5f8ddb1cf84f..e29876d01d7f3 100644 --- a/test/integration/base_integration_test.cc +++ b/test/integration/base_integration_test.cc @@ -45,7 +45,7 @@ using ::testing::ReturnRef; BaseIntegrationTest::BaseIntegrationTest(const InstanceConstSharedPtrFn& upstream_address_fn, Network::Address::IpVersion version, const std::string& config) - : api_(Api::createApiForTest(stats_store_)), + : api_(Api::createApiForTest(stats_store_, time_system_)), mock_buffer_factory_(new NiceMock), dispatcher_(api_->allocateDispatcher("test_thread", Buffer::WatermarkFactoryPtr{mock_buffer_factory_})), diff --git a/test/integration/cluster_upstream_extension_integration_test.cc b/test/integration/cluster_upstream_extension_integration_test.cc new file mode 100644 index 0000000000000..f0c6e0ddb3e0e --- /dev/null +++ b/test/integration/cluster_upstream_extension_integration_test.cc @@ -0,0 +1,92 @@ +#include "envoy/config/bootstrap/v3/bootstrap.pb.h" +#include "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.h" +#include "envoy/registry/registry.h" +#include "envoy/router/router.h" + +#include "common/buffer/buffer_impl.h" + +#include "test/integration/fake_upstream.h" +#include "test/integration/http_integration.h" +#include "test/integration/upstreams/per_host_upstream_config.h" +#include "test/test_common/registry.h" + +#include "gtest/gtest.h" + +namespace Envoy { + +namespace { +class ClusterUpstreamExtensionIntegrationTest + : public testing::TestWithParam, + public HttpIntegrationTest { +public: + ClusterUpstreamExtensionIntegrationTest() + : HttpIntegrationTest(Http::CodecClient::Type::HTTP1, GetParam()) {} + + void populateMetadataTestData(envoy::config::core::v3::Metadata& metadata, + const std::string& key1, const std::string& key2, + const std::string& value) { + + ProtobufWkt::Struct struct_obj; + (*struct_obj.mutable_fields())[key2] = ValueUtil::stringValue(value); + (*metadata.mutable_filter_metadata())[key1] = struct_obj; + } + + void initialize() override { + config_helper_.addConfigModifier([this](envoy::config::bootstrap::v3::Bootstrap& bootstrap) { + auto* cluster = bootstrap.mutable_static_resources()->mutable_clusters(0); + cluster->mutable_upstream_config()->set_name("envoy.filters.connection_pools.http.per_host"); + cluster->mutable_upstream_config()->mutable_typed_config(); + populateMetadataTestData(*cluster->mutable_metadata(), "foo", "bar", "cluster-value"); + populateMetadataTestData(*cluster->mutable_load_assignment() + ->mutable_endpoints(0) + ->mutable_lb_endpoints(0) + ->mutable_metadata(), + "foo", "bar", "host-value"); + }); + HttpIntegrationTest::initialize(); + } + PerHostGenericConnPoolFactory per_host_upstream_factory_; +}; + +INSTANTIATE_TEST_SUITE_P(IpVersions, ClusterUpstreamExtensionIntegrationTest, + testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), + TestUtility::ipTestParamsToString); + +// This test verifies that cluster upstream extensions can fulfill the requirement that they rewrite +// http headers after cluster and host are selected. See +// https://github.com/envoyproxy/envoy/issues/12236 This test case should be rewritten once upstream +// http filters(https://github.com/envoyproxy/envoy/issues/10455) is landed. +TEST_P(ClusterUpstreamExtensionIntegrationTest, + VerifyRequestHeadersAreRewrittenByClusterAndHostMetadata) { + initialize(); + Registry::InjectFactory registration(per_host_upstream_factory_); + + codec_client_ = makeHttpConnection(lookupPort("http")); + auto response = sendRequestAndWaitForResponse( + default_request_headers_, 0, Http::TestResponseHeaderMapImpl{{":status", "200"}}, 0); + EXPECT_TRUE(upstream_request_->complete()); + + { + const auto header_values = upstream_request_->headers().get(Http::LowerCaseString("X-foo")); + ASSERT_EQ(1, header_values.size()); + EXPECT_EQ("foo-common", header_values[0]->value().getStringView()); + } + { + const auto cluster_header_values = + upstream_request_->headers().get(Http::LowerCaseString("X-cluster-foo")); + ASSERT_EQ(1, cluster_header_values.size()); + EXPECT_EQ("cluster-value", cluster_header_values[0]->value().getStringView()); + } + { + const auto host_header_values = + upstream_request_->headers().get(Http::LowerCaseString("X-host-foo")); + ASSERT_EQ(1, host_header_values.size()); + EXPECT_EQ("host-value", host_header_values[0]->value().getStringView()); + } + + response->waitForEndStream(); + ASSERT_TRUE(response->complete()); + EXPECT_EQ("200", response->headers().getStatusValue()); +} +} // namespace +} // namespace Envoy diff --git a/test/integration/custom_cluster_integration_test.cc b/test/integration/custom_cluster_integration_test.cc index 62d5cac5ab9ff..84c936e006c56 100644 --- a/test/integration/custom_cluster_integration_test.cc +++ b/test/integration/custom_cluster_integration_test.cc @@ -69,10 +69,10 @@ TEST_P(CustomClusterIntegrationTest, TestCustomConfig) { initialize(); // Verify the cluster is correctly setup with the custom priority - const auto& cluster_map = test_server_->server().clusterManager().clusters(); - EXPECT_EQ(1, cluster_map.size()); - EXPECT_EQ(1, cluster_map.count("cluster_0")); - const auto& cluster_ref = cluster_map.find("cluster_0")->second; + const auto& cluster_maps = test_server_->server().clusterManager().clusters(); + EXPECT_EQ(1, cluster_maps.active_clusters_.size()); + EXPECT_EQ(1, cluster_maps.active_clusters_.count("cluster_0")); + const auto& cluster_ref = cluster_maps.active_clusters_.find("cluster_0")->second; const auto& hostset_per_priority = cluster_ref.get().prioritySet().hostSetsPerPriority(); EXPECT_EQ(11, hostset_per_priority.size()); const Envoy::Upstream::HostSetPtr& host_set = hostset_per_priority[10]; diff --git a/test/integration/eds_integration_test.cc b/test/integration/eds_integration_test.cc index 3e1c237e7c597..b8ca3c6f07c2a 100644 --- a/test/integration/eds_integration_test.cc +++ b/test/integration/eds_integration_test.cc @@ -316,9 +316,9 @@ TEST_P(EdsIntegrationTest, OverprovisioningFactorUpdate) { setEndpoints(4, 4, 0); auto get_and_compare = [this](const uint32_t expected_factor) { const auto& cluster_map = test_server_->server().clusterManager().clusters(); - EXPECT_EQ(1, cluster_map.size()); - EXPECT_EQ(1, cluster_map.count("cluster_0")); - const auto& cluster_ref = cluster_map.find("cluster_0")->second; + EXPECT_EQ(1, cluster_map.active_clusters_.size()); + EXPECT_EQ(1, cluster_map.active_clusters_.count("cluster_0")); + const auto& cluster_ref = cluster_map.active_clusters_.find("cluster_0")->second; const auto& hostset_per_priority = cluster_ref.get().prioritySet().hostSetsPerPriority(); EXPECT_EQ(1, hostset_per_priority.size()); const Envoy::Upstream::HostSetPtr& host_set = hostset_per_priority[0]; @@ -340,7 +340,7 @@ TEST_P(EdsIntegrationTest, BatchMemberUpdateCb) { auto& priority_set = test_server_->server() .clusterManager() .clusters() - .find("cluster_0") + .active_clusters_.find("cluster_0") ->second.get() .prioritySet(); diff --git a/test/integration/fake_upstream.cc b/test/integration/fake_upstream.cc index c5961ebf3a596..7e2fae5dc8f38 100644 --- a/test/integration/fake_upstream.cc +++ b/test/integration/fake_upstream.cc @@ -626,6 +626,30 @@ testing::AssertionResult FakeUpstream::rawWriteConnection(uint32_t index, const timeout); } +FakeRawConnection::~FakeRawConnection() { + // If the filter was already deleted, it means the shared_connection_ was too, so don't try to + // access it. + if (auto filter = read_filter_.lock(); filter != nullptr) { + EXPECT_TRUE(shared_connection_.executeOnDispatcher( + [filter = std::move(filter)](Network::Connection& connection) { + connection.removeReadFilter(filter); + })); + } +} + +testing::AssertionResult FakeRawConnection::initialize() { + auto filter = Network::ReadFilterSharedPtr{new ReadFilter(*this)}; + read_filter_ = filter; + testing::AssertionResult result = shared_connection_.executeOnDispatcher( + [filter = std::move(filter)](Network::Connection& connection) { + connection.addReadFilter(filter); + }); + if (!result) { + return result; + } + return FakeConnectionBase::initialize(); +} + AssertionResult FakeRawConnection::waitForData(uint64_t num_bytes, std::string* data, milliseconds timeout) { absl::MutexLock lock(&lock_); diff --git a/test/integration/fake_upstream.h b/test/integration/fake_upstream.h index 091edf70478dc..b1810822fe2c3 100644 --- a/test/integration/fake_upstream.h +++ b/test/integration/fake_upstream.h @@ -209,7 +209,7 @@ class FakeStream : public Http::RequestDecoder, void onAboveWriteBufferHighWatermark() override {} void onBelowWriteBufferLowWatermark() override {} - virtual void setEndStream(bool end) EXCLUSIVE_LOCKS_REQUIRED(lock_) { end_stream_ = end; } + virtual void setEndStream(bool end) ABSL_EXCLUSIVE_LOCKS_REQUIRED(lock_) { end_stream_ = end; } Event::TestTimeSystem& timeSystem() { return time_system_; } @@ -471,6 +471,7 @@ class FakeRawConnection : public FakeConnectionBase { FakeRawConnection(SharedConnectionWrapper& shared_connection, Event::TestTimeSystem& time_system) : FakeConnectionBase(shared_connection, time_system) {} using ValidatorFunction = const std::function; + ~FakeRawConnection() override; // Writes to data. If data is nullptr, discards the received data. ABSL_MUST_USE_RESULT @@ -493,16 +494,7 @@ class FakeRawConnection : public FakeConnectionBase { std::chrono::milliseconds timeout = TestUtility::DefaultTimeout); ABSL_MUST_USE_RESULT - testing::AssertionResult initialize() override { - testing::AssertionResult result = - shared_connection_.executeOnDispatcher([this](Network::Connection& connection) { - connection.addReadFilter(Network::ReadFilterSharedPtr{new ReadFilter(*this)}); - }); - if (!result) { - return result; - } - return FakeConnectionBase::initialize(); - } + testing::AssertionResult initialize() override; // Creates a ValidatorFunction which returns true when data_to_wait_for is // contained in the incoming data string. Unlike many of Envoy waitFor functions, @@ -530,6 +522,7 @@ class FakeRawConnection : public FakeConnectionBase { }; std::string data_ ABSL_GUARDED_BY(lock_); + std::weak_ptr read_filter_; }; using FakeRawConnectionPtr = std::unique_ptr; diff --git a/test/integration/h1_corpus/alloc_headers b/test/integration/h1_corpus/alloc_headers new file mode 100644 index 0000000000000..3e8a5e62f1a8d --- /dev/null +++ b/test/integration/h1_corpus/alloc_headers @@ -0,0 +1,12 @@ +events { + downstream_send_bytes: "POST /test/long/urlaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaattttttaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa448aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa HTTP/1.1\r\nhost: host\r\nx-lyft-user-id: 0\r\nx-forwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarded-for: -1113144117.0.0.1\r\ntransfer-encoding: chunked\r\n\r\n400\r\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\234\234\234\234\234\234\234\234\234\234\234\234\234\234\234\234\234\234\234\234\234\234\234\234\234\234\234aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\344aaaaaaaaaaaaaaaaaaaaaa\r\n0\r\n\r\n" +} +events { + upstream_send_bytes: "HTTP/1.1 454 \002\002\002\002\002\002\002\002\002\002\002OK\r\ntransfer-encoding: chunked\r\n\r\n200\r\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_aaaaaaaaaaaaaaaaFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n0\r\n\r\n" +} +events { + upstream_send_bytes: "HTTP/1.1 654 \002\002\002\002\002\002\002\002\002\002\002OK\r\ntransfer-encoding: chunked\r\n\r\n200\r\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_aaaaaaaaaaaaaaaaFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n0\r\n\r\n" +} +events { + upstream_send_bytes: "HTTP/1.1 454 \002\002\002\002\002\002\002\002\002\002\002OK\r\ntransfer-encoding: chunked\r\n\r\n200\r\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_aaaaaaaaaaaaaaaaFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n0\r\n\r\n" +} diff --git a/test/integration/h2_corpus/upstream_metadata_after_end_stream b/test/integration/h2_corpus/upstream_metadata_after_end_stream new file mode 100644 index 0000000000000..02080248fb6c3 --- /dev/null +++ b/test/integration/h2_corpus/upstream_metadata_after_end_stream @@ -0,0 +1,2631 @@ +events { + downstream_send_event { + h2_frames { + settings { + } + } + h2_frames { + } + h2_frames { + request { + stream_index: 1 + host: "host" + path: "/p\237ath/to/long/url" + } + } + h2_frames { + } + h2_frames { + } + } +} +events { + downstream_send_event { + h2_frames { + metadata { + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "" + value: "" + } + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\334377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii~iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii-1620iiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377[377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\300\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q407888iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\226iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiing-\0349\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035G-3071569\341\341\341\3410110\317\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000y\177\177\177\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000\000\000\000\000GGGGGGGGGGGGGGaaaaaaaaaa(aaa\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177E\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177aaaaaaa0110Oq4078888\177\177\177\025\0278888888888888DFMing-BdaaaAaa\006nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnGGGGGGGGGGGGG\025\0278888888788888DFMing-\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGG\317\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\342\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii116377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\035\276\2546\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGHGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\034\256\235.\310S\254\222\324\006t)lN\307b1\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii8\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiQQQQQQQQQQQQQQQQQiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377?\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGGaaaaaaaaaa(aaa\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177E\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177aaaaaaa0110Oq4078888\177\177\177\025\0278888888888888DFMing-BdaaaAaaaaaaaaaaaa(aaaaaaaaaaaaaaaa88DFMing-Bdaaaaaa\363\240\201\256BBBBBaaaaaOqaG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaaaaaaaaa(aaaaaaaaaa0110Oq4078888\177\177\177\025\02788888\330\226g88888DFMing-Bdaaaaaaaaaaaaaaaa(aaaaaaaaaaaaa(aG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGG\307\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaaaaaaaa01\030\030\030EFMing-Bdaaaaaaaaaaaaaaaa(aaa|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\035/nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\003rrrrrrrrrrrrhx\331\264rrrrrrrrrrrrrrrrr6nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnGGGGGGGGGGGGG\025\0278888888788888DFMing-\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGG\317\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "10" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000+\03100\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "Timeout Seconds" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Timeout SecondSeconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\3737\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGG56\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "<\000\000\000\000\000\000\00010" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341[341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGG26G\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\034\256\235.\310S\254\222\324\006t)lN\307b1\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii8\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-00\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q407888iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiing-\0349\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035G-3071569\341\341\341\3410110\317\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "10" + value: "" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + flags: END_HEADERS + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\035\276\2546\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGHGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356666666666666666666666666666666666666666666666666666666666\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\34141\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220\360\220\220\220" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\034\256\235.\310S\254\222\324\006t)lN\307b1\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii8\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q407888iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiing-\0349\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035G-3071569\341\341\341\3410110\317\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "15" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "" + value: "" + } + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000+\03100\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377S377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "10" + value: "10" + } + metadata { + key: "Timeout Sec)onds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "Timeout Seconds" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\367\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiio\216iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + } + } + } + h2_frames { + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q407888iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiing-\0349\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035G-3071569\341\341\341\3410110\317\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "15" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "" + value: "" + } + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000+\03100\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377S377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "10" + value: "10" + } + metadata { + key: "Timeout Sec)onds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "Timeout Seconds" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\367\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\037\257\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiio\216iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "" + value: "\001\000" + } + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\273\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\035/\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrh\370\331\264rrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + } + } + h2_frames { + metadata { + flags: END_HEADERS + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGGaaaaaaaaaa(aaa\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177{7\177\177\177\177\177\177E\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177aaaaaaa0110Oq4078988\177\177\177\025\0278888888888888DFMing-BdaaaAaaaaaaaaaaaa(aaaaaaaaaaaaaaaa88DFMing-Bdaaaaaa\363\240\201\256BBBBBaaaaaOqaG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaaaaaaaaa(aaaaaaaaaa0110Oq4078888\177\177\177\025\02788888\330\226g88888DFMing-Bdaaaaaaaaaaaaaaaa(aaaaaaaaaaaaa(aG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGG\307\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaa\334\276aaaaa01\030\030\030EFMing-Bdaaaaaaaaaaaaaaaa(aaa|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\177\177\177\177\177\177\177\177\177\177\'\'\'\'\'\'77\177\177\177\177\177\177\177\177GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnGGGGGGGGGGGGG\025\0278888888788888DFMing-\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGG\317\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGG\270GGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii-51559iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\003\'\'\'\'\'\'\'\346\350\'\'\'\'\'\'\'\'\'\'\'77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "10" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeput Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\355\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\034\256\235.\310S\254\222\324\006t)lN\307b1\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii8\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-00\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q407888iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiing-\0349\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035G-3071569\341\341\341\3410110\317\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\036\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\273\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\035/\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrh\370\331\264rrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341conds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\035\276\2546\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\037T\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGHGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\034\256\235.\310S\254\222\324\006t)lN\307b1\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii8\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiQQQQQQQQQQQQQQQQQiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377?\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGGaaaaaaaaaa(aaa\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177E\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177aaaaaaa0110Oq4078888\177\177\177\025\0278888888888888DFMing-BdaaaAaaaaaaaaaaaa(aaaaaaaaaaaaaaaa88DFMing-Bdaaaaaa\363\240\201\256BBBBBaaaaaOqaG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaaaaaaaaa(aaaaaaaaaa0110Oq4078888\177\177\177\025\02788888\330\226g88888DFMing-Bdaaaaaaaaaaaaaaaa(aaaaaaaaaaaaa(aG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGG\307\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaaaaaaaa01\030\030\030EFMing-Bdaaaaaaaaaaaaaaaa(aaa|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\035/nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\003rrrrrrrrrrrrhx\331\264rrrrrrrrrrrrrrrrr6nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnGGGGGGGGGGGGG\025\0278888888788888DFMing-\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGG\317\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "10" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000+\03100\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "Timeout Seconds" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Timeout SecondSeconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\3737\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGG56\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "<\000\000\000\000\000\000\00010" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\177\025\0278888888888878DFMing-Bdaaaaaaaaaaaaaaaa(aaaaaaaaaaaaa(aG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGG\307\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaaaaaaaa01\030\030\030EFMing-Bda195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGGGGGGGGGGGGGGGGGGGGGaaaaaaaaaa(aaa\177\177\177\177\177\177000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\035\276\2546\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGHGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356666666666666666666666666666666666666666666666666666666666\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\010" + value: "" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\34141\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii56\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\034\256\235.\310S\254\222\324\006t)lN\307b1\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii8\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\035\276\2546\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGHGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\034\256\235.\310S\254\222\324\006t)lN\307b1\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii8\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiQQQQQQQQQQQQQQQQQiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377?\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGGaaaaaaaaaa(aaa\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177E\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177aaaaaaa0110Oq4078888\177\177\177\025\0278888888888888DFMing-BdaaaAaaaaaaaaaaaa(aaaaaaaaaaaaaaaa88DFMing-Bdaaaaaa\363\240\201\256BBBBBaaaaaOqaG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaaaaaaaaa(aaaaaaaaaa0110Oq4078888\177\177\177\025\02788888\330\226g88888DFMing-Bdaaaaaaaaaaaaaaaa(aaaaaaaaaaaaa(aG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGG\307\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaaaaaaaa01\030\030\030EFMing-Bdaaaaaaaaaaaaaaaa(aaa|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\035/nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\003rrrrrrrrrrrrhx\331\264rrrrrrrrrrrrrrrrr6nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnGGGGGGGGGGGGG\025\0278888888788888DFMing-\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGG\317\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341041\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\000-99435\035\035\035\035\035\035\035\035\036\035\035\035\035GGGG\341\341\341\341\341\341\341\341\3410110\317\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "host" + value: "11" + } + metadata { + key: "\177\177\177\r" + value: "" + } + } + } + } + h2_frames { + settings { + } + } + h2_frames { + } + h2_frames { + settings { + } + } + } +} +events { +} +events { + upstream_send_event { + h2_frames { + settings { + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341041\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\003\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000+\03100\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "Timeout Seconds" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Timeout SecondSeconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\3737\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\034\276\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "" + value: "10" + } + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0068454512319142047377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii1111\37711iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + } + } + h2_frames { + metadata { + flags: END_HEADERS + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGGaaaaaaaaaa(aaa\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177{7\177\177\177\177\177\177E\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177aaaaaaa0110Oq4078988[177\177\177\025\0278888888888888DFMing-BdaaaAaaaaaaaaaaaa(aaaaaaaaaaaaaaaa88DFMing-Bdaaaaaa\363\240\201\256BBBBBaaaaaOqaG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaaaaaaaaa(aaaaaaaaaa0110Oq4078888\177\177\177\025\02788888\330\226g88888DFMing-Bdaaaaaaaaaaaaaaaa(aaaaaaaaaaaaa(aG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGG\307\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaa\334\276aaaaa01\030\030\030EFMing-Bdaaaaaaaaaaaaaaaa(aaa|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\177\177\177\177\177\177\177\177\177\177\'\'\'\'\'\'77\177\177\177\177\177\177\177\177GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnGGGGGGGGGGGGG\025\0278888888788888DFMing-\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGG\317\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGG\270GGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii-51559iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\003\'\'\'\'\'\'\'\346\350\'\'\'\'\'\'\'\'\'\'\'77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "10" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\034\256\235.\310S\254\222\324\006t)lN\307b1\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii8\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-00\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q407888iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiing-\0349\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035G-3071569\341\341\341\3410110\317\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\177\025\0278888888888878DFMing-Bdaaaaaaaaaaaaaaaa(aaaaaaaaaaaaa(aG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGG\307\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaaaaaaaa01\030\030\030EFMing-Bda195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGGGGGGGGGGGGGGGGGGGGGaaaaaaaaaa(aaa\177\177\177\177\177\177000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\035\276\2546\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGHGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\034\256\235.\310S\254\222\324\006t)lN\307b1\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii8\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiQQQQQQQQQQQQQQQQQiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377?\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGGaaaaaaaaaa(aaa\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177E\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177aaaaaaa0110Oq4078888\177\177\177\025\0278888888888888DFMing-BdaaaAaaaaaaaaaaaa(aaaaaaaaaaaaaaaa88DFMing-Bdaaaaaa\363\240\201\256BBBBBaaaaaOqaG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaaaaaaaaa(aaaaaaaaaa0110Oq4078888\177\177\177\025\02788888\330\226g88888DFMing-Bdaaaaaaaaaaaaaaaa(aaaaaaaaaaaaa(aG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGG\307\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaaaaaaaa01\030\030\030EFMing-Bdaaaaaaaaaaaaaaaa(aaa|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\035/nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\003rrrrrrrrrrrrhx\331\264rrrrrrrrrrrrrrrrr6nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnGGGGGGGGGGGGG\025\0278888888788888DFMing-\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGG\317\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGGaaaaaaaaaa(aaa\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177E\177\177\177\177\177\177\177\177\177\177\177\177\177iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGGGGGGGGGGGGGGGGGGGGGaaaaaaaaaa(aaa\177\177\177\177\177\177000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000+\03100\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "Timeout Seconds" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Timeout SecondSeconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\3737\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\034\276\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "" + value: "10" + } + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\037wk377\377\377\377\377\377\377\377\377\377\377\377\377\0068454512319142047377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\035/\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrh\370\331\264rrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^8DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\243356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\034\256\235.\310S\254\222\324\006t)lN\307b1\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii8\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-00\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGG26G\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q407888iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiing-\0349\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035G-3071569\341\341\341\3410110\317\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "10" + value: "" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + malformed_request { + stream_index: 1 + } + } + h2_frames { + metadata { + flags: END_HEADERS + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\035\276\2546\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGHGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\034\256\235.\310S\254\222\324\006t)lN\307b1\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii8\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiQQQQQQQQQQQQQQQQQiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377?\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGGaaaaaaaaaa(aaa\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177E\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177aaaaaaa0110Oq4078888\177\177\177\025\0278888888888888DFMing-BdaaaAaaaaaaaaaaaa(aaaaaaaaaaaaaaaa88DFMing-Bdaaaaaa\363\240\201\256BBBBBaaaaaOqaG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaaaaaaaaa(aaaaaaaaaa0110Oq4078888\177\177\177\025\02788888\330\226g88888DFMing-Bdaaaaaaaaaaaaaaaa(aaaaaaaaaaaaa(aG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGG\307\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaaaaaaaa01\030\030\030EFMing-Bdaaaaaaaaaaaaaaaa(aaa|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\035/nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\003rrrrrrrrrrrrhx\331\264rrrrrrrrrrrrrrrrr6nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnGGGGGGGGGGGGG\025\0278888888788888DFMing-\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGG\317\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341041\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\000-99435\035\035\035\035\035\035\035\035\036\035\035\035\035GGGG\341\341\341\341\341\341\341\341\3410110\317\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "host" + value: "11" + } + metadata { + key: "\177\177\177\r" + value: "" + } + } + } + } + h2_frames { + settings { + } + } + h2_frames { + } + h2_frames { + settings { + } + } + } +} +events { +} +events { + upstream_send_event { + h2_frames { + settings { + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341041\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\003\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGGaaaaaaaaaa(aaa\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177E\177\177\177\177\177\177\177\177\177\177\177\177\177iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGGGGGGGGGGGGGGGGGGGGGaaaaaaaaaa(aaa\177\177\177\177\177\177000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000+\03100\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "Timeout Seconds" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Timeout SecondSeconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\3737\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\034\276\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "" + value: "10" + } + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0068454512319142047377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii1111\37711iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + } + } + h2_frames { + metadata { + flags: END_HEADERS + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGGaaaaaaaaaa(aaa\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177{7\177\177\177\177\177\177E\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177aaaaaaa0110Oq4078988[177\177\177\025\0278888888888888DFMing-BdaaaAaaaaaaaaaaaa(aaaaaaaaaaaaaaaa88DFMing-Bdaaaaaa\363\240\201\256BBBBBaaaaaOqaG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaaaaaaaaa(aaaaaaaaaa0110Oq4078888\177\177\177\025\02788888\330\226g88888DFMing-Bdaaaaaaaaaaaaaaaa(aaaaaaaaaaaaa(aG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGG\307\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaa\334\276aaaaa01\030\030\030EFMing-Bdaaaaaaaaaaaaaaaa(aaa|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\177\177\177\177\177\177\177\177\177\177\'\'\'\'\'\'77\177\177\177\177\177\177\177\177GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnGGGGGGGGGGGGG\025\0278888888788888DFMing-\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGG\317\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGG\270GGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii-51559iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\003\'\'\'\'\'\'\'\346\350\'\'\'\'\'\'\'\'\'\'\'77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "10" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\034\256\235.\310S\254\222\324\006t)lN\307b1\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii8\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-00\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q407888iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiing-\0349\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035G-3071569\341\341\341\3410110\317\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\177\025\0278888888888878DFMing-Bdaaaaaaaaaaaaaaaa(aaaaaaaaaaaaa(aG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGG\307\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaaaaaaaa01\030\030\030EFMing-Bda195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGGGGGGGGGGGGGGGGGGGGGaaaaaaaaaa(aaa\177\177\177\177\177\177000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "" + value: "10" + } + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\035\276\2546\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGHGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\034\256\235.\310S\254\222\324\006t)lN\307b1\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii8\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiQQQQQQQQQQQQQQQQQiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377?\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGGaaaaaaaaaa(aaa\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177E\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177aaaaaaa0110Oq4078888\177\177\177\025\0278888888888888DFMing-BdaaaAaaaaaaaaaaaa(aaaaaaaaaaaaaaaa88DFMing-Bdaaaaaa\363\240\201\256BBBBBaaaaaOqaG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaaaaaaaaa(aaaaaaaaaa0110Oq4078888\177\177\177\025\02788888\330\226g88888DFMing-Bdaaaaaaaaaaaaaaaa(aaaaaaaaaaaaa(aG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGG\307\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaaaaaaaa01\030\030\030EFMing-Bdaaaaaaaaaaaaaaaa(aaa|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\035/nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\003rrrrrrrrrrrrhx\331\264rrrrrrrrrrrrrrrrr6nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnGGGGGGGGGGGGG\025\0278888888788888DFMing-\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGG\317\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGGaaaaaaaaaa(aaa\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177E\177\177\177\177\177\177\177\177\177\177\177\177\177iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGGGGGGGGGGGGGGGGGGGGGaaaaaaaaaa(aaa\177\177\177\177\177\177000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000+\03100\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "Timeout Seconds" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Timeout SecondSeconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "" + value: "10" + } + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\037wk377\377\377\377\377\377\377\377\377\377\377\377\377\0068454512319142047377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\035/\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrh\370\331\264rrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^8DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\243356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGGaaaaaaaaaa(aaa\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177{7\177\177\177\177\177\177E\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177aaaaaaa0110Oq4078988\177\177\177\025\0278888888888888DFMing-BdaaaAaaaaaaaaaaaa(aaaaaaaaaaaaaaaa88DFMing-Bdaaaaaa\363\240\201\256BBBBBaaaaaOqaG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaaaaaaaaa(aaaaaaaaaa0110Oq4078888\177\177\177\025\02788888\330\226g88888DFMing-Bdaaaaaaaaaaaaaaaa(aaaaaaaaaaaaa(aG!GGGGGGGGGGGGGGGGGGGGGGGGGGGGG\307\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGaaa\334\276aaaaa01\030\030\030EFMing-Bdaaaaaaaaaaaaaaaa(aaa|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\177\177\177\177\177\177\177\177\177\177\'\'\'\'\'\'77\177\177\177\177\177\177\177\177GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035000\000\000\000\000\000\000000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\3435\035\035\035ons" + value: "15" + } + metadata { + key: "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDw" + value: "" + } + metadata { + key: "Timeout Seconds" + value: "xost" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\334\334\334\334\334\334\334\334\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMin##g-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiieveniiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiing-\0349\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035G-3071569\341\341\341\3410110\317\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + } + } + } + h2_frames { + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\37556339077\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "p" + value: "" + } + } + } + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341!\341\341\341\341\341\341\341\341\341\341\34188DFMing-Bd\341\341\341\341\341\341\363\240\201\256BBBBB\341\341\341\341\341\317q\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\027888888\226\34788888DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341|!GGGGGGGGGGGGG\025\0278888888888888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "\001\000" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\034\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341\341\341\341\341\341\3410110\317q4078888\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii8\377\377\377\025\0278888888888888DFMing-Bd\341\341\341\301\341\341\006\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356\356GGGGGGGGGGGGG\025\0278888888788888DFMing-\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGG\357\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + h2_frames { + } + h2_frames { + metadata { + stream_index: 1 + metadata { + metadata { + key: "" + value: "\001\000" + } + metadata { + key: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}}}}0\000\000\000\000\000\000\000GGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377E\377\377\377\377\377\377\377\377\377\377\377\377\377iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\035\035\035\035\035nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\003rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr6nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnGGGGGGGGGGGGG\025\0278888888788888DFMing-\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177GGG\317\231GGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035ons" + value: "15" + } + metadata { + key: "Timeout Seconds" + value: "10" + } + metadata { + key: "connecti\377\025\0278888888888878DFMing-Bd\341\341\341\341\341\341\341\341\341\341\341\341\341\341\341\331(\341\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGG\270GGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii-51559iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377?\377\377\377\377GGGGGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\0351\341\341\341\341\341\341\341\341\341\341\341\341(\341G!GGGGGGGGGGGGGGGGGGG\270GGGGGGGGGG\272GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\34101\030\030\030EFMing-Bd\341195262iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihiiiiiiiiiiiiiiiiiiiiiiiiiiiii-51559iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGGGGGGG\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035\035G-3071569\341\341\341\3410110\317\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377GGGGGGGGGGGGGGGGGGGGGG\341\341\341\341\341\341\341\341\341\341(\341\341\341\377\377\377\377\377\377000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + value: "" + } + metadata { + key: "w" + value: "" + } + } + } + } + } +} diff --git a/test/integration/http2_flood_integration_test.cc b/test/integration/http2_flood_integration_test.cc index d43643e122c14..01f7fe6753a50 100644 --- a/test/integration/http2_flood_integration_test.cc +++ b/test/integration/http2_flood_integration_test.cc @@ -1162,4 +1162,136 @@ TEST_P(Http2FloodMitigationTest, UpstreamEmptyHeaders) { test_server_->counter("cluster.cluster_0.http2.inbound_empty_frames_flood")->value()); } +// Verify that the HTTP/2 connection is terminated upon receiving invalid HEADERS frame. +TEST_P(Http2FloodMitigationTest, UpstreamZerolenHeader) { + if (!initializeUpstreamFloodTest()) { + return; + } + + // Send client request which will send an upstream request. + codec_client_ = makeHttpConnection(lookupPort("http")); + auto response = codec_client_->makeHeaderOnlyRequest(default_request_headers_); + waitForNextUpstreamRequest(); + + // Send an upstream reply. + auto* upstream = fake_upstreams_.front().get(); + const auto buf = + Http2Frame::makeMalformedResponseWithZerolenHeader(Http2Frame::makeClientStreamId(0)); + ASSERT_TRUE(upstream->rawWriteConnection(0, std::string(buf.begin(), buf.end()))); + + response->waitForEndStream(); + ASSERT_TRUE(fake_upstream_connection_->waitForDisconnect()); + + EXPECT_EQ(1, test_server_->counter("cluster.cluster_0.http2.rx_messaging_error")->value()); + EXPECT_EQ( + 1, + test_server_->counter("cluster.cluster_0.upstream_cx_destroy_local_with_active_rq")->value()); + EXPECT_EQ("503", response->headers().getStatusValue()); +} + +// Verify that the HTTP/2 connection is terminated upon receiving invalid HEADERS frame. +TEST_P(Http2FloodMitigationTest, UpstreamZerolenHeaderAllowed) { + useAccessLog("%RESPONSE_FLAGS% %RESPONSE_CODE_DETAILS%"); + config_helper_.addConfigModifier([&](envoy::config::bootstrap::v3::Bootstrap& bootstrap) -> void { + RELEASE_ASSERT(bootstrap.mutable_static_resources()->clusters_size() >= 1, ""); + auto* cluster = bootstrap.mutable_static_resources()->mutable_clusters(0); + cluster->mutable_http2_protocol_options() + ->mutable_override_stream_error_on_invalid_http_message() + ->set_value(1); + }); + if (!initializeUpstreamFloodTest()) { + return; + } + + // Send client request which will send an upstream request. + codec_client_ = makeHttpConnection(lookupPort("http")); + auto response = codec_client_->makeHeaderOnlyRequest(default_request_headers_); + waitForNextUpstreamRequest(); + + // Send an upstream reply. + auto* upstream = fake_upstreams_.front().get(); + const auto buf = + Http2Frame::makeMalformedResponseWithZerolenHeader(Http2Frame::makeClientStreamId(0)); + ASSERT_TRUE(upstream->rawWriteConnection(0, std::string(buf.begin(), buf.end()))); + + // Make sure upstream and downstream got RST_STREAM from the server. + ASSERT_TRUE(upstream_request_->waitForReset()); + response->waitForEndStream(); + EXPECT_EQ("503", response->headers().getStatusValue()); + + // Send another request from downstream on the same connection, and make sure + // a new request reaches upstream on its previous connection. + auto response2 = codec_client_->makeHeaderOnlyRequest(default_request_headers_); + waitForNextUpstreamRequest(); + const auto buf2 = + Http2Frame::makeHeadersFrameWithStatus("200", Http2Frame::makeClientStreamId(1)); + ASSERT_TRUE(upstream->rawWriteConnection(0, std::string(buf2.begin(), buf2.end()))); + + response2->waitForEndStream(); + EXPECT_EQ("200", response2->headers().getStatusValue()); + + EXPECT_EQ(1, test_server_->counter("cluster.cluster_0.http2.rx_messaging_error")->value()); + EXPECT_EQ( + 0, + test_server_->counter("cluster.cluster_0.upstream_cx_destroy_local_with_active_rq")->value()); + // Expect a local reset due to upstream reset before a response. + EXPECT_THAT(waitForAccessLog(access_log_name_), + HasSubstr("upstream_reset_before_response_started")); + EXPECT_THAT(waitForAccessLog(access_log_name_), HasSubstr("LR")); +} + +TEST_P(Http2FloodMitigationTest, UpstreamEmptyData) { + if (!initializeUpstreamFloodTest()) { + return; + } + + // Send client request which will send an upstream request. + codec_client_ = makeHttpConnection(lookupPort("http")); + auto response = codec_client_->makeHeaderOnlyRequest(default_request_headers_); + waitForNextUpstreamRequest(); + + // Start the response with a 200 status. + auto* upstream = fake_upstreams_.front().get(); + Http2Frame buf = Http2Frame::makeHeadersFrameWithStatus("200", Http2Frame::makeClientStreamId(0), + Http2Frame::HeadersFlags::EndHeaders); + ASSERT_TRUE(upstream->rawWriteConnection(0, std::string(buf.begin(), buf.end()))); + + // Send empty data frames. + for (int i = 0; i < 2; i++) { + buf = Http2Frame::makeEmptyDataFrame(Http2Frame::makeClientStreamId(0)); + ASSERT_TRUE(upstream->rawWriteConnection(0, std::string(buf.begin(), buf.end()))); + } + + ASSERT_TRUE(fake_upstream_connection_->waitForDisconnect()); + response->waitForReset(); + EXPECT_EQ("200", response->headers().getStatusValue()); + EXPECT_EQ(1, + test_server_->counter("cluster.cluster_0.http2.inbound_empty_frames_flood")->value()); +} + +TEST_P(Http2FloodMitigationTest, UpstreamEmptyHeadersContinuation) { + if (!initializeUpstreamFloodTest()) { + return; + } + + codec_client_ = makeHttpConnection(lookupPort("http")); + auto response = codec_client_->makeHeaderOnlyRequest(default_request_headers_); + waitForNextUpstreamRequest(); + + auto* upstream = fake_upstreams_.front().get(); + Http2Frame buf = Http2Frame::makeEmptyHeadersFrame(Http2Frame::makeClientStreamId(0)); + ASSERT_TRUE(upstream->rawWriteConnection(0, std::string(buf.begin(), buf.end()))); + + for (int i = 0; i < 2; i++) { + buf = Http2Frame::makeEmptyContinuationFrame(Http2Frame::makeClientStreamId(0)); + ASSERT_TRUE(upstream->rawWriteConnection(0, std::string(buf.begin(), buf.end()))); + } + + ASSERT_TRUE(fake_upstream_connection_->waitForDisconnect()); + response->waitForEndStream(); + EXPECT_EQ("503", response->headers().getStatusValue()); + EXPECT_EQ(1, + test_server_->counter("cluster.cluster_0.http2.inbound_empty_frames_flood")->value()); +} + } // namespace Envoy diff --git a/test/integration/http2_integration_test.cc b/test/integration/http2_integration_test.cc index 1ad689a4849e4..7c0ca001bfd85 100644 --- a/test/integration/http2_integration_test.cc +++ b/test/integration/http2_integration_test.cc @@ -1565,4 +1565,37 @@ INSTANTIATE_TEST_SUITE_P(IpVersions, Http2FrameIntegrationTest, testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), TestUtility::ipTestParamsToString); +// Tests upstream sending a metadata frame after ending a stream. +TEST_P(Http2MetadataIntegrationTest, UpstreamMetadataAfterEndStream) { + initialize(); + codec_client_ = makeHttpConnection(lookupPort("http")); + + // Sends the first request. + auto encoder_decoder = codec_client_->startRequest(default_request_headers_); + auto response = std::move(encoder_decoder.second); + + // Wait for upstream to receive the request + ASSERT_TRUE(fake_upstreams_[0]->waitForHttpConnection(*dispatcher_, fake_upstream_connection_)); + ASSERT_TRUE(fake_upstream_connection_->waitForNewStream(*dispatcher_, upstream_request_)); + ASSERT_TRUE(upstream_request_->waitForHeadersComplete()); + + // Upstream sends headers and ends stream. + const Http::TestResponseHeaderMapImpl response_headers{{":status", "200"}}; + upstream_request_->encodeHeaders(response_headers, true); + + // Upstream sends metadata. + const Http::MetadataMap response_metadata_map = {{"resp_key1", "resp_value1"}}; + Http::MetadataMapPtr metadata_map_ptr = + std::make_unique(response_metadata_map); + Http::MetadataMapVector metadata_map_vector; + metadata_map_vector.push_back(std::move(metadata_map_ptr)); + upstream_request_->encodeMetadata(metadata_map_vector); + + // Cleanup. + ASSERT_TRUE(fake_upstream_connection_->close()); + response->waitForEndStream(); + ASSERT_TRUE(response->complete()); + EXPECT_EQ("200", response->headers().getStatusValue()); +} + } // namespace Envoy diff --git a/test/integration/http_integration.cc b/test/integration/http_integration.cc index bae6f3ba9acbe..198ca37278d1b 100644 --- a/test/integration/http_integration.cc +++ b/test/integration/http_integration.cc @@ -829,7 +829,9 @@ void HttpIntegrationTest::testGrpcRetry() { } void HttpIntegrationTest::testEnvoyHandling100Continue(bool additional_continue_from_upstream, - const std::string& via) { + const std::string& via, + bool disconnect_after_100) { + useAccessLog("%RESPONSE_CODE%"); initialize(); codec_client_ = makeHttpConnection(lookupPort("http")); @@ -865,6 +867,15 @@ void HttpIntegrationTest::testEnvoyHandling100Continue(bool additional_continue_ upstream_request_->encode100ContinueHeaders( Http::TestResponseHeaderMapImpl{{":status", "100"}}); } + + if (disconnect_after_100) { + response->waitForContinueHeaders(); + codec_client_->close(); + ASSERT_TRUE(fake_upstream_connection_->close()); + EXPECT_THAT(waitForAccessLog(access_log_name_), HasSubstr("100")); + return; + } + upstream_request_->encodeHeaders(default_response_headers_, false); upstream_request_->encodeData(12, true); @@ -879,6 +890,7 @@ void HttpIntegrationTest::testEnvoyHandling100Continue(bool additional_continue_ } else { EXPECT_EQ(via.c_str(), response->headers().getViaValue()); } + EXPECT_THAT(waitForAccessLog(access_log_name_), HasSubstr("200")); } void HttpIntegrationTest::testEnvoyProxying1xx(bool continue_before_upstream_complete, diff --git a/test/integration/http_integration.h b/test/integration/http_integration.h index ae7652d59107b..cf8afa9cfa6df 100644 --- a/test/integration/http_integration.h +++ b/test/integration/http_integration.h @@ -216,7 +216,7 @@ class HttpIntegrationTest : public BaseIntegrationTest { void testGrpcRetry(); void testEnvoyHandling100Continue(bool additional_continue_from_upstream = false, - const std::string& via = ""); + const std::string& via = "", bool disconnect_after_100 = false); void testEnvoyProxying1xx(bool continue_before_upstream_complete = false, bool with_encoder_filter = false, bool with_multiple_1xx_headers = false); diff --git a/test/integration/integration_test.cc b/test/integration/integration_test.cc index f76ad6f889e2f..944ccfe813431 100644 --- a/test/integration/integration_test.cc +++ b/test/integration/integration_test.cc @@ -483,6 +483,38 @@ TEST_P(IntegrationTest, TestSmuggling) { } } +TEST_P(IntegrationTest, TestPipelinedResponses) { + initialize(); + auto tcp_client = makeTcpConnection(lookupPort("http")); + + ASSERT_TRUE(tcp_client->write( + "POST /test/long/url HTTP/1.1\r\nHost: host\r\ntransfer-encoding: chunked\r\n\r\n")); + + FakeRawConnectionPtr fake_upstream_connection; + ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection)); + std::string data; + ASSERT_TRUE(fake_upstream_connection->waitForData( + FakeRawConnection::waitForInexactMatch("\r\n\r\n"), &data)); + ASSERT_THAT(data, HasSubstr("POST")); + + ASSERT_TRUE(fake_upstream_connection->write( + "HTTP/1.1 200 OK\r\ntransfer-encoding: chunked\r\n\r\n0\r\n\r\n" + "HTTP/1.1 200 OK\r\ntransfer-encoding: chunked\r\n\r\n0\r\n\r\n" + "HTTP/1.1 200 OK\r\ntransfer-encoding: chunked\r\n\r\n0\r\n\r\n")); + + tcp_client->waitForData("0\r\n\r\n", false); + std::string response = tcp_client->data(); + + EXPECT_THAT(response, HasSubstr("HTTP/1.1 200 OK\r\n")); + EXPECT_THAT(response, HasSubstr("transfer-encoding: chunked\r\n")); + EXPECT_THAT(response, EndsWith("0\r\n\r\n")); + + ASSERT_TRUE(fake_upstream_connection->close()); + ASSERT_TRUE(fake_upstream_connection->waitForDisconnect()); + tcp_client->close(); + EXPECT_EQ(test_server_->counter("cluster.cluster_0.upstream_cx_protocol_error")->value(), 1); +} + TEST_P(IntegrationTest, TestServerAllowChunkedLength) { config_helper_.addConfigModifier( [&](envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager& diff --git a/test/integration/protocol_integration_test.cc b/test/integration/protocol_integration_test.cc index 358ec1515cc08..68865b4c16e74 100644 --- a/test/integration/protocol_integration_test.cc +++ b/test/integration/protocol_integration_test.cc @@ -387,8 +387,13 @@ TEST_P(ProtocolIntegrationTest, FaultyFilterWithConnect) { codec_client_ = makeHttpConnection(lookupPort("http")); // Missing host for CONNECT - auto response = codec_client_->makeHeaderOnlyRequest(Http::TestRequestHeaderMapImpl{ - {":method", "CONNECT"}, {":scheme", "http"}, {":authority", "www.host.com:80"}}); + auto headers = Http::TestRequestHeaderMapImpl{ + {":method", "CONNECT"}, {":scheme", "http"}, {":authority", "www.host.com:80"}}; + + auto response = (downstream_protocol_ == Http::CodecClient::Type::HTTP1) + ? std::move((codec_client_->startRequest(headers)).second) + : codec_client_->makeHeaderOnlyRequest(headers); + response->waitForEndStream(); EXPECT_TRUE(response->complete()); EXPECT_EQ("503", response->headers().getStatusValue()); @@ -993,6 +998,14 @@ TEST_P(ProtocolIntegrationTest, HittingEncoderFilterLimit) { test_server_->waitForCounterEq("http.config_test.downstream_rq_5xx", 1); } +// The downstream connection is closed when it is read disabled, and on OSX the +// connection error is not detected under these circumstances. +#if !defined(__APPLE__) +TEST_P(ProtocolIntegrationTest, 100ContinueAndClose) { + testEnvoyHandling100Continue(false, "", true); +} +#endif + TEST_P(ProtocolIntegrationTest, EnvoyHandling100Continue) { testEnvoyHandling100Continue(); } TEST_P(ProtocolIntegrationTest, EnvoyHandlingDuplicate100Continue) { @@ -2069,8 +2082,10 @@ TEST_P(DownstreamProtocolIntegrationTest, InvalidAuthority) { TEST_P(DownstreamProtocolIntegrationTest, ConnectIsBlocked) { initialize(); codec_client_ = makeHttpConnection(lookupPort("http")); - auto response = codec_client_->makeHeaderOnlyRequest( + auto encoder_decoder = codec_client_->startRequest( Http::TestRequestHeaderMapImpl{{":method", "CONNECT"}, {":authority", "host.com:80"}}); + request_encoder_ = &encoder_decoder.first; + auto response = std::move(encoder_decoder.second); if (downstreamProtocol() == Http::CodecClient::Type::HTTP1) { // Because CONNECT requests for HTTP/1 do not include a path, they will fail diff --git a/test/integration/proxy_proto_integration_test.cc b/test/integration/proxy_proto_integration_test.cc index 064d884899ec1..9cea358aa4d1d 100644 --- a/test/integration/proxy_proto_integration_test.cc +++ b/test/integration/proxy_proto_integration_test.cc @@ -2,6 +2,8 @@ #include "envoy/config/bootstrap/v3/bootstrap.pb.h" #include "envoy/config/cluster/v3/cluster.pb.h" +#include "envoy/extensions/access_loggers/file/v3/file.pb.h" +#include "envoy/extensions/filters/network/tcp_proxy/v3/tcp_proxy.pb.h" #include "common/buffer/buffer_impl.h" @@ -14,6 +16,24 @@ namespace Envoy { +static void +insertProxyProtocolFilterConfigModifier(envoy::config::bootstrap::v3::Bootstrap& bootstrap) { + ::envoy::extensions::filters::listener::proxy_protocol::v3::ProxyProtocol proxy_protocol; + auto rule = proxy_protocol.add_rules(); + rule->set_tlv_type(0x02); + rule->mutable_on_tlv_present()->set_key("PP2TypeAuthority"); + + auto* listener = bootstrap.mutable_static_resources()->mutable_listeners(0); + auto* ppv_filter = listener->add_listener_filters(); + ppv_filter->set_name("envoy.listener.proxy_protocol"); + ppv_filter->mutable_typed_config()->PackFrom(proxy_protocol); +} + +ProxyProtoIntegrationTest::ProxyProtoIntegrationTest() + : HttpIntegrationTest(Http::CodecClient::Type::HTTP1, GetParam()) { + config_helper_.addConfigModifier(insertProxyProtocolFilterConfigModifier); +} + INSTANTIATE_TEST_SUITE_P(IpVersions, ProxyProtoIntegrationTest, testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), TestUtility::ipTestParamsToString); @@ -201,4 +221,59 @@ TEST_P(ProxyProtoIntegrationTest, ClusterProvided) { testRouterRequestAndResponseWithBody(1024, 512, false, false, &creator); } +ProxyProtoTcpIntegrationTest::ProxyProtoTcpIntegrationTest() + : BaseIntegrationTest(GetParam(), ConfigHelper::tcpProxyConfig()) { + config_helper_.addConfigModifier(insertProxyProtocolFilterConfigModifier); + config_helper_.renameListener("tcp_proxy"); +} + +INSTANTIATE_TEST_SUITE_P(IpVersions, ProxyProtoTcpIntegrationTest, + testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), + TestUtility::ipTestParamsToString); + +// This tests that the StreamInfo contains the correct addresses. +TEST_P(ProxyProtoTcpIntegrationTest, AccessLog) { + std::string access_log_path = TestEnvironment::temporaryPath( + fmt::format("access_log{}.txt", version_ == Network::Address::IpVersion::v4 ? "v4" : "v6")); + config_helper_.addConfigModifier([&](envoy::config::bootstrap::v3::Bootstrap& bootstrap) -> void { + auto* listener = bootstrap.mutable_static_resources()->mutable_listeners(0); + auto* filter_chain = listener->mutable_filter_chains(0); + auto* config_blob = filter_chain->mutable_filters(0)->mutable_typed_config(); + + ASSERT_TRUE( + config_blob + ->Is()); + auto tcp_proxy_config = MessageUtil::anyConvert(*config_blob); + + auto* access_log = tcp_proxy_config.add_access_log(); + access_log->set_name("accesslog"); + envoy::extensions::access_loggers::file::v3::FileAccessLog access_log_config; + access_log_config.set_path(access_log_path); + access_log_config.mutable_log_format()->set_text_format( + "remote=%DOWNSTREAM_REMOTE_ADDRESS% local=%DOWNSTREAM_LOCAL_ADDRESS%"); + access_log->mutable_typed_config()->PackFrom(access_log_config); + config_blob->PackFrom(tcp_proxy_config); + }); + initialize(); + + IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("tcp_proxy")); + ASSERT_TRUE(tcp_client->write("PROXY TCP4 1.2.3.4 254.254.254.254 12345 1234\r\nhello", false)); + + FakeRawConnectionPtr fake_upstream_connection; + ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection)); + ASSERT_TRUE(fake_upstream_connection->waitForData(5)); + ASSERT_TRUE(fake_upstream_connection->close()); + tcp_client->close(); + ASSERT_TRUE(fake_upstream_connection->waitForDisconnect()); + + std::string log_result; + // Access logs only get flushed to disk periodically, so poll until the log is non-empty + do { + log_result = api_->fileSystem().fileReadToEnd(access_log_path); + } while (log_result.empty()); + + EXPECT_EQ(log_result, "remote=1.2.3.4:12345 local=254.254.254.254:1234"); +} + } // namespace Envoy diff --git a/test/integration/proxy_proto_integration_test.h b/test/integration/proxy_proto_integration_test.h index 140d5b63d3f70..3a719ad44aaf0 100644 --- a/test/integration/proxy_proto_integration_test.h +++ b/test/integration/proxy_proto_integration_test.h @@ -16,19 +16,13 @@ namespace Envoy { class ProxyProtoIntegrationTest : public testing::TestWithParam, public HttpIntegrationTest { public: - ProxyProtoIntegrationTest() : HttpIntegrationTest(Http::CodecClient::Type::HTTP1, GetParam()) { - config_helper_.addConfigModifier( - [&](envoy::config::bootstrap::v3::Bootstrap& bootstrap) -> void { - ::envoy::extensions::filters::listener::proxy_protocol::v3::ProxyProtocol proxy_protocol; - auto rule = proxy_protocol.add_rules(); - rule->set_tlv_type(0x02); - rule->mutable_on_tlv_present()->set_key("PP2TypeAuthority"); - - auto* listener = bootstrap.mutable_static_resources()->mutable_listeners(0); - auto* ppv_filter = listener->add_listener_filters(); - ppv_filter->set_name("envoy.listener.proxy_protocol"); - ppv_filter->mutable_typed_config()->PackFrom(proxy_protocol); - }); - } + ProxyProtoIntegrationTest(); }; + +class ProxyProtoTcpIntegrationTest : public testing::TestWithParam, + public BaseIntegrationTest { +public: + ProxyProtoTcpIntegrationTest(); +}; + } // namespace Envoy diff --git a/test/integration/sds_dynamic_integration_test.cc b/test/integration/sds_dynamic_integration_test.cc index 2a44fc58dc86d..f686a0946fb43 100644 --- a/test/integration/sds_dynamic_integration_test.cc +++ b/test/integration/sds_dynamic_integration_test.cc @@ -139,6 +139,7 @@ class SdsDynamicIntegrationBaseTest : public Grpc::GrpcClientIntegrationParamTes const std::string server_cert_; const std::string validation_secret_; const std::string client_cert_; + bool v3_resource_api_{false}; }; // Downstream SDS integration test: static Listener with ssl cert from SDS @@ -201,6 +202,103 @@ class SdsDynamicDownstreamIntegrationTest : public SdsDynamicIntegrationBaseTest INSTANTIATE_TEST_SUITE_P(IpVersionsClientType, SdsDynamicDownstreamIntegrationTest, GRPC_CLIENT_INTEGRATION_PARAMS); +class SdsDynamicKeyRotationIntegrationTest : public SdsDynamicDownstreamIntegrationTest { +protected: + envoy::extensions::transport_sockets::tls::v3::Secret getCurrentServerSecret() { + envoy::extensions::transport_sockets::tls::v3::Secret secret; + secret.set_name(server_cert_); + auto* tls_certificate = secret.mutable_tls_certificate(); + tls_certificate->mutable_certificate_chain()->set_filename( + TestEnvironment::temporaryPath("root/current/servercert.pem")); + tls_certificate->mutable_private_key()->set_filename( + TestEnvironment::temporaryPath("root/current/serverkey.pem")); + auto* watched_directory = tls_certificate->mutable_watched_directory(); + watched_directory->set_path(TestEnvironment::temporaryPath("root")); + return secret; + } +}; + +// We don't care about multiple gRPC types here, Envoy gRPC is fine, the +// interest is on the filesystem. +INSTANTIATE_TEST_SUITE_P( + IpVersionsClientType, SdsDynamicKeyRotationIntegrationTest, + testing::Combine(testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), + testing::Values(Grpc::ClientType::EnvoyGrpc))); + +// Validate that a basic key-cert rotation works via symlink rename. +TEST_P(SdsDynamicKeyRotationIntegrationTest, BasicRotation) { + v3_resource_api_ = true; + TestEnvironment::exec( + {TestEnvironment::runfilesPath("test/integration/sds_dynamic_key_rotation_setup.sh")}); + + on_server_init_function_ = [this]() { + createSdsStream(*(fake_upstreams_[1])); + sendSdsResponse(getCurrentServerSecret()); + }; + initialize(); + + // Initial update from filesystem. + test_server_->waitForCounterGe( + listenerStatPrefix("server_ssl_socket_factory.ssl_context_update_by_sds"), 1); + + ConnectionCreationFunction creator = [&]() -> Network::ClientConnectionPtr { + return makeSslClientConnection(); + }; + // First request with server{cert,key}.pem. + testRouterHeaderOnlyRequestAndResponse(&creator); + cleanupUpstreamAndDownstream(); + // Rotate. + TestEnvironment::renameFile(TestEnvironment::temporaryPath("root/new"), + TestEnvironment::temporaryPath("root/current")); + test_server_->waitForCounterGe( + listenerStatPrefix("server_ssl_socket_factory.ssl_context_update_by_sds"), 2); + // The rotation is not a SDS attempt, so no change to these stats. + EXPECT_EQ(1, test_server_->counter("sds.server_cert.update_success")->value()); + EXPECT_EQ(0, test_server_->counter("sds.server_cert.update_rejected")->value()); + + // First request with server_ecdsa{cert,key}.pem. + testRouterHeaderOnlyRequestAndResponse(&creator); +} + +// Validate that rotating to a directory with missing certs is handled. +TEST_P(SdsDynamicKeyRotationIntegrationTest, EmptyRotation) { + v3_resource_api_ = true; + TestEnvironment::exec( + {TestEnvironment::runfilesPath("test/integration/sds_dynamic_key_rotation_setup.sh")}); + + on_server_init_function_ = [this]() { + createSdsStream(*(fake_upstreams_[1])); + sendSdsResponse(getCurrentServerSecret()); + }; + initialize(); + + // Initial update from filesystem. + test_server_->waitForCounterGe( + listenerStatPrefix("server_ssl_socket_factory.ssl_context_update_by_sds"), 1); + + ConnectionCreationFunction creator = [&]() -> Network::ClientConnectionPtr { + return makeSslClientConnection(); + }; + // First request with server{cert,key}.pem. + testRouterHeaderOnlyRequestAndResponse(&creator); + cleanupUpstreamAndDownstream(); + + // Rotate to an empty directory, this should fail. + TestEnvironment::renameFile(TestEnvironment::temporaryPath("root/empty"), + TestEnvironment::temporaryPath("root/current")); + test_server_->waitForCounterEq("sds.server_cert.key_rotation_failed", 1); + EXPECT_EQ(1, + test_server_ + ->counter(listenerStatPrefix("server_ssl_socket_factory.ssl_context_update_by_sds")) + ->value()); + // The rotation is not a SDS attempt, so no change to these stats. + EXPECT_EQ(1, test_server_->counter("sds.server_cert.update_success")->value()); + EXPECT_EQ(0, test_server_->counter("sds.server_cert.update_rejected")->value()); + + // Requests continue to work with key/cert pair. + testRouterHeaderOnlyRequestAndResponse(&creator); +} + // A test that SDS server send a good server secret for a static listener. // The first ssl request should be OK. TEST_P(SdsDynamicDownstreamIntegrationTest, BasicSuccess) { @@ -214,6 +312,10 @@ TEST_P(SdsDynamicDownstreamIntegrationTest, BasicSuccess) { return makeSslClientConnection(); }; testRouterHeaderOnlyRequestAndResponse(&creator); + + // Success + EXPECT_EQ(1, test_server_->counter("sds.server_cert.update_success")->value()); + EXPECT_EQ(0, test_server_->counter("sds.server_cert.update_rejected")->value()); } // A test that SDS server send a bad secret for a static listener, @@ -231,6 +333,10 @@ TEST_P(SdsDynamicDownstreamIntegrationTest, WrongSecretFirst) { EXPECT_FALSE(codec_client_->connected()); codec_client_->connection()->close(Network::ConnectionCloseType::NoFlush); + // Failure + EXPECT_EQ(0, test_server_->counter("sds.server_cert.update_success")->value()); + EXPECT_EQ(1, test_server_->counter("sds.server_cert.update_rejected")->value()); + sendSdsResponse(getServerSecret()); // Wait for ssl_context_updated_by_sds counter. @@ -241,6 +347,10 @@ TEST_P(SdsDynamicDownstreamIntegrationTest, WrongSecretFirst) { return makeSslClientConnection(); }; testRouterHeaderOnlyRequestAndResponse(&creator); + + // Success + EXPECT_EQ(1, test_server_->counter("sds.server_cert.update_success")->value()); + EXPECT_EQ(1, test_server_->counter("sds.server_cert.update_rejected")->value()); } class SdsDynamicDownstreamCertValidationContextTest : public SdsDynamicDownstreamIntegrationTest { @@ -369,6 +479,10 @@ TEST_P(SdsDynamicDownstreamCertValidationContextTest, BasicSuccess) { return makeSslClientConnection(); }; testRouterHeaderOnlyRequestAndResponse(&creator); + + // Success + EXPECT_EQ(1, test_server_->counter("sds.validation_secret.update_success")->value()); + EXPECT_EQ(0, test_server_->counter("sds.validation_secret.update_rejected")->value()); } // A test that SDS server sends a certificate validation context for a static listener. @@ -386,6 +500,10 @@ TEST_P(SdsDynamicDownstreamCertValidationContextTest, CombinedCertValidationCont return makeSslClientConnection(); }; testRouterHeaderOnlyRequestAndResponse(&creator); + + // Success + EXPECT_EQ(1, test_server_->counter("sds.validation_secret.update_success")->value()); + EXPECT_EQ(0, test_server_->counter("sds.validation_secret.update_rejected")->value()); } // A test that verifies that both: static cluster and LDS listener are updated when using @@ -409,6 +527,10 @@ TEST_P(SdsDynamicDownstreamCertValidationContextTest, BasicWithSharedSecret) { return makeSslClientConnection(); }; testRouterHeaderOnlyRequestAndResponse(&creator); + + // Success + EXPECT_EQ(1, test_server_->counter("sds.validation_secret.update_success")->value()); + EXPECT_EQ(0, test_server_->counter("sds.validation_secret.update_rejected")->value()); } // A test that verifies that both: static cluster and LDS listener are updated when using @@ -433,6 +555,10 @@ TEST_P(SdsDynamicDownstreamCertValidationContextTest, CombinedValidationContextW return makeSslClientConnection(); }; testRouterHeaderOnlyRequestAndResponse(&creator); + + // Success + EXPECT_EQ(1, test_server_->counter("sds.validation_secret.update_success")->value()); + EXPECT_EQ(0, test_server_->counter("sds.validation_secret.update_rejected")->value()); } // Upstream SDS integration test: a static cluster has ssl cert from SDS. @@ -504,6 +630,10 @@ TEST_P(SdsDynamicUpstreamIntegrationTest, BasicSuccess) { "cluster.cluster_0.client_ssl_socket_factory.ssl_context_update_by_sds", 1); testRouterHeaderOnlyRequestAndResponse(); + + // Success + EXPECT_EQ(1, test_server_->counter("sds.client_cert.update_success")->value()); + EXPECT_EQ(0, test_server_->counter("sds.client_cert.update_rejected")->value()); } // To test a static cluster with sds. SDS send a bad client secret first. @@ -527,11 +657,19 @@ TEST_P(SdsDynamicUpstreamIntegrationTest, WrongSecretFirst) { ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection)); ASSERT_TRUE(fake_upstream_connection->waitForDisconnect()); + // Failure + EXPECT_EQ(0, test_server_->counter("sds.client_cert.update_success")->value()); + EXPECT_EQ(1, test_server_->counter("sds.client_cert.update_rejected")->value()); + sendSdsResponse(getClientSecret()); test_server_->waitForCounterGe( "cluster.cluster_0.client_ssl_socket_factory.ssl_context_update_by_sds", 1); testRouterHeaderOnlyRequestAndResponse(); + + // Success + EXPECT_EQ(1, test_server_->counter("sds.client_cert.update_success")->value()); + EXPECT_EQ(1, test_server_->counter("sds.client_cert.update_rejected")->value()); } } // namespace Ssl diff --git a/test/integration/sds_dynamic_key_rotation_setup.sh b/test/integration/sds_dynamic_key_rotation_setup.sh new file mode 100755 index 0000000000000..a43e2bd82d2ba --- /dev/null +++ b/test/integration/sds_dynamic_key_rotation_setup.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +set -e + +TEST_CERTS="${TEST_SRCDIR}"/envoy/test/config/integration/certs + +ROOT="${TEST_TMPDIR}"/root +SERVER_KEYCERT="${ROOT}"/server +SERVER_ECDSA_KEYCERT="${ROOT}"/server_ecdsa +EMPTY_KEYCERT="${ROOT}"/empty_keycert + +rm -rf "${ROOT}" +mkdir -p "${SERVER_KEYCERT}" +mkdir -p "${SERVER_ECDSA_KEYCERT}" +mkdir -p "${EMPTY_KEYCERT}" + +cp -f "${TEST_CERTS}"/server{cert,key}.pem "${SERVER_KEYCERT}" +cp -f "${TEST_CERTS}"/server_ecdsacert.pem "${SERVER_ECDSA_KEYCERT}"/servercert.pem +cp -f "${TEST_CERTS}"/server_ecdsakey.pem "${SERVER_ECDSA_KEYCERT}"/serverkey.pem + +ln -sf "${SERVER_KEYCERT}" "${ROOT}"/current +ln -sf "${SERVER_ECDSA_KEYCERT}" "${ROOT}"/new +ln -sf "${EMPTY_KEYCERT}" "${ROOT}"/empty diff --git a/test/integration/tcp_tunneling_integration_test.cc b/test/integration/tcp_tunneling_integration_test.cc index d5056a28720c8..9dd77c67369ed 100644 --- a/test/integration/tcp_tunneling_integration_test.cc +++ b/test/integration/tcp_tunneling_integration_test.cc @@ -311,28 +311,39 @@ INSTANTIATE_TEST_SUITE_P(IpVersions, ConnectTerminationIntegrationTest, testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), TestUtility::ipTestParamsToString); -// Tunneling downstream TCP over an upstream HTTP channel. -class TcpTunnelingIntegrationTest : public testing::TestWithParam, +using Params = std::tuple; + +// Tunneling downstream TCP over an upstream HTTP CONNECT tunnel. +class TcpTunnelingIntegrationTest : public testing::TestWithParam, public HttpIntegrationTest { public: - TcpTunnelingIntegrationTest() : HttpIntegrationTest(Http::CodecClient::Type::HTTP2, GetParam()) {} + TcpTunnelingIntegrationTest() + : HttpIntegrationTest(Http::CodecClient::Type::HTTP2, std::get<0>(GetParam())) {} + + static std::string paramsToString(const testing::TestParamInfo& p) { + return fmt::format("{}_{}", + std::get<0>(p.param) == Network::Address::IpVersion::v4 ? "IPv4" : "IPv6", + std::get<1>(p.param) == FakeHttpConnection::Type::HTTP1 ? "HTTP1Upstream" + : "HTTP2Upstream"); + } void SetUp() override { enable_half_close_ = true; setDownstreamProtocol(Http::CodecClient::Type::HTTP2); - setUpstreamProtocol(FakeHttpConnection::Type::HTTP2); + setUpstreamProtocol(std::get<1>(GetParam())); config_helper_.addConfigModifier( [&](envoy::config::bootstrap::v3::Bootstrap& bootstrap) -> void { envoy::extensions::filters::network::tcp_proxy::v3::TcpProxy proxy_config; proxy_config.set_stat_prefix("tcp_stats"); proxy_config.set_cluster("cluster_0"); - proxy_config.mutable_tunneling_config()->set_hostname("host.com"); + proxy_config.mutable_tunneling_config()->set_hostname("host.com:80"); auto* listener = bootstrap.mutable_static_resources()->add_listeners(); listener->set_name("tcp_proxy"); auto* socket_address = listener->mutable_address()->mutable_socket_address(); - socket_address->set_address(Network::Test::getLoopbackAddressString(GetParam())); + socket_address->set_address( + Network::Test::getLoopbackAddressString(std::get<0>(GetParam()))); socket_address->set_port_value(0); auto* filter_chain = listener->add_filter_chains(); @@ -368,27 +379,13 @@ TEST_P(TcpTunnelingIntegrationTest, Basic) { ASSERT_TRUE(tcp_client->write("hello", false)); tcp_client->close(); ASSERT_TRUE(upstream_request_->waitForData(*dispatcher_, 5)); - ASSERT_TRUE(upstream_request_->waitForEndStream(*dispatcher_)); - - // If the upstream now sends 'end stream' the connection is fully closed. - upstream_request_->encodeData(0, true); -} - -// Validates that if the cluster is not configured with HTTP/2 we don't attempt -// to tunnel the data. -TEST_P(TcpTunnelingIntegrationTest, InvalidCluster) { - config_helper_.addConfigModifier([&](envoy::config::bootstrap::v3::Bootstrap& bootstrap) -> void { - bootstrap.mutable_static_resources() - ->mutable_clusters() - ->Mutable(0) - ->clear_http2_protocol_options(); - }); - initialize(); - - // Start a connection and see it close immediately due to the invalid cluster. - IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("tcp_proxy")); - tcp_client->waitForHalfClose(); - tcp_client->close(); + if (upstreamProtocol() == FakeHttpConnection::Type::HTTP1) { + ASSERT_TRUE(fake_upstream_connection_->waitForDisconnect()); + } else { + ASSERT_TRUE(upstream_request_->waitForEndStream(*dispatcher_)); + // If the upstream now sends 'end stream' the connection is fully closed. + upstream_request_->encodeData(0, true); + } } TEST_P(TcpTunnelingIntegrationTest, InvalidResponseHeaders) { @@ -404,7 +401,11 @@ TEST_P(TcpTunnelingIntegrationTest, InvalidResponseHeaders) { // upstream gets a stream reset. default_response_headers_.setStatus(enumToInt(Http::Code::ServiceUnavailable)); upstream_request_->encodeHeaders(default_response_headers_, false); - ASSERT_TRUE(upstream_request_->waitForReset()); + if (upstreamProtocol() == FakeHttpConnection::Type::HTTP1) { + ASSERT_TRUE(fake_upstream_connection_->waitForDisconnect()); + } else { + ASSERT_TRUE(upstream_request_->waitForReset()); + } // The connection should be fully closed, but the client has no way of knowing // that. Ensure the FIN is read and clean up state. @@ -429,20 +430,31 @@ TEST_P(TcpTunnelingIntegrationTest, CloseUpstreamFirst) { // Send data from upstream to downstream with an end stream and make sure the data is received // before the connection is half-closed. upstream_request_->encodeData(12, true); + if (upstreamProtocol() == FakeHttpConnection::Type::HTTP1) { + ASSERT_TRUE(fake_upstream_connection_->close()); + } ASSERT_TRUE(tcp_client->waitForData(12)); tcp_client->waitForHalfClose(); - // Attempt to send data upstream. - // should go through. - ASSERT_TRUE(tcp_client->write("hello", false)); - ASSERT_TRUE(upstream_request_->waitForData(*dispatcher_, 5)); - - ASSERT_TRUE(tcp_client->write("hello", true)); - ASSERT_TRUE(upstream_request_->waitForData(*dispatcher_, 5)); - ASSERT_TRUE(upstream_request_->waitForEndStream(*dispatcher_)); + if (upstreamProtocol() == FakeHttpConnection::Type::HTTP1) { + ASSERT_TRUE(fake_upstream_connection_->waitForDisconnect()); + tcp_client->close(); + } else { + // Attempt to send data upstream. + // should go through. + ASSERT_TRUE(tcp_client->write("hello", false)); + ASSERT_TRUE(upstream_request_->waitForData(*dispatcher_, 5)); + + ASSERT_TRUE(tcp_client->write("hello", true)); + ASSERT_TRUE(upstream_request_->waitForData(*dispatcher_, 5)); + ASSERT_TRUE(upstream_request_->waitForEndStream(*dispatcher_)); + } } TEST_P(TcpTunnelingIntegrationTest, ResetStreamTest) { + if (upstreamProtocol() == FakeHttpConnection::Type::HTTP1) { + return; + } enable_half_close_ = false; initialize(); @@ -490,7 +502,12 @@ TEST_P(TcpTunnelingIntegrationTest, TestIdletimeoutWithLargeOutstandingData) { upstream_request_->encodeData(data, false); tcp_client->waitForDisconnect(); - ASSERT_TRUE(upstream_request_->waitForReset()); + if (upstreamProtocol() == FakeHttpConnection::Type::HTTP1) { + ASSERT_TRUE(fake_upstream_connection_->waitForDisconnect()); + tcp_client->close(); + } else { + ASSERT_TRUE(upstream_request_->waitForReset()); + } } // Test that a downstream flush works correctly (all data is flushed) @@ -508,18 +525,29 @@ TEST_P(TcpTunnelingIntegrationTest, TcpProxyDownstreamFlush) { upstream_request_->encodeHeaders(default_response_headers_, false); tcp_client->readDisable(true); - ASSERT_TRUE(tcp_client->write("", true)); + if (upstreamProtocol() == FakeHttpConnection::Type::HTTP1) { + ASSERT_TRUE(tcp_client->write("hello", false)); + ASSERT_TRUE(upstream_request_->waitForData(*dispatcher_, 5)); - // This ensures that readDisable(true) has been run on its thread - // before tcp_client starts writing. - ASSERT_TRUE(upstream_request_->waitForEndStream(*dispatcher_)); + upstream_request_->encodeData(data, true); + ASSERT_TRUE(fake_upstream_connection_->close()); + } else { + ASSERT_TRUE(tcp_client->write("", true)); + + // This ensures that readDisable(true) has been run on its thread + // before tcp_client starts writing. + ASSERT_TRUE(upstream_request_->waitForEndStream(*dispatcher_)); - upstream_request_->encodeData(data, true); + upstream_request_->encodeData(data, true); + } test_server_->waitForCounterGe("cluster.cluster_0.upstream_flow_control_paused_reading_total", 1); tcp_client->readDisable(false); tcp_client->waitForData(data); tcp_client->waitForHalfClose(); + if (upstreamProtocol() == FakeHttpConnection::Type::HTTP1) { + tcp_client->close(); + } } // Test that an upstream flush works correctly (all data is flushed) @@ -543,19 +571,29 @@ TEST_P(TcpTunnelingIntegrationTest, TcpProxyUpstreamFlush) { ASSERT_TRUE(tcp_client->waitForData(5)); ASSERT_TRUE(tcp_client->write(data, true)); + if (upstreamProtocol() == FakeHttpConnection::Type::HTTP1) { + tcp_client->close(); - // Note that upstream_flush_active will *not* be incremented for the HTTP - // tunneling case. The data is already written to the stream, so no drainer - // is necessary. - upstream_request_->readDisable(false); - ASSERT_TRUE(upstream_request_->waitForData(*dispatcher_, size)); - ASSERT_TRUE(upstream_request_->waitForEndStream(*dispatcher_)); - upstream_request_->encodeData("world", true); - tcp_client->waitForHalfClose(); + upstream_request_->readDisable(false); + ASSERT_TRUE(upstream_request_->waitForData(*dispatcher_, size)); + ASSERT_TRUE(fake_upstream_connection_->waitForDisconnect()); + } else { + // Note that upstream_flush_active will *not* be incremented for the HTTP + // tunneling case. The data is already written to the stream, so no drainer + // is necessary. + upstream_request_->readDisable(false); + ASSERT_TRUE(upstream_request_->waitForData(*dispatcher_, size)); + ASSERT_TRUE(upstream_request_->waitForEndStream(*dispatcher_)); + upstream_request_->encodeData("world", true); + tcp_client->waitForHalfClose(); + } } // Test that h2 connection is reused. TEST_P(TcpTunnelingIntegrationTest, H2ConnectionReuse) { + if (upstreamProtocol() == FakeHttpConnection::Type::HTTP1) { + return; + } initialize(); // Establish a connection. @@ -597,9 +635,186 @@ TEST_P(TcpTunnelingIntegrationTest, H2ConnectionReuse) { ASSERT_TRUE(upstream_request_->waitForEndStream(*dispatcher_)); } -INSTANTIATE_TEST_SUITE_P(IpVersions, TcpTunnelingIntegrationTest, - testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), - TestUtility::ipTestParamsToString); +// Test that with HTTP1 we have no connection reuse with downstream close. +TEST_P(TcpTunnelingIntegrationTest, H1NoConnectionReuse) { + if (upstreamProtocol() == FakeHttpConnection::Type::HTTP2) { + return; + } + initialize(); + + // Establish a connection. + IntegrationTcpClientPtr tcp_client1 = makeTcpConnection(lookupPort("tcp_proxy")); + ASSERT_TRUE(fake_upstreams_[0]->waitForHttpConnection(*dispatcher_, fake_upstream_connection_)); + ASSERT_TRUE(fake_upstream_connection_->waitForNewStream(*dispatcher_, upstream_request_)); + ASSERT_TRUE(upstream_request_->waitForHeadersComplete()); + upstream_request_->encodeHeaders(default_response_headers_, false); + + // Send data in both directions. + ASSERT_TRUE(tcp_client1->write("hello1", false)); + ASSERT_TRUE(upstream_request_->waitForData(*dispatcher_, "hello1")); + + // Send data from upstream to downstream and close the connection + // from downstream. + upstream_request_->encodeData("world1", false); + tcp_client1->waitForData("world1"); + tcp_client1->close(); + + ASSERT_TRUE(fake_upstream_connection_->waitForDisconnect()); + + // Establish a new connection. + IntegrationTcpClientPtr tcp_client2 = makeTcpConnection(lookupPort("tcp_proxy")); + // A new connection is established + ASSERT_TRUE(fake_upstreams_[0]->waitForHttpConnection(*dispatcher_, fake_upstream_connection_)); + ASSERT_TRUE(fake_upstream_connection_->waitForNewStream(*dispatcher_, upstream_request_)); + ASSERT_TRUE(upstream_request_->waitForHeadersComplete()); + upstream_request_->encodeHeaders(default_response_headers_, false); + + ASSERT_TRUE(tcp_client2->write("hello1", false)); + ASSERT_TRUE(upstream_request_->waitForData(*dispatcher_, "hello1")); + tcp_client2->close(); + + ASSERT_TRUE(fake_upstream_connection_->waitForDisconnect()); +} + +// Test that with HTTP1 we have no connection with upstream close. +TEST_P(TcpTunnelingIntegrationTest, H1UpstreamCloseNoConnectionReuse) { + if (upstreamProtocol() == FakeHttpConnection::Type::HTTP2) { + return; + } + initialize(); + + // Establish a connection. + IntegrationTcpClientPtr tcp_client1 = makeTcpConnection(lookupPort("tcp_proxy")); + ASSERT_TRUE(fake_upstreams_[0]->waitForHttpConnection(*dispatcher_, fake_upstream_connection_)); + ASSERT_TRUE(fake_upstream_connection_->waitForNewStream(*dispatcher_, upstream_request_)); + ASSERT_TRUE(upstream_request_->waitForHeadersComplete()); + upstream_request_->encodeHeaders(default_response_headers_, false); + + // Send data in both directions. + ASSERT_TRUE(tcp_client1->write("hello1", false)); + ASSERT_TRUE(upstream_request_->waitForData(*dispatcher_, "hello1")); + + // Send data from upstream to downstream and close the connection + // from the upstream. + upstream_request_->encodeData("world1", false); + tcp_client1->waitForData("world1"); + ASSERT_TRUE(fake_upstream_connection_->close()); + + ASSERT_TRUE(fake_upstream_connection_->waitForDisconnect()); + tcp_client1->waitForHalfClose(); + tcp_client1->close(); + + // Establish a new connection. + IntegrationTcpClientPtr tcp_client2 = makeTcpConnection(lookupPort("tcp_proxy")); + // A new connection is established + ASSERT_TRUE(fake_upstreams_[0]->waitForHttpConnection(*dispatcher_, fake_upstream_connection_)); + ASSERT_TRUE(fake_upstream_connection_->waitForNewStream(*dispatcher_, upstream_request_)); + ASSERT_TRUE(upstream_request_->waitForHeadersComplete()); + upstream_request_->encodeHeaders(default_response_headers_, false); + + ASSERT_TRUE(tcp_client2->write("hello2", false)); + ASSERT_TRUE(upstream_request_->waitForData(*dispatcher_, "hello2")); + ASSERT_TRUE(fake_upstream_connection_->close()); + + ASSERT_TRUE(fake_upstream_connection_->waitForDisconnect()); + tcp_client2->waitForHalfClose(); + tcp_client2->close(); +} + +TEST_P(TcpTunnelingIntegrationTest, 2xxStatusCodeValidHttp1) { + if (upstreamProtocol() == FakeHttpConnection::Type::HTTP2) { + return; + } + initialize(); + + // Start a connection, and verify the upgrade headers are received upstream. + IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("tcp_proxy")); + ASSERT_TRUE(fake_upstreams_[0]->waitForHttpConnection(*dispatcher_, fake_upstream_connection_)); + ASSERT_TRUE(fake_upstream_connection_->waitForNewStream(*dispatcher_, upstream_request_)); + ASSERT_TRUE(upstream_request_->waitForHeadersComplete()); + + // Send valid response headers, in HTTP1 all status codes in the 2xx range + // are considered valid. + default_response_headers_.setStatus(enumToInt(Http::Code::Accepted)); + upstream_request_->encodeHeaders(default_response_headers_, false); + + // Send some data from downstream to upstream, and make sure it goes through. + ASSERT_TRUE(tcp_client->write("hello", false)); + ASSERT_TRUE(upstream_request_->waitForData(*dispatcher_, 5)); + + // Send data from upstream to downstream. + upstream_request_->encodeData(12, false); + ASSERT_TRUE(tcp_client->waitForData(12)); + + // Close the downstream connection and wait for upstream disconnect + tcp_client->close(); + ASSERT_TRUE(fake_upstream_connection_->waitForDisconnect()); +} + +TEST_P(TcpTunnelingIntegrationTest, ContentLengthHeaderIgnoredHttp1) { + if (upstreamProtocol() == FakeHttpConnection::Type::HTTP2) { + return; + } + initialize(); + + // Start a connection, and verify the upgrade headers are received upstream. + IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("tcp_proxy")); + ASSERT_TRUE(fake_upstreams_[0]->waitForHttpConnection(*dispatcher_, fake_upstream_connection_)); + ASSERT_TRUE(fake_upstream_connection_->waitForNewStream(*dispatcher_, upstream_request_)); + ASSERT_TRUE(upstream_request_->waitForHeadersComplete()); + + // Send upgrade headers downstream, including content-length that must be + // ignored. + default_response_headers_.setStatus(enumToInt(Http::Code::IMUsed)); + default_response_headers_.setContentLength(10); + upstream_request_->encodeHeaders(default_response_headers_, false); + + // Send data from upstream to downstream. + upstream_request_->encodeData(12, false); + ASSERT_TRUE(tcp_client->waitForData(12)); + + // Now send some data and close the TCP client. + ASSERT_TRUE(tcp_client->write("hello", false)); + tcp_client->close(); + ASSERT_TRUE(upstream_request_->waitForData(*dispatcher_, 5)); + ASSERT_TRUE(fake_upstream_connection_->waitForDisconnect()); +} + +// TODO(irozzo): temporarily disabled as a protocol error is thrown when +// transfer-encoding header is received in CONNECT responses. +TEST_P(TcpTunnelingIntegrationTest, DISABLED_TransferEncodingHeaderIgnoredHttp1) { + if (upstreamProtocol() == FakeHttpConnection::Type::HTTP2) { + return; + } + initialize(); + + // Start a connection, and verify the upgrade headers are received upstream. + IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("tcp_proxy")); + // Using raw connection to be able to set Transfer-encoding header. + FakeRawConnectionPtr fake_upstream_connection; + ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection)); + std::string data; + ASSERT_TRUE(fake_upstream_connection->waitForData( + FakeRawConnection::waitForInexactMatch("\r\n\r\n"), &data)); + ASSERT_THAT(data, testing::HasSubstr("CONNECT host.com:80 HTTP/1.1")); + + // Send upgrade headers downstream, fully establishing the connection. + ASSERT_TRUE( + fake_upstream_connection->write("HTTP/1.1 299 OK\r\nTransfer-encoding: chunked\r\n\r\n")); + + // Now send some data and close the TCP client. + ASSERT_TRUE(tcp_client->write("hello", false)); + tcp_client->close(); + ASSERT_TRUE(upstream_request_->waitForData(*dispatcher_, 5)); + ASSERT_TRUE(fake_upstream_connection_->waitForDisconnect()); +} + +INSTANTIATE_TEST_SUITE_P( + IpAndHttpVersions, TcpTunnelingIntegrationTest, + ::testing::Combine(testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), + testing::Values(FakeHttpConnection::Type::HTTP1, + FakeHttpConnection::Type::HTTP2)), + TcpTunnelingIntegrationTest::paramsToString); } // namespace } // namespace Envoy diff --git a/test/integration/upstreams/BUILD b/test/integration/upstreams/BUILD new file mode 100644 index 0000000000000..ddf0326374081 --- /dev/null +++ b/test/integration/upstreams/BUILD @@ -0,0 +1,30 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_library", + "envoy_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_package() + +envoy_cc_library( + name = "per_host_upstream_config", + srcs = [ + "per_host_upstream_config.h", + ], + deps = [ + "//include/envoy/http:codes_interface", + "//include/envoy/http:conn_pool_interface", + "//include/envoy/http:filter_interface", + "//include/envoy/upstream:cluster_manager_interface", + "//include/envoy/upstream:upstream_interface", + "//source/common/common:assert_lib", + "//source/common/http:header_map_lib", + "//source/common/http:headers_lib", + "//source/common/router:router_lib", + "//source/common/upstream:load_balancer_lib", + "//source/extensions/upstreams/http/http:upstream_request_lib", + "//source/extensions/upstreams/http/tcp:upstream_request_lib", + ], +) diff --git a/test/integration/upstreams/per_host_upstream_config.h b/test/integration/upstreams/per_host_upstream_config.h new file mode 100644 index 0000000000000..4fc498bda316c --- /dev/null +++ b/test/integration/upstreams/per_host_upstream_config.h @@ -0,0 +1,116 @@ +#pragma once + +#include "envoy/http/conn_pool.h" +#include "envoy/http/metadata_interface.h" +#include "envoy/http/protocol.h" +#include "envoy/router/router.h" +#include "envoy/upstream/cluster_manager.h" +#include "envoy/upstream/host_description.h" + +#include "common/http/header_map_impl.h" +#include "common/router/router.h" +#include "common/router/upstream_request.h" + +#include "extensions/upstreams/http/http/upstream_request.h" + +namespace Envoy { + +namespace { + +/** + * A helper to add header into header map from metadata. The added value is `metadata[key1][key2]`. + * + * @param header_map The mutable header map. + * @param header_name The target header entry in the `header_map`. + * @param metadata The source of header value. + * @param key1 The key to the value in metadata. + * @param key2 The second key to the value after `key1` is selected. + */ +void addHeader(Envoy::Http::RequestHeaderMap& header_map, absl::string_view header_name, + const envoy::config::core::v3::Metadata& metadata, absl::string_view key1, + absl::string_view key2) { + if (auto filter_metadata = metadata.filter_metadata().find(key1); + filter_metadata != metadata.filter_metadata().end()) { + const ProtobufWkt::Struct& data_struct = filter_metadata->second; + const auto& fields = data_struct.fields(); + if (auto iter = fields.find(key2); iter != fields.end()) { + if (iter->second.kind_case() == ProtobufWkt::Value::kStringValue) { + header_map.setCopy(Envoy::Http::LowerCaseString(std::string(header_name)), + iter->second.string_value()); + } + } + } +} +} // namespace + +// The http upstream to remember the host and encode the host metadata and cluster metadata into +// upstream http request. +class PerHostHttpUpstream : public Extensions::Upstreams::Http::Http::HttpUpstream { +public: + PerHostHttpUpstream(Router::UpstreamToDownstream& upstream_request, + Envoy::Http::RequestEncoder* encoder, + Upstream::HostDescriptionConstSharedPtr host) + : HttpUpstream(upstream_request, encoder), host_(host) {} + + Http::Status encodeHeaders(const Envoy::Http::RequestHeaderMap& headers, + bool end_stream) override { + auto dup = Envoy::Http::RequestHeaderMapImpl::create(); + Envoy::Http::HeaderMapImpl::copyFrom(*dup, headers); + dup->setCopy(Envoy::Http::LowerCaseString("X-foo"), "foo-common"); + addHeader(*dup, "X-cluster-foo", host_->cluster().metadata(), "foo", "bar"); + if (host_->metadata() != nullptr) { + addHeader(*dup, "X-host-foo", *host_->metadata(), "foo", "bar"); + } + return HttpUpstream::encodeHeaders(*dup, end_stream); + } + +private: + Upstream::HostDescriptionConstSharedPtr host_; +}; + +class PerHostHttpConnPool : public Extensions::Upstreams::Http::Http::HttpConnPool { +public: + PerHostHttpConnPool(Upstream::ClusterManager& cm, bool is_connect, + const Router::RouteEntry& route_entry, + absl::optional downstream_protocol, + Upstream::LoadBalancerContext* ctx) + : HttpConnPool(cm, is_connect, route_entry, downstream_protocol, ctx) {} + + void onPoolReady(Envoy::Http::RequestEncoder& callbacks_encoder, + Upstream::HostDescriptionConstSharedPtr host, + const StreamInfo::StreamInfo& info) override { + conn_pool_stream_handle_ = nullptr; + auto upstream = std::make_unique(callbacks_->upstreamToDownstream(), + &callbacks_encoder, host); + callbacks_->onPoolReady(std::move(upstream), host, + callbacks_encoder.getStream().connectionLocalAddress(), info); + } +}; + +/** + * Config registration for the HttpConnPool. @see Router::GenericConnPoolFactory + */ +class PerHostGenericConnPoolFactory : public Router::GenericConnPoolFactory { +public: + std::string name() const override { return "envoy.filters.connection_pools.http.per_host"; } + std::string category() const override { return "envoy.upstreams"; } + Router::GenericConnPoolPtr + createGenericConnPool(Upstream::ClusterManager& cm, bool is_connect, + const Router::RouteEntry& route_entry, + absl::optional downstream_protocol, + Upstream::LoadBalancerContext* ctx) const override { + if (is_connect) { + // This example factory doesn't support terminating CONNECT stream. + return nullptr; + } + auto upstream_http_conn_pool = std::make_unique( + cm, is_connect, route_entry, downstream_protocol, ctx); + return (upstream_http_conn_pool->valid() ? std::move(upstream_http_conn_pool) : nullptr); + } + + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique(); + } +}; + +} // namespace Envoy \ No newline at end of file diff --git a/test/mocks/event/mocks.h b/test/mocks/event/mocks.h index 861f0a10e3405..957f06222521f 100644 --- a/test/mocks/event/mocks.h +++ b/test/mocks/event/mocks.h @@ -227,6 +227,8 @@ class MockFileEvent : public FileEvent { MOCK_METHOD(void, activate, (uint32_t events)); MOCK_METHOD(void, setEnabled, (uint32_t events)); + MOCK_METHOD(void, registerEventIfEmulatedEdge, (uint32_t event)); + MOCK_METHOD(void, unregisterEventIfEmulatedEdge, (uint32_t event)); }; } // namespace Event diff --git a/test/mocks/http/stream_encoder.h b/test/mocks/http/stream_encoder.h index df3d62c00e71d..8e023f4d98db3 100644 --- a/test/mocks/http/stream_encoder.h +++ b/test/mocks/http/stream_encoder.h @@ -17,6 +17,7 @@ class MockHttp1StreamEncoderOptions : public Http1StreamEncoderOptions { ~MockHttp1StreamEncoderOptions() override; MOCK_METHOD(void, disableChunkEncoding, ()); + MOCK_METHOD(void, enableHalfClose, ()); }; class MockRequestEncoder : public RequestEncoder { diff --git a/test/mocks/network/connection.h b/test/mocks/network/connection.h index d33d4797f9927..2bf02ccfdc6a9 100644 --- a/test/mocks/network/connection.h +++ b/test/mocks/network/connection.h @@ -55,6 +55,7 @@ class MockConnectionBase { MOCK_METHOD(void, addReadFilter, (ReadFilterSharedPtr filter)); \ MOCK_METHOD(void, removeReadFilter, (ReadFilterSharedPtr filter)); \ MOCK_METHOD(void, enableHalfClose, (bool enabled)); \ + MOCK_METHOD(bool, isHalfCloseEnabled, ()); \ MOCK_METHOD(void, close, (ConnectionCloseType type)); \ MOCK_METHOD(Event::Dispatcher&, dispatcher, ()); \ MOCK_METHOD(uint64_t, id, (), (const)); \ @@ -138,6 +139,7 @@ class MockFilterManagerConnection : public FilterManagerConnection, public MockC MOCK_METHOD(void, addReadFilter, (ReadFilterSharedPtr filter)); MOCK_METHOD(void, removeReadFilter, (ReadFilterSharedPtr filter)); MOCK_METHOD(void, enableHalfClose, (bool enabled)); + MOCK_METHOD(bool, isHalfCloseEnabled, ()); MOCK_METHOD(void, close, (ConnectionCloseType type)); MOCK_METHOD(Event::Dispatcher&, dispatcher, ()); MOCK_METHOD(uint64_t, id, (), (const)); diff --git a/test/mocks/server/BUILD b/test/mocks/server/BUILD index 7214ca8203715..84fe48578be9a 100644 --- a/test/mocks/server/BUILD +++ b/test/mocks/server/BUILD @@ -37,6 +37,14 @@ envoy_cc_mock( ], ) +envoy_cc_mock( + name = "fatal_action_factory_mocks", + hdrs = ["fatal_action_factory.h"], + deps = [ + "//include/envoy/server:fatal_action_interface", + ], +) + envoy_cc_mock( name = "options_mocks", srcs = ["options.cc"], @@ -306,6 +314,7 @@ envoy_cc_mock( "//test/mocks/server:config_tracker_mocks", "//test/mocks/server:drain_manager_mocks", "//test/mocks/server:factory_context_mocks", + "//test/mocks/server:fatal_action_factory_mocks", "//test/mocks/server:filter_chain_factory_context_mocks", "//test/mocks/server:guard_dog_mocks", "//test/mocks/server:health_checker_factory_context_mocks", diff --git a/test/mocks/server/fatal_action_factory.h b/test/mocks/server/fatal_action_factory.h new file mode 100644 index 0000000000000..751b3f6e1528f --- /dev/null +++ b/test/mocks/server/fatal_action_factory.h @@ -0,0 +1,20 @@ +#pragma once + +#include "envoy/server/fatal_action_config.h" + +#include "gmock/gmock.h" + +namespace Envoy { +namespace Server { +namespace Configuration { +class MockFatalActionFactory : public FatalActionFactory { +public: + MOCK_METHOD(FatalActionPtr, createFatalActionFromProto, + (const envoy::config::bootstrap::v3::FatalAction& config, Instance* server), + (override)); + MOCK_METHOD(ProtobufTypes::MessagePtr, createEmptyConfigProto, (), (override)); + MOCK_METHOD(std::string, name, (), (const, override)); +}; +} // namespace Configuration +} // namespace Server +} // namespace Envoy diff --git a/test/mocks/server/mocks.h b/test/mocks/server/mocks.h index d041412d01d17..731d4c22778ee 100644 --- a/test/mocks/server/mocks.h +++ b/test/mocks/server/mocks.h @@ -8,6 +8,7 @@ #include "config_tracker.h" #include "drain_manager.h" #include "factory_context.h" +#include "fatal_action_factory.h" #include "filter_chain_factory_context.h" #include "guard_dog.h" #include "health_checker_factory_context.h" diff --git a/test/mocks/server/overload_manager.cc b/test/mocks/server/overload_manager.cc index d4485442386ba..461b0b27daa3d 100644 --- a/test/mocks/server/overload_manager.cc +++ b/test/mocks/server/overload_manager.cc @@ -17,12 +17,18 @@ using ::testing::ReturnRef; MockThreadLocalOverloadState::MockThreadLocalOverloadState() : disabled_state_(OverloadActionState::inactive()) { ON_CALL(*this, getState).WillByDefault(ReturnRef(disabled_state_)); - ON_CALL(*this, createScaledTimer_).WillByDefault(ReturnNew>()); + ON_CALL(*this, createScaledTypedTimer_).WillByDefault(ReturnNew>()); + ON_CALL(*this, createScaledMinimumTimer_).WillByDefault(ReturnNew>()); } Event::TimerPtr MockThreadLocalOverloadState::createScaledTimer(OverloadTimerType timer_type, Event::TimerCb callback) { - return Event::TimerPtr{createScaledTimer_(timer_type, std::move(callback))}; + return Event::TimerPtr{createScaledTypedTimer_(timer_type, std::move(callback))}; +} + +Event::TimerPtr MockThreadLocalOverloadState::createScaledTimer(Event::ScaledTimerMinimum minimum, + Event::TimerCb callback) { + return Event::TimerPtr{createScaledMinimumTimer_(minimum, std::move(callback))}; } MockOverloadManager::MockOverloadManager() { diff --git a/test/mocks/server/overload_manager.h b/test/mocks/server/overload_manager.h index 03fe54aa32321..c694ab7b12548 100644 --- a/test/mocks/server/overload_manager.h +++ b/test/mocks/server/overload_manager.h @@ -15,7 +15,11 @@ class MockThreadLocalOverloadState : public ThreadLocalOverloadState { MockThreadLocalOverloadState(); MOCK_METHOD(const OverloadActionState&, getState, (const std::string&), (override)); Event::TimerPtr createScaledTimer(OverloadTimerType timer_type, Event::TimerCb callback) override; - MOCK_METHOD(Event::Timer*, createScaledTimer_, (OverloadTimerType, Event::TimerCb)); + Event::TimerPtr createScaledTimer(Event::ScaledTimerMinimum minimum, + Event::TimerCb callback) override; + MOCK_METHOD(Event::Timer*, createScaledTypedTimer_, (OverloadTimerType, Event::TimerCb)); + MOCK_METHOD(Event::Timer*, createScaledMinimumTimer_, + (Event::ScaledTimerMinimum, Event::TimerCb)); private: const OverloadActionState disabled_state_; diff --git a/test/mocks/upstream/cluster_manager.h b/test/mocks/upstream/cluster_manager.h index c24b1b045acda..cc3071052f677 100644 --- a/test/mocks/upstream/cluster_manager.h +++ b/test/mocks/upstream/cluster_manager.h @@ -42,7 +42,8 @@ class MockClusterManager : public ClusterManager { MOCK_METHOD(void, setInitializedCb, (InitializationCompleteCallback)); MOCK_METHOD(void, initializeSecondaryClusters, (const envoy::config::bootstrap::v3::Bootstrap& bootstrap)); - MOCK_METHOD(ClusterInfoMap, clusters, ()); + MOCK_METHOD(ClusterInfoMaps, clusters, ()); + MOCK_METHOD(const ClusterSet&, primaryClusters, ()); MOCK_METHOD(ThreadLocalCluster*, get, (absl::string_view cluster)); MOCK_METHOD(Http::ConnectionPool::Instance*, httpConnPoolForCluster, diff --git a/test/mocks/upstream/cluster_manager_factory.h b/test/mocks/upstream/cluster_manager_factory.h index cdcc952d090b0..00e4b6c409beb 100644 --- a/test/mocks/upstream/cluster_manager_factory.h +++ b/test/mocks/upstream/cluster_manager_factory.h @@ -23,12 +23,13 @@ class MockClusterManagerFactory : public ClusterManagerFactory { MOCK_METHOD(Http::ConnectionPool::InstancePtr, allocateConnPool, (Event::Dispatcher & dispatcher, HostConstSharedPtr host, ResourcePriority priority, Http::Protocol protocol, const Network::ConnectionSocket::OptionsSharedPtr& options, - const Network::TransportSocketOptionsSharedPtr& transport_socket_options)); + const Network::TransportSocketOptionsSharedPtr& transport_socket_options, + ClusterConnectivityState& state)); MOCK_METHOD(Tcp::ConnectionPool::InstancePtr, allocateTcpConnPool, (Event::Dispatcher & dispatcher, HostConstSharedPtr host, ResourcePriority priority, const Network::ConnectionSocket::OptionsSharedPtr& options, - Network::TransportSocketOptionsSharedPtr)); + Network::TransportSocketOptionsSharedPtr, ClusterConnectivityState& state)); MOCK_METHOD((std::pair), clusterFromProto, (const envoy::config::cluster::v3::Cluster& cluster, ClusterManager& cm, diff --git a/test/per_file_coverage.sh b/test/per_file_coverage.sh index 13526f0eebb2c..7813126d4c0eb 100755 --- a/test/per_file_coverage.sh +++ b/test/per_file_coverage.sh @@ -3,7 +3,8 @@ # directory:coverage_percent # for existing directories with low coverage. declare -a KNOWN_LOW_COVERAGE=( -"source/common/network:95.6" +"source/common/event:93.5" # Emulated edge events guards don't report LCOV +"source/common/network:95.1" "source/common/http/http3:50.0" "source/common/tracing:94.9" "source/common/protobuf:94.3" @@ -11,6 +12,7 @@ declare -a KNOWN_LOW_COVERAGE=( "source/common/singleton:95.1" "source/common/api:72.9" "source/common/api/posix:71.8" +"source/common/event:92.9" "source/common/filter:96.3" "source/common/filter/http:96.3" "source/common/init:96.2" @@ -20,7 +22,7 @@ declare -a KNOWN_LOW_COVERAGE=( "source/common/crypto:0.0" "source/common/common:96.1" "source/common/common/posix:94.1" -"source/common/signal:90.4" +"source/common/signal:83.1" # Death tests don't report LCOV "source/common/watchdog:42.9" # Death tests don't report LCOV "source/exe:93.7" "source/extensions:96.3" @@ -42,6 +44,7 @@ declare -a KNOWN_LOW_COVERAGE=( "source/extensions/filters/http/cache/simple_http_cache:95.2" "source/extensions/filters/http/dynamic_forward_proxy:94.9" "source/extensions/filters/http/ip_tagging:91.2" +"source/extensions/filters/http/kill_request:94.4" # Death tests don't report LCOV "source/extensions/filters/http/grpc_json_transcoder:93.3" "source/extensions/filters/http/oauth2:96.5" "source/extensions/filters/listener:96.0" @@ -62,16 +65,19 @@ declare -a KNOWN_LOW_COVERAGE=( "source/extensions/tracers:96.0" "source/extensions/tracers/opencensus:91.2" "source/extensions/tracers/xray:94.0" -"source/extensions/transport_sockets:95.3" +"source/extensions/transport_sockets:95.1" "source/extensions/transport_sockets/tap:95.6" "source/extensions/transport_sockets/tls:94.2" "source/extensions/transport_sockets/tls/ocsp:95.3" "source/extensions/transport_sockets/tls/private_key:76.9" +"source/extensions/wasm_runtime:50.0" +"source/extensions/wasm_runtime/wasmtime:0.0" # Not enabled in coverage build +"source/extensions/wasm_runtime/wavm:0.0" # Noe enabled in coverage build "source/extensions/watchdog:69.6" # Death tests within extensions "source/extensions/watchdog/profile_action:84.9" -"source/server:94.6" +"source/server:94.5" "source/server/config_validation:76.6" -"source/server/admin:95.2" +"source/server/admin:95.1" ) [[ -z "${SRCDIR}" ]] && SRCDIR="${PWD}" diff --git a/test/proto/bookstore.proto b/test/proto/bookstore.proto index 62e697e219ee8..559ec4da0acee 100644 --- a/test/proto/bookstore.proto +++ b/test/proto/bookstore.proto @@ -134,6 +134,11 @@ service Bookstore { get: "/bigbook" }; } + rpc PostWildcard(EchoBodyRequest) returns (google.protobuf.Empty) { + option (google.api.http) = { + post: "/wildcard/{arg=**}" + }; + } } service ServiceWithResponseBody { diff --git a/test/run_envoy_bazel_coverage.sh b/test/run_envoy_bazel_coverage.sh index 48d8b47a57341..5e99411773c2a 100755 --- a/test/run_envoy_bazel_coverage.sh +++ b/test/run_envoy_bazel_coverage.sh @@ -2,6 +2,29 @@ set -e +LLVM_VERSION="10.0.0" +CLANG_VERSION=$(clang --version | grep version | sed -e 's/\ *clang version \(.*\)\ /\1/') +LLVM_COV_VERSION=$(llvm-cov --version | grep version | sed -e 's/\ *LLVM version \(.*\)/\1/') +LLVM_PROFDATA_VERSION=$(llvm-profdata show --version | grep version | sed -e 's/\ *LLVM version \(.*\)/\1/') + +if [ "${CLANG_VERSION}" != "${LLVM_VERSION}" ] +then + echo "clang version ${CLANG_VERSION} does not match expected ${LLVM_VERSION}" + exit 1 +fi + +if [ "${LLVM_COV_VERSION}" != "${LLVM_VERSION}" ] +then + echo "llvm-cov version ${LLVM_COV_VERSION} does not match expected ${LLVM_VERSION}" + exit 1 +fi + +if [ "${LLVM_PROFDATA_VERSION}" != "${LLVM_VERSION}" ] +then + echo "llvm-profdata version ${LLVM_PROFDATA_VERSION} does not match expected ${LLVM_VERSION}" + exit 1 +fi + [[ -z "${SRCDIR}" ]] && SRCDIR="${PWD}" [[ -z "${VALIDATE_COVERAGE}" ]] && VALIDATE_COVERAGE=true [[ -z "${FUZZ_COVERAGE}" ]] && FUZZ_COVERAGE=false diff --git a/test/server/BUILD b/test/server/BUILD index c26a2ebcc87ac..82766be214b2c 100644 --- a/test/server/BUILD +++ b/test/server/BUILD @@ -371,6 +371,7 @@ envoy_cc_test( "//test/common/stats:stat_test_utility_lib", "//test/integration:integration_lib", "//test/mocks/server:bootstrap_extension_factory_mocks", + "//test/mocks/server:fatal_action_factory_mocks", "//test/mocks/server:hot_restart_mocks", "//test/mocks/server:instance_mocks", "//test/mocks/server:options_mocks", diff --git a/test/server/admin/clusters_handler_test.cc b/test/server/admin/clusters_handler_test.cc index f0ba3f5ae7e56..4d41b6c24969a 100644 --- a/test/server/admin/clusters_handler_test.cc +++ b/test/server/admin/clusters_handler_test.cc @@ -14,11 +14,11 @@ INSTANTIATE_TEST_SUITE_P(IpVersions, AdminInstanceTest, TestUtility::ipTestParamsToString); TEST_P(AdminInstanceTest, ClustersJson) { - Upstream::ClusterManager::ClusterInfoMap cluster_map; - ON_CALL(server_.cluster_manager_, clusters()).WillByDefault(ReturnPointee(&cluster_map)); + Upstream::ClusterManager::ClusterInfoMaps cluster_maps; + ON_CALL(server_.cluster_manager_, clusters()).WillByDefault(ReturnPointee(&cluster_maps)); NiceMock cluster; - cluster_map.emplace(cluster.info_->name_, cluster); + cluster_maps.active_clusters_.emplace(cluster.info_->name_, cluster); NiceMock outlier_detector; ON_CALL(Const(cluster), outlierDetector()).WillByDefault(Return(&outlier_detector)); diff --git a/test/server/admin/config_dump_handler_test.cc b/test/server/admin/config_dump_handler_test.cc index 7c7f5f57781f8..6075dffa4a673 100644 --- a/test/server/admin/config_dump_handler_test.cc +++ b/test/server/admin/config_dump_handler_test.cc @@ -113,11 +113,11 @@ TEST_P(AdminInstanceTest, ConfigDumpMaintainsOrder) { // Test that using ?include_eds parameter adds EDS to the config dump. TEST_P(AdminInstanceTest, ConfigDumpWithEndpoint) { - Upstream::ClusterManager::ClusterInfoMap cluster_map; - ON_CALL(server_.cluster_manager_, clusters()).WillByDefault(ReturnPointee(&cluster_map)); + Upstream::ClusterManager::ClusterInfoMaps cluster_maps; + ON_CALL(server_.cluster_manager_, clusters()).WillByDefault(ReturnPointee(&cluster_maps)); NiceMock cluster; - cluster_map.emplace(cluster.info_->name_, cluster); + cluster_maps.active_clusters_.emplace(cluster.info_->name_, cluster); ON_CALL(*cluster.info_, addedViaApi()).WillByDefault(Return(false)); @@ -186,11 +186,11 @@ TEST_P(AdminInstanceTest, ConfigDumpWithEndpoint) { // Test EDS config dump while multiple localities and priorities exist TEST_P(AdminInstanceTest, ConfigDumpWithLocalityEndpoint) { - Upstream::ClusterManager::ClusterInfoMap cluster_map; - ON_CALL(server_.cluster_manager_, clusters()).WillByDefault(ReturnPointee(&cluster_map)); + Upstream::ClusterManager::ClusterInfoMaps cluster_maps; + ON_CALL(server_.cluster_manager_, clusters()).WillByDefault(ReturnPointee(&cluster_maps)); NiceMock cluster; - cluster_map.emplace(cluster.info_->name_, cluster); + cluster_maps.active_clusters_.emplace(cluster.info_->name_, cluster); ON_CALL(*cluster.info_, addedViaApi()).WillByDefault(Return(false)); @@ -398,11 +398,11 @@ TEST_P(AdminInstanceTest, ConfigDumpFiltersByResource) { // We add both static and dynamic endpoint config to the dump, but expect only // dynamic in the JSON with ?resource=dynamic_endpoint_configs. TEST_P(AdminInstanceTest, ConfigDumpWithEndpointFiltersByResource) { - Upstream::ClusterManager::ClusterInfoMap cluster_map; - ON_CALL(server_.cluster_manager_, clusters()).WillByDefault(ReturnPointee(&cluster_map)); + Upstream::ClusterManager::ClusterInfoMaps cluster_maps; + ON_CALL(server_.cluster_manager_, clusters()).WillByDefault(ReturnPointee(&cluster_maps)); NiceMock cluster_1; - cluster_map.emplace(cluster_1.info_->name_, cluster_1); + cluster_maps.active_clusters_.emplace(cluster_1.info_->name_, cluster_1); ON_CALL(*cluster_1.info_, addedViaApi()).WillByDefault(Return(true)); @@ -419,7 +419,7 @@ TEST_P(AdminInstanceTest, ConfigDumpWithEndpointFiltersByResource) { NiceMock cluster_2; cluster_2.info_->name_ = "fake_cluster_2"; - cluster_map.emplace(cluster_2.info_->name_, cluster_2); + cluster_maps.active_clusters_.emplace(cluster_2.info_->name_, cluster_2); ON_CALL(*cluster_2.info_, addedViaApi()).WillByDefault(Return(false)); diff --git a/test/server/configuration_impl_test.cc b/test/server/configuration_impl_test.cc index eeeba3585b770..c8e63cb180f6c 100644 --- a/test/server/configuration_impl_test.cc +++ b/test/server/configuration_impl_test.cc @@ -161,10 +161,10 @@ TEST_F(ConfigurationImplTest, SetUpstreamClusterPerConnectionBufferLimit) { MainImpl config; config.initialize(bootstrap, server_, cluster_manager_factory_); - ASSERT_EQ(1U, config.clusterManager()->clusters().count("test_cluster")); + ASSERT_EQ(1U, config.clusterManager()->clusters().active_clusters_.count("test_cluster")); EXPECT_EQ(8192U, config.clusterManager() ->clusters() - .find("test_cluster") + .active_clusters_.find("test_cluster") ->second.get() .info() ->perConnectionBufferLimitBytes()); diff --git a/test/server/listener_manager_impl_test.cc b/test/server/listener_manager_impl_test.cc index 3d21de26252ec..de70751f4d027 100644 --- a/test/server/listener_manager_impl_test.cc +++ b/test/server/listener_manager_impl_test.cc @@ -371,6 +371,20 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, UdpAddress) { EXPECT_EQ(1u, manager_->listeners().size()); } +TEST_F(ListenerManagerImplWithRealFiltersTest, AllowOnlyDefaultFilterChain) { + const std::string yaml = R"EOF( +address: + socket_address: + address: 127.0.0.1 + port_value: 1234 +default_filter_chain: + filters: [] + )EOF"; + + manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + EXPECT_EQ(1, manager_->listeners().size()); +} + TEST_F(ListenerManagerImplWithRealFiltersTest, BadListenerConfig) { const std::string yaml = R"EOF( address: @@ -3566,7 +3580,9 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateInvalidPrivateKey) Network::Address::IpVersion::v4); EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, "Failed to load private key from "); + EnvoyException, + "Failed to load private key from , " + "Cause: error:0900006e:PEM routines:OPENSSL_internal:NO_START_LINE"); } TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateInvalidTrustedCA) { @@ -3591,6 +3607,28 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateInvalidTrustedCA) { EnvoyException, "Failed to load trusted CA certificates from "); } +TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateCertPrivateKeyMismatch) { + const std::string yaml = TestEnvironment::substitute(R"EOF( + address: + socket_address: { address: 127.0.0.1, port_value: 1234 } + filter_chains: + - transport_socket: + name: tls + typed_config: + "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext + common_tls_context: + tls_certificates: + - certificate_chain: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns3_chain.pem" } + private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns2_key.pem" } + )EOF", + Network::Address::IpVersion::v4); + + EXPECT_THROW_WITH_REGEX( + manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), EnvoyException, + "Failed to load private key from .*, " + "Cause: error:0b000074:X.509 certificate routines:OPENSSL_internal:KEY_VALUES_MISMATCH"); +} + TEST_F(ListenerManagerImplWithRealFiltersTest, Metadata) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: diff --git a/test/server/overload_manager_impl_test.cc b/test/server/overload_manager_impl_test.cc index a134cfab60754..71fc4c6d290fe 100644 --- a/test/server/overload_manager_impl_test.cc +++ b/test/server/overload_manager_impl_test.cc @@ -558,6 +558,30 @@ TEST_F(OverloadManagerImplTest, CreateScaledTimerWithAbsoluteMinimum) { EXPECT_EQ(timer.get(), mock_scaled_timer); } +TEST_F(OverloadManagerImplTest, CreateScaledTimerWithProvidedMinimum) { + setDispatcherExpectation(); + auto manager(createOverloadManager(kReducedTimeoutsConfig)); + + auto* scaled_timer_manager = new Event::MockScaledRangeTimerManager(); + EXPECT_CALL(*manager, createScaledRangeTimerManager) + .WillOnce(Return(ByMove(Event::ScaledRangeTimerManagerPtr{scaled_timer_manager}))); + manager->start(); + + auto* mock_scaled_timer = new Event::MockTimer(); + MockFunction mock_callback; + EXPECT_CALL(*scaled_timer_manager, createTimer_) + .WillOnce([&](Event::ScaledTimerMinimum minimum, auto) { + // This timer was created with an absolute minimum. Test that by checking an arbitrary + // value. + EXPECT_EQ(minimum.computeMinimum(std::chrono::seconds(55)), std::chrono::seconds(3)); + return mock_scaled_timer; + }); + + auto timer = manager->getThreadLocalOverloadState().createScaledTimer( + Event::AbsoluteMinimum(std::chrono::seconds(3)), mock_callback.AsStdFunction()); + EXPECT_EQ(timer.get(), mock_scaled_timer); +} + TEST_F(OverloadManagerImplTest, DuplicateResourceMonitor) { const std::string config = R"EOF( resource_monitors: diff --git a/test/server/server_test.cc b/test/server/server_test.cc index d7abaf788c1d1..aa097fc787cf3 100644 --- a/test/server/server_test.cc +++ b/test/server/server_test.cc @@ -1,8 +1,10 @@ #include +#include "envoy/common/scope_tracker.h" #include "envoy/config/core/v3/base.pb.h" #include "envoy/network/exception.h" #include "envoy/server/bootstrap_extension_config.h" +#include "envoy/server/fatal_action_config.h" #include "common/common/assert.h" #include "common/network/address_impl.h" @@ -19,6 +21,7 @@ #include "test/common/stats/stat_test_utility.h" #include "test/integration/server.h" #include "test/mocks/server/bootstrap_extension_factory.h" +#include "test/mocks/server/fatal_action_factory.h" #include "test/mocks/server/hot_restart.h" #include "test/mocks/server/instance.h" #include "test/mocks/server/options.h" @@ -1212,6 +1215,72 @@ TEST_P(ServerInstanceImplTest, WithUnknownBootstrapExtensions) { "Didn't find a registered implementation for name: 'envoy_test.bootstrap.foo'"); } +// Insufficient support on Windows. +#ifndef WIN32 +class SafeFatalAction : public Configuration::FatalAction { +public: + void run(const ScopeTrackedObject* /*current_object*/) override { + std::cerr << "Called SafeFatalAction" << std::endl; + } + + bool isAsyncSignalSafe() const override { return true; } +}; + +class UnsafeFatalAction : public Configuration::FatalAction { +public: + void run(const ScopeTrackedObject* /*current_object*/) override { + std::cerr << "Called UnsafeFatalAction" << std::endl; + } + + bool isAsyncSignalSafe() const override { return false; } +}; + +TEST_P(ServerInstanceImplTest, WithFatalActions) { + // Inject Safe Factory. + NiceMock mock_safe_factory; + EXPECT_CALL(mock_safe_factory, createEmptyConfigProto()).WillRepeatedly(Invoke([]() { + return std::make_unique(); + })); + EXPECT_CALL(mock_safe_factory, name()).WillRepeatedly(Return("envoy_test.fatal_action.safe")); + + Registry::InjectFactory registered_safe_factory( + mock_safe_factory); + + // Inject Unsafe Factory + NiceMock mock_unsafe_factory; + EXPECT_CALL(mock_unsafe_factory, createEmptyConfigProto()).WillRepeatedly(Invoke([]() { + return std::make_unique(); + })); + EXPECT_CALL(mock_unsafe_factory, name()).WillRepeatedly(Return("envoy_test.fatal_action.unsafe")); + + Registry::InjectFactory registered_unsafe_factory( + mock_unsafe_factory); + + EXPECT_DEATH( + { + EXPECT_CALL(mock_safe_factory, createFatalActionFromProto(_, _)) + .WillOnce( + Invoke([](const envoy::config::bootstrap::v3::FatalAction& /*config*/, + Instance* /*server*/) { return std::make_unique(); })); + EXPECT_CALL(mock_unsafe_factory, createFatalActionFromProto(_, _)) + .WillOnce( + Invoke([](const envoy::config::bootstrap::v3::FatalAction& /*config*/, + Instance* /*server*/) { return std::make_unique(); })); + absl::Notification abort_called; + auto server_thread = + startTestServer("test/server/test_data/server/fatal_actions.yaml", false); + // Trigger SIGABRT, wait for the ABORT + server_->dispatcher().post([&] { + abort(); + abort_called.Notify(); + }); + + abort_called.WaitForNotification(); + }, + ""); +} +#endif + // Static configuration validation. We test with both allow/reject settings various aspects of // configuration from YAML. class StaticValidationTest diff --git a/test/server/test_data/server/fatal_actions.yaml b/test/server/test_data/server/fatal_actions.yaml new file mode 100644 index 0000000000000..cbebfaa188ebb --- /dev/null +++ b/test/server/test_data/server/fatal_actions.yaml @@ -0,0 +1,9 @@ +fatal_actions: + - config: + name: envoy_test.fatal_action.safe + typed_config: + '@type': type.googleapis.com/google.protobuf.Empty + - config: + name: envoy_test.fatal_action.unsafe + typed_config: + '@type': type.googleapis.com/google.protobuf.Empty diff --git a/test/test_common/simulated_time_system_test.cc b/test/test_common/simulated_time_system_test.cc index 4234142114afb..e46284925deb8 100644 --- a/test/test_common/simulated_time_system_test.cc +++ b/test/test_common/simulated_time_system_test.cc @@ -202,17 +202,17 @@ TEST_P(SimulatedTimeSystemTest, TimerOrderAndRescheduleTimer) { // is delayed since it is rescheduled with a non-zero delta. advanceMsAndLoop(5); if (activateMode() == ActivateMode::DelayActivateTimers) { -#ifdef WIN32 - // Force it to run again to pick up next iteration callbacks. - // The event loop runs for a single iteration in NonBlock mode on Windows as a hack to work - // around LEVEL trigger fd registrations constantly firing events and preventing the NonBlock - // event loop from ever reaching the no-fd event and no-expired timers termination condition. It - // is not possible to get consistent event loop behavior since the time system does not override - // the base scheduler's run behavior, and libevent does not provide a mode where it runs at most - // N iterations before breaking out of the loop for us to prefer over the single iteration mode - // used on Windows. - advanceMsAndLoop(0); -#endif + if constexpr (Event::PlatformDefaultTriggerType == FileTriggerType::Level) { + // Force it to run again to pick up next iteration callbacks. + // The event loop runs for a single iteration in NonBlock mode on Windows as a hack to work + // around LEVEL trigger fd registrations constantly firing events and preventing the NonBlock + // event loop from ever reaching the no-fd event and no-expired timers termination condition. + // It is not possible to get consistent event loop behavior since the time system does not + // override the base scheduler's run behavior, and libevent does not provide a mode where it + // runs at most N iterations before breaking out of the loop for us to prefer over the single + // iteration mode used on Windows. + advanceMsAndLoop(0); + } EXPECT_EQ("p013p4", output_); } else { EXPECT_EQ("p0134", output_); @@ -252,11 +252,11 @@ TEST_P(SimulatedTimeSystemTest, TimerOrderDisableAndRescheduleTimer) { // re-enabled with a non-zero timeout. advanceMsAndLoop(5); if (activateMode() == ActivateMode::DelayActivateTimers) { -#ifdef WIN32 - // The event loop runs for a single iteration in NonBlock mode on Windows. Force it to run again - // to pick up next iteration callbacks. - advanceMsAndLoop(0); -#endif + if constexpr (Event::PlatformDefaultTriggerType == FileTriggerType::Level) { + // The event loop runs for a single iteration in NonBlock mode on Windows. Force it to run + // again to pick up next iteration callbacks. + advanceMsAndLoop(0); + } EXPECT_THAT(output_, testing::AnyOf("p03p14", "p03p41")); } else { EXPECT_EQ("p0314", output_); diff --git a/test/test_common/threadsafe_singleton_injector.h b/test/test_common/threadsafe_singleton_injector.h index 627efa1390e61..b9a0020dc88a3 100644 --- a/test/test_common/threadsafe_singleton_injector.h +++ b/test/test_common/threadsafe_singleton_injector.h @@ -12,6 +12,7 @@ template class TestThreadsafeSingletonInjector { ThreadSafeSingleton::instance_ = instance; } ~TestThreadsafeSingletonInjector() { ThreadSafeSingleton::instance_ = latched_instance_; } + T& latched() { return *latched_instance_; } private: T* latched_instance_; diff --git a/test/test_common/utility.cc b/test/test_common/utility.cc index adb3e8b4de7c5..08c04e889c743 100644 --- a/test/test_common/utility.cc +++ b/test/test_common/utility.cc @@ -379,6 +379,10 @@ ApiPtr createApiForTest() { Filesystem::fileSystemForTest()); } +ApiPtr createApiForTest(Filesystem::Instance& filesystem) { + return std::make_unique(Thread::threadFactoryForTest(), filesystem); +} + ApiPtr createApiForTest(Random::RandomGenerator& random) { return std::make_unique(Thread::threadFactoryForTest(), Filesystem::fileSystemForTest(), nullptr, nullptr, &random); diff --git a/test/test_common/utility.h b/test/test_common/utility.h index 1e0d25cd57f9f..6b4abcd7c63c8 100644 --- a/test/test_common/utility.h +++ b/test/test_common/utility.h @@ -1034,6 +1034,7 @@ makeHeaderMap(const std::initializer_list>& namespace Api { ApiPtr createApiForTest(); +ApiPtr createApiForTest(Filesystem::Instance& filesystem); ApiPtr createApiForTest(Random::RandomGenerator& random); ApiPtr createApiForTest(Stats::Store& stat_store); ApiPtr createApiForTest(Stats::Store& stat_store, Random::RandomGenerator& random); diff --git a/tools/code_format/check_shellcheck_format.sh b/tools/code_format/check_shellcheck_format.sh index f0247de5cd1f3..1cc031ea06235 100755 --- a/tools/code_format/check_shellcheck_format.sh +++ b/tools/code_format/check_shellcheck_format.sh @@ -8,7 +8,7 @@ find_shell_files () { shellfiles=() shellfiles+=("$(git grep "^#!/bin/bash" | cut -d: -f1)") shellfiles+=("$(git grep "^#!/bin/sh" | cut -d: -f1)") - shellfiles+=("$(find . -name "*.sh" | cut -d/ -f2-)") + shellfiles+=("$(git ls-files|grep '\.sh$')") shellfiles=("$(echo "${shellfiles[@]}" | tr ' ' '\n' | sort | uniq)") for file in "${shellfiles[@]}"; do echo "$file" diff --git a/tools/spelling/spelling_dictionary.txt b/tools/spelling/spelling_dictionary.txt index b0c7a7c98d5e2..7911b3134fd75 100644 --- a/tools/spelling/spelling_dictionary.txt +++ b/tools/spelling/spelling_dictionary.txt @@ -237,6 +237,7 @@ Postgre Postgres Prereq QDCOUNT +QPACK QUIC QoS RAII