// Copyright 2020 The gRPC 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 grpc.lookup.v1;

import "google/protobuf/duration.proto";

option go_package = "google.golang.org/grpc/lookup/grpc_lookup_v1";
option java_multiple_files = true;
option java_package = "io.grpc.lookup.v1";
option java_outer_classname = "RlsConfigProto";

// Extract a key based on a given name (e.g. header name or query parameter
// name).  The name must match one of the names listed in the "name" field.  If
// the "required_match" field is true, one of the specified names must be
// present for the keybuilder to match.
message NameMatcher {
  // The name that will be used in the RLS key_map to refer to this value.
  // If required_match is true, you may omit this field or set it to an empty
  // string, in which case the matcher will require a match, but won't update
  // the key_map.
  string key = 1;

  // Ordered list of names (headers or query parameter names) that can supply
  // this value; the first one with a non-empty value is used.
  repeated string names = 2;

  // If true, make this extraction required; the key builder will not match
  // if no value is found.
  bool required_match = 3;
}

// A GrpcKeyBuilder applies to a given gRPC service, name, and headers.
message GrpcKeyBuilder {
  // To match, one of the given Name fields must match; the service and method
  // fields are specified as fixed strings.  The service name is required and
  // includes the proto package name.  The method name may be omitted, in
  // which case any method on the given service is matched.
  message Name {
    string service = 1;
    string method = 2;
  }
  repeated Name names = 1;

  // If you wish to include the host, service, or method names as keys in the
  // generated RouteLookupRequest, specify key names to use in the extra_keys
  // submessage. If a key name is empty, no key will be set for that value.
  // If this submessage is specified, the normal host/path fields will be left
  // unset in the RouteLookupRequest. We are deprecating host/path in the
  // RouteLookupRequest, so services should migrate to the ExtraKeys approach.
  message ExtraKeys {
    string host = 1;
    string service = 2;
    string method = 3;
  }
  ExtraKeys extra_keys = 3;

  // Extract keys from all listed headers.
  // For gRPC, it is an error to specify "required_match" on the NameMatcher
  // protos.
  repeated NameMatcher headers = 2;

  // You can optionally set one or more specific key/value pairs to be added to
  // the key_map.  This can be useful to identify which builder built the key,
  // for example if you are suppressing the actual method, but need to
  // separately cache and request all the matched methods.
  map<string, string> constant_keys = 4;
}

// An HttpKeyBuilder applies to a given HTTP URL and headers.
//
// Path and host patterns use the matching syntax from gRPC transcoding to
// extract named key/value pairs from the path and host components of the URL:
// https://github.com/googleapis/googleapis/blob/master/google/api/http.proto
//
// It is invalid to specify the same key name in multiple places in a pattern.
//
// For a service where the project id can be expressed either as a subdomain or
// in the path, separate HttpKeyBuilders must be used:
//     host_pattern: 'example.com' path_pattern: '/{id}/{object}/**'
//     host_pattern: '{id}.example.com' path_pattern: '/{object}/**'
// If the host is exactly 'example.com', the first path segment will be used as
// the id and the second segment as the object. If the host has a subdomain, the
// subdomain will be used as the id and the first segment as the object. If
// neither pattern matches, no keys will be extracted.
message HttpKeyBuilder {
  // host_pattern is an ordered list of host template patterns for the desired
  // value.  If any host_pattern values are specified, then at least one must
  // match, and the last one wins and sets any specified variables.  A host
  // consists of labels separated by dots. Each label is matched against the
  // label in the pattern as follows:
  //   - "*": Matches any single label.
  //   - "**": Matches zero or more labels (first or last part of host only).
  //   - "{<name>=...}": One or more label capture, where "..." can be any
  //      template that does not include a capture.
  //   - "{<name>}": A single label capture. Identical to {<name>=*}.
  //
  // Examples:
  //   - "example.com": Only applies to the exact host example.com.
  //   - "*.example.com": Matches subdomains of example.com.
  //   - "**.example.com": matches example.com, and all levels of subdomains.
  //   - "{project}.example.com": Extracts the third level subdomain.
  //   - "{project=**}.example.com": Extracts the third level+ subdomains.
  //   - "{project=**}": Extracts the entire host.
  repeated string host_patterns = 1;

  // path_pattern is an ordered list of path template patterns for the desired
  // value.  If any path_pattern values are specified, then at least one must
  // match, and the last one wins and sets any specified variables.  A path
  // consists of segments separated by slashes. Each segment is matched against
  // the segment in the pattern as follows:
  //   - "*": Matches any single segment.
  //   - "**": Matches zero or more segments (first or last part of path only).
  //   - "{<name>=...}": One or more segment capture, where "..." can be any
  //      template that does not include a capture.
  //   - "{<name>}": A single segment capture. Identical to {<name>=*}.
  // A custom method may also be specified by appending ":" and the custom
  // method name or "*" to indicate any custom method (including no custom
  // method).  For example, "/*/projects/{project_id}/**:*" extracts
  // `{project_id}` for any version, resource and custom method that includes
  // it.  By default, any custom method will be matched.
  //
  // Examples:
  //   - "/v1/{name=messages/*}": extracts a name like "messages/12345".
  //   - "/v1/messages/{message_id}": extracts a message_id like "12345".
  //   - "/v1/users/{user_id}/messages/{message_id}": extracts two key values.
  repeated string path_patterns = 2;

  // List of query parameter names to try to match.
  // For example: ["parent", "name", "resource.name"]
  // We extract all the specified query_parameters (case-sensitively).  If any
  // are marked as "required_match" and are not present, this keybuilder fails
  // to match.  If a given parameter appears multiple times (?foo=a&foo=b) we
  // will report it as a comma-separated string (foo=a,b).
  repeated NameMatcher query_parameters = 3;

  // List of headers to try to match.
  // We extract all the specified header values (case-insensitively).  If any
  // are marked as "required_match" and are not present, this keybuilder fails
  // to match.  If a given header appears multiple times in the request we will
  // report it as a comma-separated string, in standard HTTP fashion.
  repeated NameMatcher headers = 4;

  // You can optionally set one or more specific key/value pairs to be added to
  // the key_map.  This can be useful to identify which builder built the key,
  // for example if you are suppressing a lot of information from the URL, but
  // need to separately cache and request URLs with that content.
  map<string, string> constant_keys = 5;
}

message RouteLookupConfig {
  // Ordered specifications for constructing keys for HTTP requests.  Last
  // match wins.  If no HttpKeyBuilder matches, an empty key_map will be sent to
  // the lookup service; it should likely reply with a global default route
  // and raise an alert.
  repeated HttpKeyBuilder http_keybuilders = 1;

  // Unordered specifications for constructing keys for gRPC requests.  All
  // GrpcKeyBuilders on this list must have unique "name" fields so that the
  // client is free to prebuild a hash map keyed by name.  If no GrpcKeyBuilder
  // matches, an empty key_map will be sent to the lookup service; it should
  // likely reply with a global default route and raise an alert.
  repeated GrpcKeyBuilder grpc_keybuilders = 2;

  // The name of the lookup service as a gRPC URI.  Typically, this will be
  // a subdomain of the target, such as "lookup.datastore.googleapis.com".
  string lookup_service = 3;

  // Configure a timeout value for lookup service requests.
  // Defaults to 10 seconds if not specified.
  google.protobuf.Duration lookup_service_timeout = 4;

  // How long are responses valid for (like HTTP Cache-Control).
  // If omitted or zero, the longest valid cache time is used.
  // This value is clamped to 5 minutes to avoid unflushable bad responses.
  google.protobuf.Duration max_age = 5;

  // After a response has been in the client cache for this amount of time
  // and is re-requested, start an asynchronous RPC to re-validate it.
  // This value should be less than max_age by at least the length of a
  // typical RTT to the Route Lookup Service to fully mask the RTT latency.
  // If omitted, keys are only re-requested after they have expired.
  google.protobuf.Duration stale_age = 6;

  // Rough indicator of amount of memory to use for the client cache.  Some of
  // the data structure overhead is not accounted for, so actual memory consumed
  // will be somewhat greater than this value.  If this field is omitted or set
  // to zero, a client default will be used.  The value may be capped to a lower
  // amount based on client configuration.
  int64 cache_size_bytes = 7;

  // This is a list of all the possible targets that can be returned by the
  // lookup service.  If a target not on this list is returned, it will be
  // treated the same as an unhealthy target.
  repeated string valid_targets = 8;

  // This value provides a default target to use if needed.  If set, it will be
  // used if RLS returns an error, times out, or returns an invalid response.
  // Note that requests can be routed only to a subdomain of the original
  // target, e.g. "us_east_1.cloudbigtable.googleapis.com".
  string default_target = 9;

  reserved 10;
  reserved "request_processing_strategy";
}

// RouteLookupClusterSpecifier is used in xDS to represent a cluster specifier
// plugin for RLS.
message RouteLookupClusterSpecifier {
  // The RLS config for this cluster specifier plugin instance.
  RouteLookupConfig route_lookup_config = 1;
}
