// Copyright 2016 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package org.chromium.net; import androidx.annotation.Nullable; import java.util.Collection; import java.util.Date; import java.util.concurrent.Executor; /** * Information about a finished request. Passed to {@link RequestFinishedInfo.Listener}. * *

To associate the data with the original request, use {@link * UrlRequest.Builder#addRequestAnnotation} to add a unique identifier when creating the * request, and call {@link #getAnnotations} when the {@link RequestFinishedInfo} is received to * retrieve the identifier. */ public abstract class RequestFinishedInfo { /** Listens for finished requests for the purpose of collecting metrics. */ public abstract static class Listener { private final Executor mExecutor; public Listener(Executor executor) { if (executor == null) { throw new IllegalStateException("Executor must not be null"); } mExecutor = executor; } /** * Invoked with request info. Will be called in a task submitted to the {@link * java.util.concurrent.Executor} returned by {@link #getExecutor}. * * @param requestInfo {@link RequestFinishedInfo} for finished request. */ public abstract void onRequestFinished(RequestFinishedInfo requestInfo); /** * Returns this listener's executor. Can be called on any thread. * * @return this listener's {@link java.util.concurrent.Executor} */ public Executor getExecutor() { return mExecutor; } } /** * 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: * *

    *
  1. {@link #getRequestStart request start} *
  2. {@link #getDnsStart DNS start} *
  3. {@link #getDnsEnd DNS end} *
  4. {@link #getConnectStart connect start} *
  5. {@link #getSslStart SSL start} *
  6. {@link #getSslEnd SSL end} *
  7. {@link #getConnectEnd connect end} *
  8. {@link #getSendingStart sending start} *
  9. {@link #getSendingEnd sending end} *
  10. {@link #getResponseStart response start} *
  11. {@link #getRequestEnd request end} *
* * Start times are reported as the time when a request started blocking on 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 {@code null}. If no time was spent blocking on an event, * start and end will be the same time. * *

If the system clock is adjusted during the request, some of the {@link java.util.Date} * values might not match it. 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 LoadTimingInfo, * which holds the information for and . * *

{@hide} as it's a prototype. */ public abstract static class Metrics { /** * Returns time when the request started. * * @return {@link java.util.Date} representing when the native request actually started. * This * timestamp will match the system clock at the time it represents. */ @Nullable public abstract Date getRequestStart(); /** * Returns time when DNS lookup started. This and {@link #getDnsEnd} will return non-null * values regardless of whether the result came from a DNS server or the local cache. * * @return {@link java.util.Date} representing when DNS lookup started. {@code null} if the * socket was reused (see {@link #getSocketReused}). */ @Nullable public abstract Date getDnsStart(); /** * Returns time when DNS lookup finished. This and {@link #getDnsStart} will return non-null * values regardless of whether the result came from a DNS server or the local cache. * * @return {@link java.util.Date} representing when DNS lookup finished. {@code null} if the * socket was reused (see {@link #getSocketReused}). */ @Nullable public abstract Date getDnsEnd(); /** * Returns time when connection establishment started. * * @return {@link java.util.Date} representing when connection establishment started, * typically * when DNS resolution finishes. {@code null} if the socket was reused (see {@link * #getSocketReused}). */ @Nullable public abstract Date getConnectStart(); /** * Returns time when connection establishment finished. * * @return {@link java.util.Date} representing 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 #getSendingStart}. {@code null} if the socket was reused (see {@link * #getSocketReused}). */ @Nullable public abstract Date getConnectEnd(); /** * Returns time when SSL handshake started. For QUIC, this will be the same time as {@link * #getConnectStart}. * * @return {@link java.util.Date} representing when SSL handshake started. {@code null} if * SSL * is not used or if the socket was reused (see {@link #getSocketReused}). */ @Nullable public abstract Date getSslStart(); /** * Returns time when SSL handshake finished. For QUIC, this will be the same time as {@link * #getConnectEnd}. * * @return {@link java.util.Date} representing when SSL handshake finished. {@code null} if * SSL * is not used or if the socket was reused (see {@link #getSocketReused}). */ @Nullable public abstract Date getSslEnd(); /** * Returns time when sending the request started. * * @return {@link java.util.Date} representing when sending HTTP request headers started. */ @Nullable public abstract Date getSendingStart(); /** * Returns time when sending the request finished. * * @return {@link java.util.Date} representing when sending HTTP request body finished. * (Sending * request body happens after sending request headers.) */ @Nullable public abstract Date getSendingEnd(); /** * Returns time when first byte of HTTP/2 server push was received. * * @return {@link java.util.Date} representing when the first byte of an HTTP/2 server push * was * received. {@code null} if server push is not used. */ @Nullable public abstract Date getPushStart(); /** * Returns time when last byte of HTTP/2 server push was received. * * @return {@link java.util.Date} representing when the last byte of an HTTP/2 server push * was * received. {@code null} if server push is not used. */ @Nullable public abstract Date getPushEnd(); /** * Returns time when the end of the response headers was received. * * @return {@link java.util.Date} representing when the end of the response headers was * received. */ @Nullable public abstract Date getResponseStart(); /** * Returns time when the request finished. * * @return {@link java.util.Date} representing when the request finished. */ @Nullable public abstract Date getRequestEnd(); /** * Returns whether the socket was reused from a previous request. In HTTP/2 or QUIC, if * streams are multiplexed in a single connection, returns {@code true} for all streams * after the first. * * @return whether this request reused a socket from a previous request. When {@code true}, * DNS, * connection, and SSL times will be {@code null}. */ public abstract boolean getSocketReused(); /** * Returns milliseconds between request initiation and first byte of response headers, or * {@code null} if not collected. TODO(mgersh): Remove once new API works * http://crbug.com/629194 * {@hide} */ @Nullable public abstract Long getTtfbMs(); /** * Returns milliseconds between request initiation and finish, including a failure or * cancellation, or {@code null} if not collected. TODO(mgersh): Remove once new API works * http://crbug.com/629194 {@hide} */ @Nullable public abstract Long getTotalTimeMs(); /** * Returns total bytes sent over the network transport layer, or {@code null} if not * collected. */ @Nullable public abstract Long getSentByteCount(); /** * Returns total bytes received over the network transport layer, or {@code null} if not * collected. Number of bytes does not include any previous redirects. */ @Nullable public abstract Long getReceivedByteCount(); } /** Reason value indicating that the request succeeded. Returned from {@link #getFinishedReason}. */ public static final int SUCCEEDED = 0; /** * Reason value indicating that the request failed or returned an error. Returned from {@link * #getFinishedReason}. */ public static final int FAILED = 1; /** * Reason value indicating that the request was canceled. Returned from {@link * #getFinishedReason}. */ public static final int CANCELED = 2; /** * Returns the request's original URL. * * @return the request's original URL */ public abstract String getUrl(); /** * Returns the objects that the caller has supplied when initiating the request, using {@link * UrlRequest.Builder#addRequestAnnotation}. Annotations can be used to associate a * {@link RequestFinishedInfo} with the original request or type of request. * * @return annotations supplied when creating the request */ public abstract Collection getAnnotations(); // TODO(klm): Collect and return a chain of Metrics objects for redirect responses. // TODO(mgersh): Update this javadoc when new metrics are fully implemented /** * Returns metrics collected for this request. * *

The reported times and bytes account for all redirects, i.e. * the TTFB is from the start of the original request to the ultimate response headers, the TTLB * is from the start of the original request to the end of the ultimate response, the received * byte count is for all redirects and the ultimate response combined. These cumulative metric * definitions are debatable, but are chosen to make sense for user-facing latency analysis. * * @return metrics collected for this request. * *

{@hide} as the Metrics class is hidden */ public abstract Metrics getMetrics(); /** * Returns the reason why the request finished. * * @return one of {@link #SUCCEEDED}, {@link #FAILED}, or {@link #CANCELED} */ public abstract int getFinishedReason(); /** * Returns a {@link UrlResponseInfo} for the request, if its response had started. * * @return {@link UrlResponseInfo} for the request, if its response had started. */ @Nullable public abstract UrlResponseInfo getResponseInfo(); /** * If the request failed, returns the same {@link CronetException} provided to {@link * UrlRequest.Callback#onFailed}. * * @return the request's {@link CronetException}, if the request failed */ @Nullable public abstract CronetException getException(); }