// Copyright 2016 Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package istio.mixer.v1;

option go_package = "istio.io/api/mixer/v1";

import "gogoproto/gogo.proto";
import "google/protobuf/duration.proto";
import "google/rpc/status.proto";
import "mixer/v1/attributes.proto";

option (gogoproto.goproto_getters_all) = false;
option (gogoproto.equal_all) = false;
option (gogoproto.gostring_all) = false;

// Used to get a thumbs-up/thumbs-down before performing an action.
message CheckRequest {
  // parameters for a quota allocation
  message QuotaParams {
    // Amount of quota to allocate
    int64 amount = 1;

    // When true, supports returning less quota than what was requested.
    bool best_effort = 2;
  }

  // The attributes to use for this request.
  //
  // Mixer's configuration determines how these attributes are used to
  // establish the result returned in the response.
  CompressedAttributes attributes = 1 [(gogoproto.nullable) = false];

  // The number of words in the global dictionary, used with to populate the attributes.
  // This value is used as a quick way to determine whether the client is using a dictionary that
  // the server understands.
  uint32 global_word_count = 2;

  // Used for deduplicating `Check` calls in the case of failed RPCs and retries. This should be a UUID
  // per call, where the same UUID is used for retries of the same call.
  string deduplication_id = 3;

  // The individual quotas to allocate
  map<string, QuotaParams> quotas = 4 [(gogoproto.nullable) = false];
}

// The response generated by the Check method.
message CheckResponse {

  // Expresses the result of a precondition check.
  message PreconditionResult {
    reserved 4;

    // A status code of OK indicates all preconditions were satisfied. Any other code indicates not
    // all preconditions were satisfied and details describe why.
    google.rpc.Status status = 1 [(gogoproto.nullable) = false];

    // The amount of time for which this result can be considered valid.
    google.protobuf.Duration valid_duration = 2 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true];

    // The number of uses for which this result can be considered valid.
    int32 valid_use_count = 3;

    // The total set of attributes that were used in producing the result
    // along with matching conditions.
    ReferencedAttributes referenced_attributes = 5;

    // An optional routing directive, used to manipulate the traffic metadata
    // whenever all preconditions are satisfied.
    RouteDirective route_directive = 6;
  }

  // Expresses the result of a quota allocation.
  message QuotaResult {
    // The amount of time for which this result can be considered valid.
    google.protobuf.Duration valid_duration = 1 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true];

    // The amount of granted quota. When `QuotaParams.best_effort` is true, this will be >= 0.
    // If `QuotaParams.best_effort` is false, this will be either 0 or >= `QuotaParams.amount`.
    int64 granted_amount = 2;

    // The total set of attributes that were used in producing the result
    // along with matching conditions.
    ReferencedAttributes referenced_attributes = 5 [(gogoproto.nullable) = false];
  }

  // The precondition check results.
  PreconditionResult precondition = 2 [(gogoproto.nullable) = false];

  // The resulting quota, one entry per requested quota.
  map<string, QuotaResult> quotas = 3 [(gogoproto.nullable) = false];
}

// Describes the attributes that were used to determine the response.
// This can be used to construct a response cache.
message ReferencedAttributes {
  // How an attribute's value was matched
  enum Condition {
    CONDITION_UNSPECIFIED = 0;    // should not occur
    ABSENCE = 1;                  // match when attribute doesn't exist
    EXACT = 2;                    // match when attribute value is an exact byte-for-byte match
    REGEX = 3;                    // match when attribute value matches the included regex
  }

  // Describes a single attribute match.
  message AttributeMatch {
    // The name of the attribute. This is a dictionary index encoded in a manner identical
    // to all strings in the [CompressedAttributes][istio.mixer.v1.CompressedAttributes] message.
    sint32 name = 1;

    // The kind of match against the attribute value.
    Condition condition = 2;

    // If a REGEX condition is provided for a STRING_MAP attribute,
    // clients should use the regex value to match against map keys.
    string regex = 3;

    // A key in a STRING_MAP. When multiple keys from a STRING_MAP
    // attribute were referenced, there will be multiple AttributeMatch
    // messages with different map_key values. Values for map_key SHOULD
    // be ignored for attributes that are not STRING_MAP.
    //
    // Indices for the keys are used (taken either from the
    // message dictionary from the `words` field or the global dictionary).
    //
    // If no map_key value is provided for a STRING_MAP attribute, the
    // entire STRING_MAP will be used.
    sint32 map_key = 4;
  }

  // The message-level dictionary. Refer to [CompressedAttributes][istio.mixer.v1.CompressedAttributes] for information
  // on using dictionaries.
  repeated string words = 1;

  // Describes a set of attributes.
  repeated AttributeMatch attribute_matches = 2 [(gogoproto.nullable) = false];
}

// Operation on HTTP headers to replace, append, or remove a header. Header
// names are normalized to lower-case with dashes, e.g.  "x-request-id".
// Pseudo-headers ":path", ":authority", and ":method" are supported to modify
// the request headers.
message HeaderOperation {
  // Operation type.
  enum Operation {
    REPLACE = 0;  // replaces the header with the given name
    REMOVE = 1;   // removes the header with the given name (the value is ignored)
    APPEND = 2;   // appends the value to the header value, or sets it if not present
  }
  // Header name.
  string name = 1;

  // Header value.
  string value = 2;

  // Header operation.
  Operation operation = 3;
}

// Expresses the routing manipulation actions to be performed on behalf of
// Mixer in response to a successful precondition check.
message RouteDirective {
  // Operations on the request headers.
  repeated HeaderOperation request_header_operations = 1 [(gogoproto.nullable) = false];

  // Operations on the response headers.
  repeated HeaderOperation response_header_operations = 2 [(gogoproto.nullable) = false];

  // If set, enables a direct response without proxying the request to the routing
  // destination. Required to be a value in the 2xx or 3xx range.
  uint32 direct_response_code = 3;

  // Supplies the response body for the direct response.
  // If this setting is omitted, no body is included in the generated response.
  string direct_response_body = 4;
}
