// Copyright 2015 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package android.net.http; import android.annotation.IntDef; import android.annotation.SuppressLint; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.ByteBuffer; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; /** * Class for bidirectional sending and receiving of data over HTTP/2 or QUIC connections. Created by * {@link Builder}. * * Note: There are ordering restrictions on methods of {@link BidirectionalStream}; * please see individual methods for description of restrictions. */ public abstract class BidirectionalStream { /** * Lowest stream priority. Passed to {@link Builder#setPriority}. */ public static final int STREAM_PRIORITY_IDLE = 0; /** * Very low stream priority. Passed to {@link Builder#setPriority}. */ public static final int STREAM_PRIORITY_LOWEST = 1; /** * Low stream priority. Passed to {@link Builder#setPriority}. */ public static final int STREAM_PRIORITY_LOW = 2; /** * Medium stream priority. Passed to {@link Builder#setPriority}. This is the * default priority given to the stream. */ public static final int STREAM_PRIORITY_MEDIUM = 3; /** * Highest stream priority. Passed to {@link Builder#setPriority}. */ public static final int STREAM_PRIORITY_HIGHEST = 4; /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef({ BidirectionalStream.STREAM_PRIORITY_IDLE, BidirectionalStream.STREAM_PRIORITY_LOWEST, BidirectionalStream.STREAM_PRIORITY_LOW, BidirectionalStream.STREAM_PRIORITY_MEDIUM, BidirectionalStream.STREAM_PRIORITY_HIGHEST}) public @interface BidirectionalStreamPriority {} /** * Builder for {@link BidirectionalStream}s. Allows configuring stream before constructing * it via {@link Builder#build}. */ // SuppressLint: Builder can not be final since this is abstract and inherited @SuppressLint("StaticFinalBuilder") public abstract static class Builder { /** * Sets the HTTP method for the request. Returns builder to facilitate chaining. * * @param method the method to use for request. Default is 'POST' * @return the builder to facilitate chaining */ @NonNull public abstract Builder setHttpMethod(@NonNull String method); /** * Adds a request header. Returns builder to facilitate chaining. * * @param header the header name * @param value the header value * @return the builder to facilitate chaining */ @NonNull public abstract Builder addHeader(@NonNull String header, @NonNull String value); /** * Sets priority of the stream which should be one of the {@link #STREAM_PRIORITY_IDLE * STREAM_PRIORITY_*} values. The stream is given {@link #STREAM_PRIORITY_MEDIUM} priority * if this method is not called. * * @param priority priority of the stream which should be one of the {@link * #STREAM_PRIORITY_IDLE STREAM_PRIORITY_*} values. * @return the builder to facilitate chaining. */ @NonNull public abstract Builder setPriority(@BidirectionalStreamPriority int priority); /** * Sets whether to delay sending request headers until {@link BidirectionalStream#flush()} * is called. This flag is currently only respected when QUIC is negotiated. * When true, QUIC will send request header frame along with data frame(s) * as a single packet when possible. * * @param delayRequestHeadersUntilFirstFlush if true, sending request headers will be * delayed * until flush() is called. * @return the builder to facilitate chaining. */ @NonNull public abstract Builder setDelayRequestHeadersUntilFirstFlushEnabled( boolean delayRequestHeadersUntilFirstFlush); /** * Sets {@link android.net.TrafficStats} tag to use when accounting socket traffic caused by * this request. See {@link android.net.TrafficStats} for more information. If no tag is * set (e.g. this method isn't called), then Android accounts for the socket traffic caused * by this request as if the tag value were set to 0. *

* NOTE:Setting a tag disallows sharing of sockets with requests * with other tags, which may adversely effect performance by prohibiting * connection sharing. In other words use of multiplexed sockets (e.g. HTTP/2 * and QUIC) will only be allowed if all requests have the same socket tag. * * @param tag the tag value used to when accounting for socket traffic caused by this * request. Tags between 0xFFFFFF00 and 0xFFFFFFFF are reserved and used * internally by system services like {@link android.app.DownloadManager} when * performing traffic on behalf of an application. * @return the builder to facilitate chaining. */ @NonNull public abstract Builder setTrafficStatsTag(int tag); /** * Sets specific UID to use when accounting socket traffic caused by this request. See * {@link android.net.TrafficStats} for more information. Designed for use when performing * an operation on behalf of another application. Caller must hold * {@code android.Manifest.permission#MODIFY_NETWORK_ACCOUNTING} permission. By default * traffic is attributed to UID of caller. *

* NOTE:Setting a UID disallows sharing of sockets with requests * with other UIDs, which may adversely effect performance by prohibiting * connection sharing. In other words use of multiplexed sockets (e.g. HTTP/2 * and QUIC) will only be allowed if all requests have the same UID set. * * @param uid the UID to attribute socket traffic caused by this request. * @return the builder to facilitate chaining. */ @NonNull public abstract Builder setTrafficStatsUid(int uid); /** * Creates a {@link BidirectionalStream} using configuration from this {@link Builder}. The * returned {@code BidirectionalStream} can then be started by calling {@link * BidirectionalStream#start}. * * @return constructed {@link BidirectionalStream} using configuration from this {@link * Builder} */ @NonNull public abstract BidirectionalStream build(); } /** * Callback interface used to receive callbacks from a {@link BidirectionalStream}. */ public interface Callback { /** * Invoked when the stream is ready for reading and writing. Consumer may call {@link * BidirectionalStream#read read()} to start reading data. Consumer may call {@link * BidirectionalStream#write write()} to start writing data. * * @param stream the stream that is ready. This is not guaranteed to be the same * object as the one received by other callbacks, nor is it guaranteed to be the one * returned by {@link BidirectionalStream.Builder#build}. However, method * calls on this object will have the same effects as calls on the original * {@link BidirectionalStream}. */ void onStreamReady(@NonNull BidirectionalStream stream); /** * Invoked when initial response headers are received. Headers are available from {@code * info.}{@link UrlResponseInfo#getHeaders getHeaders()}. Consumer may call {@link * BidirectionalStream#read read()} to start reading. Consumer may call {@link * BidirectionalStream#write write()} to start writing or close the stream. * * @param stream the stream on which response headers were received. This is not * guaranteed to be the same object as the one received by other callbacks, nor is * it guaranteed to be the one returned by {@link BidirectionalStream.Builder#build}. * However, method calls on this object will have the same effects as * calls on the original {@link BidirectionalStream}. * @param info the response information. */ void onResponseHeadersReceived(@NonNull BidirectionalStream stream, @NonNull UrlResponseInfo info); /** * Invoked when data is read into the buffer passed to {@link BidirectionalStream#read * read()}. Only part of the buffer may be populated. To continue reading, call {@link * BidirectionalStream#read read()}. It may be invoked after {@code * onResponseTrailersReceived()}, if there was pending read data before trailers were * received. * * @param stream the stream on which the read completed. This is not guaranteed to * be the same object as the one received by other callbacks, nor is it guaranteed * to be the one returned by {@link BidirectionalStream.Builder#build}. * However, method calls on this object will have the same effects as calls on the * original {@link BidirectionalStream}. * @param info the response information * @param buffer the buffer that was passed to {@link BidirectionalStream#read read()}, now * set to the end of the received data. If position is not updated, it means the remote side * has signaled that it will send no more data. * @param endOfStream if true, this is the last read data, remote will not send more data, * and * the read side is closed. */ void onReadCompleted(@NonNull BidirectionalStream stream, @NonNull UrlResponseInfo info, @NonNull ByteBuffer buffer, boolean endOfStream); /** * Invoked when the entire ByteBuffer passed to {@link BidirectionalStream#write write()} is * sent. The buffer's position is updated to be the same as the buffer's limit. The buffer's * limit is not changed. To continue writing, call {@link BidirectionalStream#write * write()}. * * @param stream the stream on which the write completed. This is not guaranteed to * be the same object as the one received by other callbacks, nor is it guaranteed * to be the one returned by {@link BidirectionalStream.Builder#build}. * However, method calls on this object will have the same effects as calls on the * original {@link BidirectionalStream}. * @param info the response information * @param buffer the buffer that was passed to {@link BidirectionalStream#write write()}. * The * buffer's position is set to the buffer's limit. The buffer's limit is not changed. * @param endOfStream the endOfStream flag that was passed to the corresponding {@link * BidirectionalStream#write write()}. If true, the write side is closed. */ void onWriteCompleted(@NonNull BidirectionalStream stream, @NonNull UrlResponseInfo info, @NonNull ByteBuffer buffer, boolean endOfStream); /** * Invoked when trailers are received before closing the stream. Only invoked when server * sends trailers, which it may not. May be invoked while there is read data remaining in * local buffer. * * Default implementation takes no action. * * @param stream the stream on which response trailers were received. This is not * guaranteed to be the same object as the one received by other callbacks, nor is * it guaranteed to be the one returned by {@link BidirectionalStream.Builder#build}. * However, method calls on this object will have the same effects as calls * on the original {@link BidirectionalStream}. * @param info the response information * @param trailers the trailers received */ void onResponseTrailersReceived(@NonNull BidirectionalStream stream, @NonNull UrlResponseInfo info, @NonNull HeaderBlock trailers); /** * Invoked when there is no data to be read or written and the stream is closed successfully * remotely and locally. Once invoked, no further {@link BidirectionalStream.Callback} * methods will be invoked. * * @param stream the stream which is closed successfully. This is not guaranteed to * be the same object as the one received by other callbacks, nor is it guaranteed * to be the one returned by {@link BidirectionalStream.Builder#build}. * However, method calls on this object will have the same effects as calls on the * original {@link BidirectionalStream}. * @param info the response information */ void onSucceeded(@NonNull BidirectionalStream stream, @NonNull UrlResponseInfo info); /** * Invoked if the stream failed for any reason after {@link BidirectionalStream#start}. * HTTP/2 error codes are * mapped to {@link NetworkException#getErrorCode} codes. Once invoked, * no further {@link BidirectionalStream.Callback} methods will be invoked. * * @param stream the stream which has failed. This is not guaranteed to * be the same object as the one received by other callbacks, nor is it guaranteed * to be the one returned by {@link BidirectionalStream.Builder#build}. * However, method calls on this object will have the same effects as calls on the * original {@link BidirectionalStream}. * @param info the response information. May be {@code null} if no response was received. * @param error information about the failure */ void onFailed(@NonNull BidirectionalStream stream, @Nullable UrlResponseInfo info, @NonNull HttpException error); /** * Invoked if the stream was canceled via {@link BidirectionalStream#cancel}. Once invoked, * no further {@link BidirectionalStream.Callback} methods will be invoked. Default * implementation takes no action. * * @param stream the stream that was canceled. This is not guaranteed to * be the same object as the one received by other callbacks, nor is it guaranteed * to be the one returned by {@link BidirectionalStream.Builder#build}. * However, method calls on this object will have the same effects as calls on the * original {@link BidirectionalStream}. * @param info the response information. May be {@code null} if no response was received. */ void onCanceled(@NonNull BidirectionalStream stream, @Nullable UrlResponseInfo info); } /** * See {@link BidirectionalStream.Builder#setHttpMethod(String)}. */ @NonNull public abstract String getHttpMethod(); /** * See {@link BidirectionalStream.Builder#setTrafficStatsTag(int)} */ public abstract boolean hasTrafficStatsTag(); /** * See {@link BidirectionalStream.Builder#setTrafficStatsTag(int)} */ public abstract int getTrafficStatsTag(); /** * See {@link BidirectionalStream.Builder#setTrafficStatsUid(int)} */ public abstract boolean hasTrafficStatsUid(); /** * See {@link BidirectionalStream.Builder#setTrafficStatsUid(int)} */ public abstract int getTrafficStatsUid(); /** * See {@link Builder#addHeader(String, String)} */ @NonNull public abstract HeaderBlock getHeaders(); /** * See {@link Builder#setPriority(int)} */ public abstract @BidirectionalStreamPriority int getPriority(); /** * See {@link Builder#setDelayRequestHeadersUntilFirstFlushEnabled(boolean)} */ public abstract boolean isDelayRequestHeadersUntilFirstFlushEnabled(); /** * Starts the stream, all callbacks go to the {@code callback} argument passed to {@link * BidirectionalStream.Builder}'s constructor. Should only be called once. */ public abstract void start(); /** * Reads data from the stream into the provided buffer. Can only be called at most once in * response to each invocation of the {@link Callback#onStreamReady onStreamReady()}/ {@link * Callback#onResponseHeadersReceived onResponseHeadersReceived()} and {@link * Callback#onReadCompleted onReadCompleted()} methods of the {@link Callback}. Each call will * result in an invocation of one of the {@link Callback Callback}'s {@link * Callback#onReadCompleted onReadCompleted()} method if data is read, or its {@link * Callback#onFailed onFailed()} method if there's an error. * * An attempt to read data into {@code buffer} starting at {@code buffer.position()} is begun. * At most {@code buffer.remaining()} bytes are read. {@code buffer.position()} is updated upon * invocation of {@link Callback#onReadCompleted onReadCompleted()} to indicate how much data * was read. * * @param buffer the {@link ByteBuffer} to read data into. Must be a direct ByteBuffer. The * embedder must not read or modify buffer's position, limit, or data between its position and * limit until {@link Callback#onReadCompleted onReadCompleted()}, {@link Callback#onCanceled * onCanceled()}, or {@link Callback#onFailed onFailed()} are invoked. */ public abstract void read(@NonNull ByteBuffer buffer); /** * Attempts to write data from the provided buffer into the stream. If auto flush is disabled, * data will be sent only after {@link #flush flush()} is called. Each call will result in an * invocation of one of the {@link Callback Callback}'s {@link Callback#onWriteCompleted * onWriteCompleted()} method if data is sent, or its {@link Callback#onFailed onFailed()} * method if there's an error. * * An attempt to write data from {@code buffer} starting at {@code buffer.position()} is begun. * {@code buffer.remaining()} bytes will be written. {@link Callback#onWriteCompleted * onWriteCompleted()} will be invoked only when the full ByteBuffer is written. * * @param buffer the {@link ByteBuffer} to write data from. Must be a direct ByteBuffer. The * embedder must not read or modify buffer's position, limit, or data between its position and * limit until {@link Callback#onWriteCompleted onWriteCompleted()}, {@link Callback#onCanceled * onCanceled()}, or {@link Callback#onFailed onFailed()} are invoked. Can be empty when {@code * endOfStream} is {@code true}. * @param endOfStream if {@code true}, then {@code buffer} is the last buffer to be written, and * once written, stream is closed from the client side, resulting in half-closed stream or a * fully closed stream if the remote side has already closed. */ public abstract void write(@NonNull ByteBuffer buffer, boolean endOfStream); /** * Flushes pending writes. This method should not be invoked before {@link * Callback#onStreamReady onStreamReady()}. For previously delayed {@link #write write()}s, a * corresponding {@link Callback#onWriteCompleted onWriteCompleted()} will be invoked when the * buffer is sent. */ public abstract void flush(); /** * Cancels the stream. Can be called at any time after {@link #start}. {@link * Callback#onCanceled onCanceled()} will be invoked when cancelation is complete and no further * callback methods will be invoked. If the stream has completed or has not started, calling * {@code cancel()} has no effect and {@code onCanceled()} will not be invoked. If the {@link * Executor} passed in during * {@code BidirectionalStream} construction runs tasks on a single thread, and {@code cancel()} * is called on that thread, no listener methods (besides {@code onCanceled()}) will be invoked * after * {@code cancel()} is called. Otherwise, at most one callback method may be invoked after * {@code cancel()} has completed. */ public abstract void cancel(); /** * Returns {@code true} if the stream was successfully started and is now done (succeeded, * canceled, or failed). * * @return {@code true} if the stream was successfully started and is now done (completed, * canceled, or failed), otherwise returns {@code false} to indicate stream is not yet started * or is in progress. */ public abstract boolean isDone(); }