syntax = "proto3";

package envoy.extensions.filters.http.compressor.v3;

import "envoy/config/core/v3/base.proto";
import "envoy/config/core/v3/extension.proto";

import "google/protobuf/wrappers.proto";

import "envoy/annotations/deprecation.proto";
import "udpa/annotations/status.proto";
import "udpa/annotations/versioning.proto";
import "validate/validate.proto";

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

// [#protodoc-title: Compressor]
// Compressor :ref:`configuration overview <config_http_filters_compressor>`.
// [#extension: envoy.filters.http.compressor]

// [#next-free-field: 10]
message Compressor {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.config.filter.http.compressor.v2.Compressor";

  message CommonDirectionConfig {
    // Runtime flag that controls whether compression is enabled for the direction this
    // common config is applied to. When this field is ``false``, the filter will operate as a
    // pass-through filter in the chosen direction, unless overridden by ``CompressorPerRoute``.
    // If this field is not specified, the filter will be enabled.
    config.core.v3.RuntimeFeatureFlag enabled = 1;

    // Minimum value of the ``Content-Length`` header in request or response messages (depending on the
    // direction this common config is applied to), in bytes, that will trigger compression. Defaults to 30.
    google.protobuf.UInt32Value min_content_length = 2;

    // Set of strings that allows specifying which mime-types yield compression; e.g.,
    // ``application/json``, ``text/html``, etc.
    //
    // When this field is not specified, compression will be applied to these following mime-types
    // and their synonyms:
    //
    // * ``application/javascript``
    // * ``application/json``
    // * ``application/xhtml+xml``
    // * ``image/svg+xml``
    // * ``text/css``
    // * ``text/html``
    // * ``text/plain``
    // * ``text/xml``
    //
    repeated string content_type = 3;
  }

  // Configuration for filter behavior on the request direction.
  message RequestDirectionConfig {
    CommonDirectionConfig common_config = 1;
  }

  // Configuration for filter behavior on the response direction.
  // [#next-free-field: 7]
  message ResponseDirectionConfig {
    CommonDirectionConfig common_config = 1;

    // When this field is ``true``, disables compression when the response contains an ``ETag`` header.
    // When this field is ``false``, the filter will preserve weak ``ETag`` values and remove those that
    // require strong validation (unless ``weaken_etag_on_compress`` is set).
    // When both ``disable_on_etag_header`` and ``weaken_etag_on_compress`` are ``true``,
    // ``weaken_etag_on_compress`` takes precedence (compression is applied and the ETag is weakened).
    bool disable_on_etag_header = 2;

    // When this field is ``true`` and the filter compresses a response that contains a strong
    // ``ETag``, the filter will weaken the ETag by prepending ``W/`` to its value instead of
    // removing it. This allows caching and conditional requests to work while indicating the
    // response body was modified by compression. When ``false`` (default), strong ETags are
    // removed when compression is applied. When both ``weaken_etag_on_compress`` and
    // ``disable_on_etag_header`` are ``true``, this field takes precedence so that compression
    // is applied and the ETag is weakened, supporting gradual rollout to clients and servers.
    bool weaken_etag_on_compress = 6;

    // When this field is ``true``, removes ``Accept-Encoding`` from the request headers before dispatching
    // the request to the upstream so that responses do not get compressed before reaching the filter.
    //
    // .. attention::
    //
    //    To avoid interfering with other compression filters in the same chain, use this option in
    //    the filter closest to the upstream.
    bool remove_accept_encoding_header = 3;

    // Set of response codes for which compression is disabled; e.g., 206 Partial Content should not
    // be compressed.
    repeated uint32 uncompressible_response_codes = 4 [(validate.rules).repeated = {
      unique: true
      items {uint32 {lt: 600 gte: 200}}
    }];

    // If true, the filter adds the ``x-envoy-compression-status`` response
    // header to indicate whether the compression occurred and, if not, provide
    // the reason why. The header's value format is
    // ``<encoder-type>;<status>[;<additional-params>]``, where ``<status>`` is
    // ``Compressed`` or the reason compression was skipped (e.g.,
    // ``ContentLengthTooSmall``). When this field is enabled, the compressor
    // filter alters the order of the compression eligibility checks to report
    // the most valid reason for skipping the compression.
    bool status_header_enabled = 5;
  }

  // Minimum response length, in bytes, which will trigger compression. The default value is 30.
  google.protobuf.UInt32Value content_length = 1
      [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"];

  // Set of strings that allows specifying which mime-types yield compression; e.g.,
  // ``application/json``, ``text/html``, etc.
  //
  // When this field is not specified, compression will be applied to these following mime-types
  // and their synonyms:
  //
  // * ``application/javascript``
  // * ``application/json``
  // * ``application/xhtml+xml``
  // * ``image/svg+xml``
  // * ``text/css``
  // * ``text/html``
  // * ``text/plain``
  // * ``text/xml``
  //
  repeated string content_type = 2
      [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"];

  // When this field is ``true``, disables compression when the response contains an ``ETag`` header.
  // When this field is ``false``, the filter will preserve weak ``ETag`` values and remove those that
  // require strong validation.
  bool disable_on_etag_header = 3
      [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"];

  // When this field is ``true``, removes ``Accept-Encoding`` from the request headers before dispatching
  // the request to the upstream so that responses do not get compressed before reaching the filter.
  //
  // .. attention::
  //
  //    To avoid interfering with other compression filters in the same chain, use this option in
  //    the filter closest to the upstream.
  bool remove_accept_encoding_header = 4
      [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"];

  // Runtime flag that controls whether the filter is enabled. When this field is ``false``, the
  // filter will operate as a pass-through filter, unless overridden by ``CompressorPerRoute``.
  // If this field is not specified, the filter is enabled by default.
  config.core.v3.RuntimeFeatureFlag runtime_enabled = 5
      [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"];

  // A compressor library to use for compression.
  // [#extension-category: envoy.compression.compressor]
  config.core.v3.TypedExtensionConfig compressor_library = 6
      [(validate.rules).message = {required: true}];

  // Configuration for request compression. If this field is not specified, request compression is disabled.
  RequestDirectionConfig request_direction_config = 7;

  // Configuration for response compression. If this field is not specified, response compression is enabled.
  //
  // .. attention::
  //
  //    When this field is set, duplicate deprecated fields of the ``Compressor`` message,
  //    such as ``content_length``, ``content_type``, ``disable_on_etag_header``,
  //    ``remove_accept_encoding_header``, and ``runtime_enabled``, are ignored.
  //
  //    Additionally, all statistics related to response compression will be rooted in
  //    ``<stat_prefix>.compressor.<compressor_library.name>.<compressor_library_stat_prefix>.response.*``
  //    instead of
  //    ``<stat_prefix>.compressor.<compressor_library.name>.<compressor_library_stat_prefix>.*``.
  ResponseDirectionConfig response_direction_config = 8;

  // When this field is ``true``, this compressor is preferred when q-values in ``Accept-Encoding`` are equal.
  // If multiple compressor filters set ``choose_first`` to ``true``, the last one in the filter chain is chosen.
  bool choose_first = 9;
}

// Per-route overrides of ``ResponseDirectionConfig``. Anything added here should be optional,
// to allow overriding arbitrary subsets of configuration. Omitted fields must have no effect.
message ResponseDirectionOverrides {
  // If set, overrides the filter-level
  // :ref:`remove_accept_encoding_header<envoy_v3_api_field_extensions.filters.http.compressor.v3.Compressor.ResponseDirectionConfig.remove_accept_encoding_header>`.
  google.protobuf.BoolValue remove_accept_encoding_header = 1;
}

// Per-route overrides. As per-route overrides are needed, they should be
// added here, mirroring the structure of ``Compressor``. All fields should be
// optional, to allow overriding arbitrary subsets of configuration.
message CompressorOverrides {
  // If present, response compression is enabled.
  ResponseDirectionOverrides response_direction_config = 1;

  // A compressor library to use for compression. If specified, this overrides
  // the filter-level ``compressor_library`` configuration for this route.
  config.core.v3.TypedExtensionConfig compressor_library = 2;
}

message CompressorPerRoute {
  oneof override {
    option (validate.required) = true;

    // If set, the filter will operate as a pass-through filter.
    // Overrides ``Compressor.runtime_enabled`` and ``CommonDirectionConfig.enabled``.
    bool disabled = 1 [(validate.rules).bool = {const: true}];

    // Per-route overrides. Fields set here will override corresponding fields in ``Compressor``.
    CompressorOverrides overrides = 2;
  }
}
