syntax = "proto3";

package envoy.extensions.upstreams.http.v3;

import "envoy/config/common/matcher/v3/matcher.proto";
import "envoy/config/core/v3/extension.proto";
import "envoy/config/core/v3/protocol.proto";
import "envoy/config/route/v3/route_components.proto";
import "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto";

import "udpa/annotations/status.proto";
import "validate/validate.proto";

option java_package = "io.envoyproxy.envoy.extensions.upstreams.http.v3";
option java_outer_classname = "HttpProtocolOptionsProto";
option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/upstreams/http/v3;httpv3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;

// [#protodoc-title: HTTP Protocol Options]
// [#extension: envoy.upstreams.http.http_protocol_options]

// HttpProtocolOptions specifies Http upstream protocol options. This object
// is used in
// :ref:`typed_extension_protocol_options<envoy_v3_api_field_config.cluster.v3.Cluster.typed_extension_protocol_options>`,
// keyed by the name ``envoy.extensions.upstreams.http.v3.HttpProtocolOptions``.
//
// This controls what protocol(s) should be used for upstream and how said protocol(s) are configured.
//
// This replaces the prior pattern of explicit protocol configuration directly
// in the cluster. So a configuration like this, explicitly configuring the use of HTTP/2 upstream:
//
// .. code::
//
//   clusters:
//     - name: some_service
//       connect_timeout: 5s
//       upstream_http_protocol_options:
//         auto_sni: true
//       common_http_protocol_options:
//         idle_timeout: 1s
//       http2_protocol_options:
//         max_concurrent_streams: 100
//        .... [further cluster config]
//
// Would now look like this:
//
// .. code::
//
//   clusters:
//     - name: some_service
//       connect_timeout: 5s
//       typed_extension_protocol_options:
//         envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
//           "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
//           upstream_http_protocol_options:
//             auto_sni: true
//           common_http_protocol_options:
//             idle_timeout: 1s
//           explicit_http_config:
//             http2_protocol_options:
//               max_concurrent_streams: 100
//        .... [further cluster config]
// [#next-free-field: 12]
message HttpProtocolOptions {
  // If this is used, the cluster will only operate on one of the possible upstream protocols.
  // Note that HTTP/2 or above should generally be used for upstream gRPC clusters.
  message ExplicitHttpConfig {
    oneof protocol_config {
      option (validate.required) = true;

      config.core.v3.Http1ProtocolOptions http_protocol_options = 1;

      config.core.v3.Http2ProtocolOptions http2_protocol_options = 2;

      // .. warning::
      //   QUIC upstream support is currently not ready for internet use.
      //   Please see :ref:`here <arch_overview_http3>` for details.
      config.core.v3.Http3ProtocolOptions http3_protocol_options = 3;
    }
  }

  // If this is used, the cluster can use either of the configured protocols, and
  // will use whichever protocol was used by the downstream connection.
  //
  // If HTTP/3 is configured for downstream and not configured for upstream,
  // HTTP/3 requests will fail over to HTTP/2.
  message UseDownstreamHttpConfig {
    config.core.v3.Http1ProtocolOptions http_protocol_options = 1;

    config.core.v3.Http2ProtocolOptions http2_protocol_options = 2;

    // .. warning::
    //   QUIC upstream support is currently not ready for internet use.
    //   Please see :ref:`here <arch_overview_http3>` for details.
    config.core.v3.Http3ProtocolOptions http3_protocol_options = 3;
  }

  // If this is used, the cluster can use either HTTP/1 or HTTP/2, and will use whichever
  // protocol is negotiated by ALPN with the upstream.
  // Clusters configured with ``AutoHttpConfig`` will use the highest available
  // protocol; HTTP/2 if supported, otherwise HTTP/1.
  // If the upstream does not support ALPN, ``AutoHttpConfig`` will fail over to HTTP/1.
  // This can only be used with transport sockets which support ALPN. Using a
  // transport socket which does not support ALPN will result in configuration
  // failure. The transport layer may be configured with custom ALPN, but the default ALPN
  // for the cluster (or if custom ALPN fails) will be "h2,http/1.1".
  message AutoHttpConfig {
    config.core.v3.Http1ProtocolOptions http_protocol_options = 1;

    config.core.v3.Http2ProtocolOptions http2_protocol_options = 2;

    // Unlike HTTP/1 and HTTP/2, HTTP/3 will not be configured unless it is
    // present, and (soon) only if there is an indication of server side
    // support.
    // See :ref:`here <arch_overview_http3_upstream>` for more information on
    // when HTTP/3 will be used, and when Envoy will fail over to TCP.
    //
    // .. warning::
    //   QUIC upstream support is currently not ready for internet use.
    //   Please see :ref:`here <arch_overview_http3>` for details.
    config.core.v3.Http3ProtocolOptions http3_protocol_options = 3;

    // The presence of alternate protocols cache options causes the use of the
    // alternate protocols cache, which is responsible for parsing and caching
    // HTTP Alt-Svc headers. This enables the use of HTTP/3 for origins that
    // advertise supporting it.
    //
    // .. note::
    //   This is required when HTTP/3 is enabled.
    config.core.v3.AlternateProtocolsCacheOptions alternate_protocols_cache_options = 4;
  }

  message OutlierDetection {
    // If specified, only responses matching the matcher will be treated by outlier detection as errors.
    // If not specified, only 5xx codes are treated by outlier detection as errors.
    config.common.matcher.v3.MatchPredicate error_matcher = 1
        [(validate.rules).message = {required: true}];
  }

  // This contains options common across HTTP/1 and HTTP/2
  config.core.v3.HttpProtocolOptions common_http_protocol_options = 1;

  // This contains common protocol options which are only applied upstream.
  config.core.v3.UpstreamHttpProtocolOptions upstream_http_protocol_options = 2;

  // This controls the actual protocol to be used upstream.
  oneof upstream_protocol_options {
    option (validate.required) = true;

    // To explicitly configure either HTTP/1 or HTTP/2 (but not both!) use ``explicit_http_config``.
    ExplicitHttpConfig explicit_http_config = 3;

    // This allows switching on protocol based on what protocol the downstream
    // connection used.
    UseDownstreamHttpConfig use_downstream_protocol_config = 4;

    // This allows switching on protocol based on ALPN
    AutoHttpConfig auto_config = 5;
  }

  // Optional HTTP filters for the upstream HTTP filter chain.
  //
  // .. note::
  //   Upstream HTTP filters are currently in alpha.
  //
  //
  // These filters will be applied for all HTTP streams which flow through this
  // cluster. Unlike downstream HTTP filters, they will *not* be applied to terminated CONNECT requests.
  //
  // If using upstream HTTP filters, please be aware that local errors sent by
  // upstream HTTP filters will not trigger retries, and local errors sent by
  // upstream HTTP filters will count as a final response if hedging is configured.
  // [#extension-category: envoy.filters.http.upstream]
  repeated filters.network.http_connection_manager.v3.HttpFilter http_filters = 6;

  // Configuration options for Unified Header Validation (UHV).
  // UHV is an extensible mechanism for checking validity of HTTP responses.
  //
  // [#comment:TODO(yanavlasov): Make it a link to the default header validator doc when it becomes visible.]
  // Leaving this field unspecified, selects the default header validator ``envoy.http.header_validators.envoy_default``.
  //
  // [#not-implemented-hide:]
  // [#extension-category: envoy.http.header_validators]
  config.core.v3.TypedExtensionConfig header_validation_config = 7;

  // Defines http specific outlier detection parameters.
  OutlierDetection outlier_detection = 8;

  // Specifies a list of HTTP-level mirroring policies for requests routed to this cluster.
  // Cluster-level policies override route-level policies when they both are configured.
  //
  // .. note::
  //
  //   Mirroring will not be triggered if the :ref:`primary cluster
  //   <envoy_v3_api_field_config.route.v3.RouteAction.cluster>` does not exist.
  repeated config.route.v3.RouteAction.RequestMirrorPolicy request_mirror_policies = 9;

  // Specifies a list of hash policies for consistent hashing load balancing (e.g., Ring Hash or
  // Maglev) for requests routed to this cluster. When configured, cluster-level policies override
  // route-level policies. When not configured, route-level policies (if any) will be used.
  //
  // This enables consistent routing to the same upstream host for all requests to a cluster,
  // which is particularly useful for stateful services like caching, session management, or
  // sticky routing requirements.
  //
  // .. note::
  //
  //   Hash policies are only effective when the cluster is configured with a hash-based load
  //   balancing policy (e.g., :ref:`RING_HASH <envoy_v3_api_enum_value_config.cluster.v3.Cluster.LbPolicy.RING_HASH>`
  //   or :ref:`MAGLEV <envoy_v3_api_enum_value_config.cluster.v3.Cluster.LbPolicy.MAGLEV>`).
  repeated config.route.v3.RouteAction.HashPolicy hash_policy = 10;

  // Specifies the retry policy for requests routed to this cluster. When configured,
  // cluster-level retry policy overrides route-level retry policy. When not configured,
  // route-level retry policy (if any) will be used.
  //
  // .. note::
  //
  //   Cluster-level retry policy will override route-level retry policy entirely. Policies are
  //   not merged.
  config.route.v3.RetryPolicy retry_policy = 11;
}
