syntax = "proto3";

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

import "envoy/config/common/mutation_rules/v3/mutation_rules.proto";
import "envoy/config/core/v3/substitution_format_string.proto";

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

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

// [#protodoc-title: Transform filter configuration]
// Transform filter :ref:`configuration overview <config_http_filters_transform>` to perform
// HTTP header and body transformations.
// [#extension: envoy.filters.http.transform]

// Configuration for the transform filter. The filter may buffer the request/response until the
// entire body is received, and then mutate the headers and body according to the contents
// of the request/response. The request and response transformations are independent and could
// be configured separately.
// Only JSON body transformation is supported for now.
message TransformConfig {
  // Configuration for transforming request.
  //
  // .. note::
  //
  //   If set then the entire request headers and body will always be buffered on a JSON request
  //   even if only headers are transformed.
  Transformation request_transformation = 1;

  // Configuration for transforming response.
  //
  // .. note::
  //
  //   If set then the entire response headers and body will always be buffered on a JSON response
  //   even if only headers are transformed.
  Transformation response_transformation = 2;

  // If true and the request headers are transformed, Envoy will re-evaluate the target
  // cluster in the same route. Please ensure the cluster specifier in the route supports
  // dynamic evaluation or this flag will have no effect, e.g.
  // :ref:`matcher cluster specifier
  // <envoy_v3_api_msg_extensions.router.cluster_specifiers.matcher.v3.MatcherClusterSpecifier>`.
  //
  // Only one of ``clear_cluster_cache`` and ``clear_route_cache`` can be true.
  bool clear_cluster_cache = 3;

  // If true and the request headers are transformed, Envoy will clear the route cache for
  // the current request and force re-evaluation of the route. This has performance penalty and
  // should only be used when the route match criteria depends on the transformed headers.
  //
  // Only one of ``clear_cluster_cache`` and ``clear_route_cache`` can be true.
  bool clear_route_cache = 4;
}

message Transformation {
  // The header mutations to perform.
  // The :ref:`substitution format specifier <config_access_log_format>` could be applied here.
  // In addition to the commonly used format specifiers, this filter introduces additional format specifiers:
  //
  // * ``%REQUEST_BODY(KEY*)%``: the request body. And ``Key`` KEY is an optional
  //   lookup key in the namespace with the option of specifying nested keys separated by ':'.
  // * ``%RESPONSE_BODY(KEY*)%``: the response body. And ``Key`` KEY is an optional
  //   lookup key in the namespace with the option of specifying nested keys separated by ':'.
  repeated config.common.mutation_rules.v3.HeaderMutation headers_mutations = 1;

  // The body transformation configuration. If not set, no body transformation will be performed.
  BodyTransformation body_transformation = 2;
}

message BodyTransformation {
  enum TransformAction {
    // Merge the transformed body with the original body. This is the default action.
    MERGE = 0;

    // Replace the original body with the transformed body.
    REPLACE = 1;
  }

  // Body transformation configuration. The substitution format string is used as the template
  // to generate the transformed new body content.
  // The :ref:`substitution format specifier <config_access_log_format>` could be applied here.
  // And except the commonly used format specifiers, the additional format specifiers
  // ``%REQUEST_BODY(KEY*)%`` and ``%RESPONSE_BODY(KEY*)%`` could also be used here.
  config.core.v3.SubstitutionFormatString body_format = 1
      [(validate.rules).message = {required: true}];

  // The action to perform for new body content and original body content.
  // For example, if ``MERGE`` is used, then the new body content generated from the ``body_format``
  // will be merged into the original body content.
  //
  // Default is ``MERGE``.
  TransformAction action = 2;
}
