chromium/components/cronet/native/cronet.idl

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// The IDL in this file is based on Mojo IDL, but is not currently targeted
// for direct use in Mojo projects.

module Cronet;

// General system support interfaces.

/**
 * Data buffer provided by the application to read and write data.
 */
interface Buffer {
  /**
   * Initialize Buffer with raw buffer |data| of |size| allocated by the app.
   * The |callback| is invoked when buffer is destroyed.
   */
  InitWithDataAndCallback(handle data, uint64 size, BufferCallback callback);

  /**
   * Initialize Buffer by allocating buffer of |size|. The content of allocated
   * data is not initialized.
   */
  InitWithAlloc(uint64 size);

  /**
   * Return size of data owned by this buffer.
   */
  [Sync]
  GetSize() => (uint64 size);

  /**
   * Return raw pointer to |data| owned by this buffer.
   */
  [Sync]
  GetData() => (handle data);
};

/**
 * App-provided callback passed to Buffer::InitWithDataAndCallback that gets invoked
 * when Buffer is destroyed.
 */
[Abstract]
interface BufferCallback {
  /**
   * Method invoked when |buffer| is destroyed so its app-allocated |data| can
   * be freed. If a UrlRequest has ownership of a Buffer and the UrlRequest is destroyed
   * (e.g. Cronet_UrlRequest_Destroy() is called), then Cronet will call OnDestroy().
   */
  OnDestroy(Buffer buffer);
};

// Base error passed to UrlRequestCallback.onFailed().
struct Error {
  enum ERROR_CODE {
    /**
     * Error code indicating the error returned by app callback.
     */
    ERROR_CALLBACK = 0,

    /**
     * Error code indicating the host being sent the request could not be resolved to an IP address.
     */
    ERROR_HOSTNAME_NOT_RESOLVED = 1,

    /**
     * Error code indicating the device was not connected to any network.
     */
    ERROR_INTERNET_DISCONNECTED = 2,

    /**
     * Error code indicating that as the request was processed the network configuration changed.
     */
    ERROR_NETWORK_CHANGED = 3,

    /**
     * Error code indicating a timeout expired. Timeouts expiring while attempting to connect will
     * be reported as the more specific {@link #ERROR_CONNECTION_TIMED_OUT}.
     */
    ERROR_TIMED_OUT = 4,

    /**
     * Error code indicating the connection was closed unexpectedly.
     */
    ERROR_CONNECTION_CLOSED = 5,

    /**
     * Error code indicating the connection attempt timed out.
     */
    ERROR_CONNECTION_TIMED_OUT = 6,

    /**
     * Error code indicating the connection attempt was refused.
     */
    ERROR_CONNECTION_REFUSED = 7,

    /**
     * Error code indicating the connection was unexpectedly reset.
     */
    ERROR_CONNECTION_RESET = 8,

    /**
     * Error code indicating the IP address being contacted is unreachable, meaning there is no
     * route to the specified host or network.
     */
    ERROR_ADDRESS_UNREACHABLE = 9,

    /**
     * Error code indicating an error related to the <a href="https://www.chromium.org/quic">
     * QUIC</a> protocol. When {@link #error_code} is this code, see
     * {@link quic_detailed_error_code} for more information.
     */
    ERROR_QUIC_PROTOCOL_FAILED = 10,

    /**
     * Error code indicating another type of error was encountered.
     * |internal_error_code| can be consulted to get a more specific cause.
     */
    ERROR_OTHER = 11
  };

  /**
   * Error code, one of ERROR_* values.
   */
  ERROR_CODE error_code = ERROR_CALLBACK;

  /**
   * Message, explaining the error.
   */
  string message;

  /**
   * Cronet internal error code. This may provide more specific error
   * diagnosis than |error_code|, but the constant values may change over time.
   * See
   * <a href=https://chromium.googlesource.com/chromium/src/+/main/net/base/net_error_list.h>
   * here</a> for the lastest list of values.
   */
  int32 internal_error_code = 0;

  /**
   * |true| if retrying this request right away might succeed, |false|
   * otherwise. For example, is |true| when |error_code| is |ERROR_NETWORK_CHANGED|
   * because trying the request might succeed using the new
   * network configuration, but |false| when |error_code| is
   * ERROR_INTERNET_DISCONNECTED because retrying the request right away will
   * encounter the same failure (instead retrying should be delayed until device regains
   * network connectivity).
   */
  bool immediately_retryable = false;

  /**
   * Contains detailed <a href="https://www.chromium.org/quic">QUIC</a> error code from
   * <a href="https://cs.chromium.org/search/?q=symbol:%5CbQuicErrorCode%5Cb">
   * QuicErrorCode</a> when the |error_code| code is |ERROR_QUIC_PROTOCOL_FAILED|.
   */
  int32 quic_detailed_error_code = 0;
};

/**
 * An interface to run commands on the |Executor|.
 *
 * Note: In general creating Runnables should only be done by Cronet. Runnables
 * created by the app don't have the ability to perform operations when the
 * Runnable is being destroyed (i.e. by Cronet_Runnable_Destroy) so resource
 * leaks are possible if the Runnable is posted to an Executor that is being
 * shutdown with unexecuted Runnables. In controlled testing environments
 * deallocation of associated resources can be performed in Run() if the
 * runnable can be assumed to always be executed.
 */
[Abstract]
interface Runnable {
  Run();
};

/**
 * An interface provided by the app to run |command| asynchronously.
 */
[Abstract]
interface Executor {
  /**
   * Takes ownership of |command| and runs it synchronously or asynchronously.
   * Destroys the |command| after execution, or if executor is shutting down.
   */
  Execute(Runnable command);
};

/**
 * Runtime result code returned by Engine and UrlRequest. Equivalent to
 * runtime exceptions in Android Java API. All results except SUCCESS trigger
 * native crash (via SIGABRT triggered by CHECK failure) unless
 * EngineParams.enableCheckResult is set to false.
 */
enum RESULT {
  /**
   * Operation completed successfully
   */
  SUCCESS = 0,

  /**
   * Illegal argument
   */
  ILLEGAL_ARGUMENT = -100,
  /**
   * Storage path must be set to existing directory
   */
  ILLEGAL_ARGUMENT_STORAGE_PATH_MUST_EXIST = -101,
  /**
   * Public key pin is invalid
   */
  ILLEGAL_ARGUMENT_INVALID_PIN = -102,
  /**
   * Host name is invalid
   */
  ILLEGAL_ARGUMENT_INVALID_HOSTNAME = -103,
  /**
   * Invalid http method
   */
  ILLEGAL_ARGUMENT_INVALID_HTTP_METHOD = -104,
  /**
   * Invalid http header
   */
  ILLEGAL_ARGUMENT_INVALID_HTTP_HEADER = -105,

  /**
   * Illegal state
   */
  ILLEGAL_STATE = -200,
  /**
   * Storage path is used by another engine
   */
  ILLEGAL_STATE_STORAGE_PATH_IN_USE = -201,
  /**
   * Cannot shutdown engine from network thread
   */
  ILLEGAL_STATE_CANNOT_SHUTDOWN_ENGINE_FROM_NETWORK_THREAD = -202,
  /**
   * The engine has already started
   */
  ILLEGAL_STATE_ENGINE_ALREADY_STARTED = -203,
  /**
   * The request has already started
   */
  ILLEGAL_STATE_REQUEST_ALREADY_STARTED = -204,
  /**
   * The request is not initialized
   */
  ILLEGAL_STATE_REQUEST_NOT_INITIALIZED = -205,
  /**
   * The request is already initialized
   */
  ILLEGAL_STATE_REQUEST_ALREADY_INITIALIZED = -206,
  /**
   * The request is not started
   */
  ILLEGAL_STATE_REQUEST_NOT_STARTED = -207,
  /**
   * No redirect to follow
   */
  ILLEGAL_STATE_UNEXPECTED_REDIRECT = -208,
  /**
   * Unexpected read attempt
   */
  ILLEGAL_STATE_UNEXPECTED_READ = -209,
  /**
   * Unexpected read failure
   */
  ILLEGAL_STATE_READ_FAILED = -210,

  /**
   * Null pointer or empty data
   */
  NULL_POINTER = -300,
  /**
   * The hostname cannot be null
   */
  NULL_POINTER_HOSTNAME = -301,
  /**
   * The set of SHA256 pins cannot be null
   */
  NULL_POINTER_SHA256_PINS = -302,
  /**
   * The pin expiration date cannot be null
   */
  NULL_POINTER_EXPIRATION_DATE = -303,
  /**
   * Engine is required
   */
  NULL_POINTER_ENGINE = -304,
  /**
   * URL is required
   */
  NULL_POINTER_URL = -305,
  /**
   * Callback is required
   */
  NULL_POINTER_CALLBACK = -306,
  /**
   * Executor is required
   */
  NULL_POINTER_EXECUTOR = -307,
  /**
   * Method is required
   */
  NULL_POINTER_METHOD = -308,
  /**
   * Invalid header name
   */
  NULL_POINTER_HEADER_NAME = -309,
  /**
   * Invalid header value
   */
  NULL_POINTER_HEADER_VALUE = -310,
  /**
   * Params is required
   */
  NULL_POINTER_PARAMS = -311,
  /**
   * Executor for RequestFinishedInfoListener is required
   */
  NULL_POINTER_REQUEST_FINISHED_INFO_LISTENER_EXECUTOR = -312,
};

/**
 * An engine to process UrlRequests, which uses the best HTTP stack
 * available on the current platform. An instance of this class can be started
 * using StartWithParams.
 */
interface Engine {
  /**
   * Starts Engine using given |params|. The engine must be started once
   * and only once before other methods can be used.
   */
  [Sync]
  StartWithParams(EngineParams params) => (RESULT result);

  /**
   * Starts NetLog logging to a file. The NetLog will contain events emitted
   * by all live Engines. The NetLog is useful for debugging.
   * The file can be viewed using a Chrome browser navigated to
   * chrome://net-internals/#import
   * Returns |true| if netlog has started successfully, |false| otherwise.
   * @param file_name the complete file path. It must not be empty. If the file
   *            exists, it is truncated before starting. If actively logging,
   *            this method is ignored.
   * @param log_all {@code true} to include basic events, user cookies,
   *    credentials and all transferred bytes in the log. This option presents
   *    a privacy risk, since it exposes the user's credentials, and should
   *    only be used with the user's consent and in situations where the log
   *    won't be public.  {@code false} to just include basic events.
   */
  [Sync]
  StartNetLogToFile(string file_name, bool log_all) => (bool started);

  /**
   * Stops NetLog logging and flushes file to disk. If a logging session is
   * not in progress, this call is ignored. This method blocks until the log is
   * closed to ensure that log file is complete and available.
   */
  [Sync]
  StopNetLog() => ();

  /**
   * Shuts down the Engine if there are no active requests,
   * otherwise returns a failure RESULT.
   *
   * Cannot be called on network thread - the thread Cronet calls into
   * Executor on (which is different from the thread the Executor invokes
   * callbacks on). This method blocks until all the Engine's resources have
   * been cleaned up.
   */
  [Sync]
  Shutdown() => (RESULT result);

  /**
   * Returns a human-readable version string of the engine.
   */
  [Sync]
  GetVersionString() => (string version_string);

  /**
   * Returns default human-readable version string of the engine. Can be used
   * before StartWithParams() is called.
   */
  [Sync]
  GetDefaultUserAgent() => (string default_user_agent);

  /**
   * Registers a listener that gets called at the end of each request.
   *
   * The listener is called on {@code executor}.
   *
   * The listener is called before {@link UrlRequestCallback.OnCanceled()},
   * {@link UrlRequestCallback.OnFailed()} or {@link
   * UrlRequestCallback.OnSucceeded()} is called -- note that if {@code
   * executor} runs the listener asyncronously, the actual call to the listener
   * may happen after a {@code UrlRequestCallback} method is called.
   *
   * Listeners are only guaranteed to be called for requests that are started
   * after the listener is added.
   *
   * Ownership is **not** taken for {@code listener} or {@code executor}.
   *
   * Assuming the listener won't run again (there are no pending requests with
   * the listener attached, either via {@code Engine} or {@code UrlRequest}),
   * the app may destroy it once its {@code OnRequestFinished()} has started,
   * even inside that method.
   *
   * Similarly, the app may destroy {@code executor} in or after {@code
   * OnRequestFinished()}.
   *
   * It's also OK to destroy {@code executor} in or after one of {@link
   * UrlRequestCallback.OnCanceled()}, {@link UrlRequestCallback.OnFailed()} or
   * {@link UrlRequestCallback.OnSucceeded()}.
   *
   * Of course, both of these are only true if {@code listener} won't run again
   * and {@code executor} isn't being used for anything else that might start
   * running in the future.
   *
   * @param listener the listener for finished requests.
   * @param executor the executor upon which to run {@code listener}.
   */
  AddRequestFinishedListener(RequestFinishedInfoListener listener,
                             Executor executor);

  /**
   * Unregisters a RequestFinishedInfoListener, including its association with
   * its registered Executor.
   */
  RemoveRequestFinishedListener(RequestFinishedInfoListener listener);
};

/**
 * Hint that |host| supports QUIC.
 */
struct QuicHint {
  /**
   * Name of the host that supports QUIC.
   */
  string host;

  /**
   * Port of the server that supports QUIC.
   */
  int32 port = 0;

  /**
   * Alternate port to use for QUIC.
   */
  int32 alternate_port = 0;
};

/**
 * Pins a set of public keys for a given |host|. By pinning a set of public keys,
 * |pinsSha256|, communication with |host| is required to
 * authenticate with a certificate with a public key from the set of pinned ones.
 * An app can pin the public key of the root certificate, any of the intermediate
 * certificates or the end-entry certificate. Authentication will fail and secure
 * communication will not be established if none of the public keys is present in the
 * host's certificate chain, even if the host attempts to authenticate with a
 * certificate allowed by the device's trusted store of certificates.
 *
 * More information about the public key pinning can be found in
 * <a href="https://tools.ietf.org/html/rfc7469">RFC 7469</a>.
 */
struct PublicKeyPins {
  /**
   * Name of the host to which the public keys should be pinned. A host that
   * consists only of digits and the dot character is treated as invalid.
   */
  string host;

  /**
   * An array of pins. Each pin is the SHA-256 cryptographic
   * hash (in the form of "sha256/<base64-hash-value>") of the DER-encoded ASN.1
   * representation of the Subject Public Key Info (SPKI) of the host's X.509 certificate.
   * Although, the method does not mandate the presence of the backup pin
   * that can be used if the control of the primary private key has been
   * lost, it is highly recommended to supply one.
   */
  array<string> pins_sha256;

  /**
   * Indicates whether the pinning policy should be applied to subdomains of |host|.
   */
  bool include_subdomains = false;

  /**
   * The expiration date for the pins in milliseconds since epoch (as in java.util.Date).
   */
  int64 expiration_date = 0;
};

/**
 * Parameters for Engine, which allows its configuration before start.
 * Configuration options are set on the EngineParms and
 * then Engine.StartWithParams is called to start the Engine.
 */
struct EngineParams {
  /**
   * Override strict result checking for all operations that return RESULT.
   * If set to true, then failed result will cause native crash via SIGABORT.
   */
  bool enable_check_result = true;

  /**
   * Override of the User-Agent header for all requests. An explicitly
   * set User-Agent header will override a value set using this param.
   */
  string user_agent;

  /**
   * Sets a default value for the Accept-Language header value for UrlRequests
   * created by this engine. Explicitly setting the Accept-Language header
   * value for individual UrlRequests will override this value.
   */
  string accept_language;

  /**
   * Directory for HTTP Cache and Prefs Storage. The directory must exist.
   */
  string storage_path;

  /**
   * Whether <a href="https://www.chromium.org/quic">QUIC</a> protocol
   * is enabled. If QUIC is enabled, then QUIC User Agent Id
   * containing application name and Cronet version is sent to the server.
   */
  bool enable_quic = true;

  /**
   * Whether <a href="https://tools.ietf.org/html/rfc7540">HTTP/2</a>
   * protocol is enabled.
   */
  bool enable_http2 = true;

  /**
   * Whether <a href="https://tools.ietf.org/html/rfc7932">Brotli</a> compression is
   * enabled. If enabled, Brotli will be advertised in Accept-Encoding request headers.
   */
  bool enable_brotli = true;

  /**
   * Enables or disables caching of HTTP data and other information like QUIC
   * server information.
   */
  enum HTTP_CACHE_MODE {
    /**
     * Disable HTTP cache. Some data may still be temporarily stored in memory.
     */
    DISABLED = 0,

    /**
     * Enable in-memory HTTP cache, including HTTP data.
     */
    IN_MEMORY = 1,

    /**
     * Enable on-disk cache, excluding HTTP data.
     * |storagePath| must be set to existing directory.
     */
    DISK_NO_HTTP = 2,

    /**
     * Enable on-disk cache, including HTTP data.
     * |storagePath| must be set to existing directory.
     */
    DISK = 3
  };
  HTTP_CACHE_MODE http_cache_mode = DISABLED;

  /**
   * Maximum size in bytes used to cache data (advisory and maybe exceeded at
   * times).
   */
  int64 http_cache_max_size = 0;

  /**
   * Hints that hosts support QUIC.
   */
  array<QuicHint> quic_hints;

  /**
   * Pins a set of public keys for given hosts. See |PublicKeyPins| for explanation.
   */
  array<PublicKeyPins> public_key_pins;

  /**
   * Enables or disables public key pinning bypass for local trust anchors. Disabling the
   * bypass for local trust anchors is highly discouraged since it may prohibit the app
   * from communicating with the pinned hosts. E.g., a user may want to send all traffic
   * through an SSL enabled proxy by changing the device proxy settings and adding the
   * proxy certificate to the list of local trust anchor. Disabling the bypass will most
   * likly prevent the app from sending any traffic to the pinned hosts. For more
   * information see 'How does key pinning interact with local proxies and filters?' at
   * https://www.chromium.org/Home/chromium-security/security-faq
   */
  bool enable_public_key_pinning_bypass_for_local_trust_anchors = true;

  /**
   * Optional network thread priority. NAN indicates unset, use default.
   * On Android, corresponds to android.os.Process.setThreadPriority() values.
   * Do not specify for other platforms.
   */
  double network_thread_priority = double.NAN;

  /**
   * JSON formatted experimental options to be used in Cronet Engine.
   */
  string experimental_options;
};

/**
  * Single HTTP request or response header.
  */
struct HttpHeader {
  /**
   * Header name.
   */
  string name;

  /**
   * Header value.
   */
  string value;
};

struct UrlResponseInfo {
  /**
   * The URL the response is for. This is the URL after following
   * redirects, so it may not be the originally requested URL.
   */
  string url;

  /**
   * The URL chain. The first entry is the originally requested URL;
   * the following entries are redirects followed.
   */
  array<string> url_chain;

  /**
   * The HTTP status code. When a resource is retrieved from the cache,
   * whether it was revalidated or not, the original status code is returned.
   */
  int32 http_status_code = 0;

  /**
   * The HTTP status text of the status line. For example, if the
   * request received a "HTTP/1.1 200 OK" response, this method returns "OK".
   */
  string http_status_text;

  /**
   * Returns an unmodifiable list of response header field and value pairs.
   * The headers are in the same order they are received over the wire.
   */
  array<HttpHeader> all_headers_list;

  /**
   * True if the response came from the cache, including
   * requests that were revalidated over the network before being retrieved
   * from the cache, failed otherwise.
   */
  bool was_cached = false;

  /**
   * The protocol (for example 'quic/1+spdy/3') negotiated with the server.
   * An empty string if no protocol was negotiated, the protocol is
   * not known, or when using plain HTTP or HTTPS.
   */
  string negotiated_protocol;

  /**
   * The proxy server that was used for the request.
   */
  string proxy_server;

  /**
   * A minimum count of bytes received from the network to process this
   * request. This count may ignore certain overheads (for example IP and
   * TCP/UDP framing, SSL handshake and framing, proxy handling). This count is
   * taken prior to decompression (for example GZIP and Brotli) and includes
   * headers and data from all redirects.
   */
  int64 received_byte_count = 0;
};

/**
 * Listener class used with UrlRequest.GetStatus() to receive the status of a
 * UrlRequest.
 */
[Abstract]
interface UrlRequestStatusListener {
  enum Status {
    /**
     * This state indicates that the request is completed, canceled, or is not
     * started.
     */
    INVALID = -1,

    /**
     * This state corresponds to a resource load that has either not yet begun
     * or is idle waiting for the consumer to do something to move things along
     * (e.g. when the consumer of a UrlRequest has not called
     * UrlRequest.read() yet).
     */
    IDLE = 0,

    /**
     * When a socket pool group is below the maximum number of sockets allowed
     * per group, but a new socket cannot be created due to the per-pool socket
     * limit, this state is returned by all requests for the group waiting on an
     * idle connection, except those that may be serviced by a pending new
     * connection.
     */
    WAITING_FOR_STALLED_SOCKET_POOL = 1,

    /**
     * When a socket pool group has reached the maximum number of sockets
     * allowed per group, this state is returned for all requests that don't
     * have a socket, except those that correspond to a pending new connection.
     */
    WAITING_FOR_AVAILABLE_SOCKET = 2,

    /**
     * This state indicates that the URLRequest delegate has chosen to block
     * this request before it was sent over the network.
     */
    WAITING_FOR_DELEGATE = 3,

    /**
     * This state corresponds to a resource load that is blocked waiting for
     * access to a resource in the cache. If multiple requests are made for the
     * same resource, the first request will be responsible for writing (or
     * updating) the cache entry and the second request will be deferred until
     * the first completes. This may be done to optimize for cache reuse.
     */
    WAITING_FOR_CACHE = 4,

    /**
     * This state corresponds to a resource being blocked waiting for the
     * PAC script to be downloaded.
     */
    DOWNLOADING_PAC_FILE = 5,

    /**
     * This state corresponds to a resource load that is blocked waiting for a
     * proxy autoconfig script to return a proxy server to use.
     */
    RESOLVING_PROXY_FOR_URL = 6,

    /**
     * This state corresponds to a resource load that is blocked waiting for a
     * proxy autoconfig script to return a proxy server to use, but that proxy
     * script is busy resolving the IP address of a host.
     */
    RESOLVING_HOST_IN_PAC_FILE = 7,

    /**
     * This state indicates that we're in the process of establishing a tunnel
     * through the proxy server.
     */
    ESTABLISHING_PROXY_TUNNEL = 8,

    /**
     * This state corresponds to a resource load that is blocked waiting for a
     * host name to be resolved. This could either indicate resolution of the
     * origin server corresponding to the resource or to the host name of a
     * proxy server used to fetch the resource.
     */
    RESOLVING_HOST = 9,

    /**
     * This state corresponds to a resource load that is blocked waiting for a
     * TCP connection (or other network connection) to be established. HTTP
     * requests that reuse a keep-alive connection skip this state.
     */
    CONNECTING = 10,

    /**
     * This state corresponds to a resource load that is blocked waiting for the
     * SSL handshake to complete.
     */
    SSL_HANDSHAKE = 11,

    /**
     * This state corresponds to a resource load that is blocked waiting to
     * completely upload a request to a server. In the case of a HTTP POST
     * request, this state includes the period of time during which the message
     * body is being uploaded.
     */
    SENDING_REQUEST = 12,

    /**
     * This state corresponds to a resource load that is blocked waiting for the
     * response to a network request. In the case of a HTTP transaction, this
     * corresponds to the period after the request is sent and before all of the
     * response headers have been received.
     */
    WAITING_FOR_RESPONSE = 13,

    /**
     * This state corresponds to a resource load that is blocked waiting for a
     * read to complete. In the case of a HTTP transaction, this corresponds to
     * the period after the response headers have been received and before all
     * of the response body has been downloaded. (NOTE: This state only applies
     * for an {@link UrlRequest} while there is an outstanding
     * {@link UrlRequest#read read()} operation.)
     */
    READING_RESPONSE = 14
  };

  /**
   * Invoked on UrlRequest's Executor when request status is obtained.
   * |status| is representing the status of the request.
   */
  OnStatus(Status status);
};

/**
 * Users of Cronet implement this interface to receive callbacks indicating the
 * progress of a UrlRequest being processed. An instance of this interface
 * is passed in to UrlRequest's method InitWithParams().
 * <p>
 * Note:  All methods will be invoked on the Executor passed to UrlRequest.InitWithParams();
 */
[Abstract]
interface UrlRequestCallback {
  /**
   * Invoked whenever a redirect is encountered. This will only be invoked
   * between the call to UrlRequest.start() and
   * UrlRequestCallback.onResponseStarted().
   * The body of the redirect response, if it has one, will be ignored.
   *
   * The redirect will not be followed until the URLRequest.followRedirect()
   * ethod is called, either synchronously or asynchronously.
   *
   * @param request Request being redirected.
   * @param info Response information.
   * @param new_location_url Location where request is redirected.
   */
  OnRedirectReceived(UrlRequest request, UrlResponseInfo info, string new_location_url);

  /**
   * Invoked when the final set of headers, after all redirects, is received.
   * Will only be invoked once for each request.
   *
   * With the exception of UrlRequestCallback.onCanceled(),
   * no other UrlRequestCallback method will be invoked for the request,
   * including UrlRequestCallback.onSucceeded() and
   * UrlRequestCallback.onFailed(), until UrlRequest.read()} is called to attempt
   * to start reading the response body.
   *
   * @param request Request that started to get response.
   * @param info Response information.
   */
  OnResponseStarted(UrlRequest request, UrlResponseInfo info);

  /**
   * Invoked whenever part of the response body has been read. Only part of
   * the buffer may be populated, even if the entire response body has not yet
   * been consumed. This callback transfers ownership of |buffer| back to the app,
   * and Cronet guarantees not to access it.
   *
   * With the exception of UrlRequestCallback.onCanceled(),
   * no other UrlRequestCallback method will be invoked for the request,
   * including UrlRequestCallback.onSucceeded() and
   * UrlRequestCallback.onFailed(), until UrlRequest.read()} is called to attempt
   * to continue reading the response body.
   *
   * @param request Request that received data.
   * @param info Response information.
   * @param buffer The buffer that was passed in to UrlRequest.read(), now
   *         containing the received data.
   * @param bytes_read The number of bytes read into buffer.
   */
  OnReadCompleted(UrlRequest request, UrlResponseInfo info, Buffer buffer, uint64 bytes_read);

  /**
   * Invoked when request is completed successfully. Once invoked, no other
   * UrlRequestCallback methods will be invoked.
   *
   * Implementations of {@link #OnSucceeded} are allowed to call {@code
   * Cronet_UrlRequest_Destroy(request)}, but note that destroying {@code
   * request} destroys {@code info}.
   *
   * @param request Request that succeeded.
   * @param info Response information. NOTE: this is owned by {@code request}.
   */
  OnSucceeded(UrlRequest request, UrlResponseInfo info);

  /**
   * Invoked if request failed for any reason after UrlRequest.start().
   * Once invoked, no other UrlRequestCallback methods will be invoked.
   * |error| provides information about the failure.
   *
   * Implementations of {@link #OnFailed} are allowed to call {@code
   * Cronet_UrlRequest_Destroy(request)}, but note that destroying {@code
   * request} destroys {@code info} and {@code error}.
   *
   * @param request Request that failed.
   * @param info Response information. May be null if no response was
   *         received. NOTE: this is owned by {@code request}.
   * @param error information about error. NOTE: this is owned by {@code
   *         request}.
   */
  OnFailed(UrlRequest request, UrlResponseInfo info, Error error);

  /**
   * Invoked if request was canceled via UrlRequest.cancel(). Once
   * invoked, no other UrlRequestCallback methods will be invoked.
   *
   * Implementations of {@link #OnCanceled} are allowed to call {@code
   * Cronet_UrlRequest_Destroy(request)}, but note that destroying {@code
   * request} destroys {@code info}.
   *
   * @param request Request that was canceled.
   * @param info Response information. May be null if no response was
   *         received. NOTE: this is owned by {@code request}.
   */
  OnCanceled(UrlRequest request, UrlResponseInfo info);
};

/**
 * Defines callbacks methods for UploadDataProvider. All methods
 * may be called synchronously or asynchronously, on any thread.
 */
interface UploadDataSink {
  /**
   * Called by UploadDataProvider when a read succeeds.
   *
   * @param bytes_read number of bytes read into buffer passed to read().
   * @param final_chunk For chunked uploads, |true| if this is the final
   *     read. It must be |false| for non-chunked uploads.
   */
  OnReadSucceeded(uint64 bytes_read, bool final_chunk);

  /**
   * Called by UploadDataProvider when a read fails.
   * @param error_message to pass on to UrlRequestCallback.onFailed().
   */
  OnReadError(string error_message);

  /**
   * Called by UploadDataProvider when a rewind succeeds.
   */
  OnRewindSucceeded();

  /**
   * Called by UploadDataProvider when a rewind fails, or if rewinding
   * uploads is not supported.
   * @param error_message to pass on to UrlRequestCallback.onFailed().
   */
  OnRewindError(string error_message);
};

/**
 * The interface allowing the embedder to provide an upload body to
 * UrlRequest. It supports both non-chunked (size known in advanced) and
 * chunked (size not known in advance) uploads. Be aware that not all servers
 * support chunked uploads.
 *
 * An upload is either always chunked, across multiple uploads if the data
 * ends up being sent more than once, or never chunked.
 */
[Abstract]
interface UploadDataProvider {
  /**
   * If this is a non-chunked upload, returns the length of the upload. Must
   * always return -1 if this is a chunked upload.
   */
  [Sync]
  GetLength() => (int64 length);

  /**
   * Reads upload data into |buffer|. Each call of this method must be followed be a
   * single call, either synchronous or asynchronous, to
   * UploadDataSink.onReadSucceeded() on success
   * or UploadDataSink.onReadError() on failure. Neither read nor rewind
   * will be called until one of those methods or the other is called. Even if
   * the associated UrlRequest is canceled, one or the other must
   * still be called before resources can be safely freed.
   *
   * @param upload_data_sink The object to notify when the read has completed,
   *            successfully or otherwise.
   * @param buffer The buffer to copy the read bytes into.
   */
  Read(UploadDataSink upload_data_sink, Buffer buffer);

  /**
   * Rewinds upload data. Each call must be followed be a single
   * call, either synchronous or asynchronous, to
   * UploadDataSink.onRewindSucceeded() on success or
   * UploadDataSink.onRewindError() on failure. Neither read nor rewind
   * will be called until one of those methods or the other is called.
   * Even if the associated UrlRequest is canceled, one or the other
   * must still be called before resources can be safely freed.
   *
   * If rewinding is not supported, this should call
   * UploadDataSink.onRewindError(). Note that rewinding is required to
   * follow redirects that preserve the upload body, and for retrying when the
   * server times out stale sockets.
   *
   * @param upload_data_sink The object to notify when the rewind operation has
   *         completed, successfully or otherwise.
   */
  Rewind(UploadDataSink upload_data_sink);

  /**
   * Called when this UploadDataProvider is no longer needed by a request, so that resources
   * (like a file) can be explicitly released.
   */
  Close();
};

/**
 * Controls an HTTP request (GET, PUT, POST etc).
 * Initialized by InitWithParams().
 * Note: All methods must be called on the Executor passed to InitWithParams().
 */
interface UrlRequest {
  /**
   * Initialized UrlRequest to |url| with |params|. All methods of |callback| for
   * request will be invoked on |executor|. The |executor| must not run tasks on
   * the thread calling Executor.execute() to prevent blocking networking
   * operations and causing failure RESULTs during shutdown.
   *
   * @param engine Engine to process the request.
   * @param url URL for the request.
   * @param params additional parameters for the request, like headers and priority.
   * @param callback Callback that gets invoked on different events.
   * @param executor Executor on which all callbacks will be invoked.
   */
  [Sync]
  InitWithParams(Engine engine,
                 string url,
                 UrlRequestParams params,
                 UrlRequestCallback callback,
                 Executor executor) => (RESULT result);

  /**
   * Starts the request, all callbacks go to UrlRequestCallback. May only be called
   * once. May not be called if Cancel() has been called.
   */
  [Sync]
  Start() => (RESULT result);

  /**
   * Follows a pending redirect. Must only be called at most once for each
   * invocation of UrlRequestCallback.OnRedirectReceived().
   */
  [Sync]
  FollowRedirect() => (RESULT result);

  /**
   * Attempts to read part of the response body into the provided buffer.
   * Must only be called at most once in response to each invocation of the
   * UrlRequestCallback.OnResponseStarted() and
   * UrlRequestCallback.OnReadCompleted()} methods of the UrlRequestCallback.
   * Each call will result in an asynchronous call to
   * either the UrlRequestCallback.OnReadCompleted() method if data
   * is read, its UrlRequestCallback.OnSucceeded() method if
   * there's no more data to read, or its UrlRequestCallback.OnFailed()
   * method if there's an error.
   * This method transfers ownership of |buffer| to Cronet, and app should
   * not access it until one of these callbacks is invoked.
   *
   * @param buffer to write response body to. The app must not read or
   *        modify buffer's position, limit, or data between its position and
   *        limit until the request calls back into the UrlRequestCallback.
   */
  [Sync]
  Read(Buffer buffer) => (RESULT result);

  /**
   * Cancels the request. Can be called at any time.
   * UrlRequestCallback.OnCanceled() will be invoked when cancellation
   * is complete and no further callback methods will be invoked. If the
   * request has completed or has not started, calling Cancel() has no
   * effect and OnCanceled() will not be invoked. If the
   * Executor passed in to UrlRequest.InitWithParams() runs
   * tasks on a single thread, and Cancel() is called on that thread,
   * no callback methods (besides OnCanceled() will be invoked after
   * Cancel() is called. Otherwise, at most one callback method may be
   * invoked after Cancel() has completed.
   */
  Cancel();

  /**
   * Returns true if the request was successfully started and is now
   * finished (completed, canceled, or failed).
   */
  [Sync]
  IsDone() => (bool done);

  /**
   * Queries the status of the request.
   * @param listener a UrlRequestStatusListener that will be invoked with
   *         the request's current status. Listener will be invoked
   *         back on the Executor passed in when the request was
   *         created.
   */
  GetStatus(UrlRequestStatusListener listener);
};

/**
 * Parameters for UrlRequest. Allows configuring requests before initializing them
 * with UrlRequest.InitWithParams().
 */
struct UrlRequestParams {
  enum REQUEST_PRIORITY {
    /**
     * Lowest request priority.
     */
    REQUEST_PRIORITY_IDLE = 0,
    /**
     * Very low request priority.
     */
    REQUEST_PRIORITY_LOWEST = 1,
    /**
     * Low request priority.
     */
    REQUEST_PRIORITY_LOW = 2,
    /**
     * Medium request priority. This is the default priority given to the request.
     */
    REQUEST_PRIORITY_MEDIUM = 3,
    /**
     * Highest request priority.
     */
    REQUEST_PRIORITY_HIGHEST = 4,
  };

  /**
   * The HTTP method verb to use for this request.
   *
   * The default when this value is not set is "GET" if the request has
   * no body or "POST" if it does.
   *
   * Allowed methods are "GET", "HEAD", "DELETE", "POST" or "PUT".
   */
  string http_method;

  /**
   * Array of HTTP headers for this request..
   */
  array<HttpHeader> request_headers;

  /**
   * Disables cache for the request. If context is not set up to use cache,
   * this call has no effect.
   */
  bool disable_cache = false;

  /**
   * Priority of the request which should be one of the REQUEST_PRIORITY values.
   */
  REQUEST_PRIORITY priority = REQUEST_PRIORITY_MEDIUM;

  /**
   * Upload data provider. Setting this value switches method to "POST" if not
   * explicitly set. Starting the request will fail if a Content-Type header is not set.
   */
  UploadDataProvider? upload_data_provider;

  /**
   * Upload data provider executor that will be used to invoke uploadDataProvider.
   */
  Executor? upload_data_provider_executor;

  /**
   * Marks that the executors this request will use to notify callbacks (for
   * UploadDataProvider and UrlRequestCallback) is intentionally performing
   * inline execution without switching to another thread.
   *
   * <p><b>Warning:</b> This option makes it easy to accidentally block the network thread.
   * It should not be used if your callbacks perform disk I/O, acquire locks, or call into
   * other code you don't carefully control and audit.
   */
  bool allow_direct_executor = false;

  /**
   * Associates the annotation object with this request. May add more than one.
   * Passed through to a RequestFinishedInfoListener.
   */
  array<handle> annotations;

  /**
   * A listener that gets invoked at the end of each request.
   *
   * The listener is invoked with the request finished info on {@code
   * request_finished_executor}, which must be set.
   *
   * The listener is called before {@link UrlRequestCallback.OnCanceled()},
   * {@link UrlRequestCallback.OnFailed()} or {@link
   * UrlRequestCallback.OnSucceeded()} is called -- note that if {@code
   * request_finished_executor} runs the listener asyncronously, the actual
   * call to the listener may happen after a {@code UrlRequestCallback} method
   * is called.

   * Ownership is **not** taken.
   *
   * Assuming the listener won't run again (there are no pending requests with
   * the listener attached, either via {@code Engine} or {@code UrlRequest}),
   * the app may destroy it once its {@code OnRequestFinished()} has started,
   * even inside that method.
   */
  RequestFinishedInfoListener? request_finished_listener;

  /**
   * The Executor used to run the {@code request_finished_listener}.
   *
   * Ownership is **not** taken.
   *
   * Similar to {@code request_finished_listener}, the app may destroy {@code
   * request_finished_executor} in or after {@code OnRequestFinished()}.
   *
   * It's also OK to destroy {@code request_finished_executor} in or after one
   * of {@link UrlRequestCallback.OnCanceled()}, {@link
   * UrlRequestCallback.OnFailed()} or {@link
   * UrlRequestCallback.OnSucceeded()}.
   *
   * Of course, both of these are only true if {@code
   * request_finished_executor} isn't being used for anything else that might
   * start running in the future.
   */
  Executor? request_finished_executor;

  enum IDEMPOTENCY {
    DEFAULT_IDEMPOTENCY = 0,
    IDEMPOTENT = 1,
    NOT_IDEMPOTENT = 2,
  };

 /**
   * Idempotency of the request, which determines that if it is safe to enable
   * 0-RTT for the Cronet request. By default, 0-RTT is only enabled for safe
   * HTTP methods, i.e., GET, HEAD, OPTIONS, and TRACE. For other methods,
   * enabling 0-RTT may cause security issues since a network observer can
   * replay the request. If the request has any side effects, those effects can
   * happen multiple times. It is only safe to enable the 0-RTT if it is known
   * that the request is idempotent.
   */
  IDEMPOTENCY idempotency = DEFAULT_IDEMPOTENCY;
};

/**
 * Represents a date and time expressed as the number of milliseconds since the
 * UNIX epoch.
 */
struct DateTime {
  /**
   * Number of milliseconds since the UNIX epoch.
   */
  int64 value = 0;
};

/*
 * Represents metrics collected for a single request. Most of these metrics are
 * timestamps for events during the lifetime of the request, which can be used
 * to build a detailed timeline for investigating performance.
 *
 * Events happen in this order:
 * <ol>
 * <li>{@link #request_start request start}</li>
 * <li>{@link #dns_start DNS start}</li>
 * <li>{@link #dns_end DNS end}</li>
 * <li>{@link #connect_start connect start}</li>
 * <li>{@link #ssl_start SSL start}</li>
 * <li>{@link #ssl_end SSL end}</li>
 * <li>{@link #connect_end connect end}</li>
 * <li>{@link #sending_start sending start}</li>
 * <li>{@link #sending_end sending end}</li>
 * <li>{@link #response_start response start}</li>
 * <li>{@link #request_end request end}</li>
 * </ol>
 *
 * Start times are reported as the time when a request started blocking on the
 * event, not when the event actually occurred, with the exception of push
 * start and end. If a metric is not meaningful or not available, including
 * cases when a request finished before reaching that stage, start and end
 * times will be null. If no time was spent blocking on an event, start and end
 * will be the same time.
 *
 * Timestamps are recorded using a clock that is guaranteed not to run
 * backwards. All timestamps are correct relative to the system clock at the
 * time of request start, and taking the difference between two timestamps will
 * give the correct difference between the events. In order to preserve this
 * property, timestamps for events other than request start are not guaranteed
 * to match the system clock at the times they represent.
 *
 * Most timing metrics are taken from
 * <a
 * href="https://cs.chromium.org/chromium/src/net/base/load_timing_info.h">LoadTimingInfo</a>,
 * which holds the information for <a href="http://w3c.github.io/navigation-timing/"></a> and
 * <a href="https://www.w3.org/TR/resource-timing/"></a>.
 */
struct Metrics {
  /**
   * Time when the request started, which corresponds to calling
   * Cronet_UrlRequest_Start(). This timestamp will match the system clock at
   * the time it represents.
   */
  DateTime request_start;

  /**
   * Time when DNS lookup started. This and {@link #dns_end} will be set to
   * non-null regardless of whether the result came from a DNS server or the
   * local cache. Will equal null if the socket was reused (see {@link
   * #socket_reused}).
   */
  DateTime? dns_start;

  /**
   * Time when DNS lookup finished. This and {@link dns_start} will return
   * non-null regardless of whether the result came from a DNS server or the
   * local cache. Will equal null if the socket was reused (see {@link
   * #socket_reused}).
   */
  DateTime? dns_end;

  /**
   * Time when connection establishment started, typically when DNS resolution
   * finishes. Will equal null if the socket was reused (see {@link
   * #socket_reused}).
   */
  DateTime? connect_start;

  /**
   * Time when connection establishment finished, after TCP connection is
   * established and, if using HTTPS, SSL handshake is completed. For QUIC
   * 0-RTT, this represents the time of handshake confirmation and might happen
   * later than {@link #sending_start}. Will equal null if the socket was
   * reused (see {@link #socket_reused}).
   */
  DateTime? connect_end;

  /**
   * Time when SSL handshake started. For QUIC, this will be the same time as
   * {@link #connect_start}. Will equal null if SSL is not used or if the
   * socket was reused (see {@link #socket_reused}).
   */
  DateTime? ssl_start;

  /**
   * Time when SSL handshake finished. For QUIC, this will be the same time as
   * {@link #connect_end}. Will equal null if SSL is not used or if the socket
   * was reused (see {@link #socket_reused}).
   */
  DateTime? ssl_end;

  /**
   * Time when sending HTTP request headers started.
   *
   * Will equal null if the request failed or was canceled before sending
   * started.
   */
  DateTime? sending_start;

  /**
   * Time when sending HTTP request body finished. (Sending request body
   * happens after sending request headers.)
   *
   * Will equal null if the request failed or was canceled before sending
   * ended.
   */
  DateTime? sending_end;

  /**
   * Time when first byte of HTTP/2 server push was received.  Will equal
   * null if server push is not used.
   */
  DateTime? push_start;

  /**
   * Time when last byte of HTTP/2 server push was received.  Will equal
   * null if server push is not used.
   */
  DateTime? push_end;

  /**
   * Time when the end of the response headers was received.
   *
   * Will equal null if the request failed or was canceled before the response
   * started.
   */
  DateTime? response_start;

  /**
   * Time when the request finished.
   */
  DateTime request_end;

  /**
   * True if the socket was reused from a previous request, false otherwise.
   * In HTTP/2 or QUIC, if streams are multiplexed in a single connection, this
   * will be {@code true} for all streams after the first.  When {@code true},
   * DNS, connection, and SSL times will be null.
   */
  bool socket_reused = false;

  /**
   * Returns total bytes sent over the network transport layer, or -1 if not
   * collected.
   */
  int64 sent_byte_count = -1;

  /**
   * Total bytes received over the network transport layer, or -1 if not
   * collected. Number of bytes does not include any previous redirects.
   */
  int64 received_byte_count = -1;
};

/**
 * Information about a finished request.
 */
struct RequestFinishedInfo {
  /**
   * The reason why the request finished.
   */
  enum FINISHED_REASON {
    /**
     * The request succeeded.
     */
    SUCCEEDED = 0,
    /**
     * The request failed or returned an error.
     */
    FAILED = 1,
    /**
     * The request was canceled.
     */
    CANCELED = 2,
  };

  /**
   * Metrics collected for this request.
   */
  Metrics metrics;

  /**
   * The objects that the caller has supplied when initiating the request,
   * using {@link UrlRequestParams.annotations}.
   *
   * Annotations can be used to associate a {@link RequestFinishedInfo} with
   * the original request or type of request.
   */
  array<handle> annotations;

  /**
   * Returns the reason why the request finished.
   */
  FINISHED_REASON finished_reason = SUCCEEDED;
};

/**
 * Listens for finished requests for the purpose of collecting metrics.
 */
[Abstract]
interface RequestFinishedInfoListener {
  /**
   * Will be called in a task submitted to the {@code Executor} passed with
   * this {@code RequestFinishedInfoListener}.
   *
   * The listener is called before {@link UrlRequestCallback.OnCanceled()},
   * {@link UrlRequestCallback.OnFailed()} or {@link
   * UrlRequestCallback.OnSucceeded()} is called -- note that if the executor
   * runs the listener asyncronously, the actual call to the listener may
   * happen after a {@code UrlRequestCallback} method is called.
   *
   * @param request_info {@link RequestFinishedInfo} for finished request.
   *     Ownership is *not* transferred by this call, do not destroy
   *     {@code request_info}.
   *
   *     {@code request_info} will be valid as long as the {@code UrlRequest}
   *     that created it hasn't been destroyed -- **additionally**, it will
   *     also always be valid for the duration of {@code OnRequestFinished()},
   *     even if the {@code UrlRequest} has been destroyed.
   *
   *     This is accomplished by ownership being shared between the {@code
   *     UrlRequest} and the code that calls this listener.
   *
   * @param response_info A pointer to the same UrlResponseInfo passed to
   *     {@link UrlRequestCallback.OnCanceled()}, {@link
   *     UrlRequestCallback.OnFailed()} or {@link
   *     UrlRequestCallback.OnSucceeded()}. The lifetime and ownership of
   *     {@code response_info} works the same as for {@code request_info}.
   *
   * @param error A pointer to the same Error passed to
   *     {@code UrlRequestCallback.OnFailed()}, or null if there was no error.
   *     The lifetime and ownership of {@code error} works the same as for
   *     {@code request_info}.
   */
  OnRequestFinished(RequestFinishedInfo request_info,
                    UrlResponseInfo response_info,
                    Error error);
};