1 // Copyright 2022 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package android.net.http; 6 7 import android.annotation.SuppressLint; 8 9 import androidx.annotation.NonNull; 10 import androidx.annotation.Nullable; 11 12 import java.time.Duration; 13 import java.util.Collections; 14 import java.util.LinkedHashSet; 15 import java.util.Set; 16 17 /** 18 * Configuration options for QUIC. 19 * 20 * <p>The settings in this class are only relevant if QUIC is enabled. Use 21 * {@link HttpEngine.Builder#setEnableQuic(boolean)} to enable / disable QUIC for 22 * the HTTP engine. 23 */ 24 // SuppressLint to be consistent with other cronet code 25 @SuppressLint("UserHandleName") 26 public class QuicOptions { 27 private final Set<String> mQuicHostAllowlist; 28 private final Set<String> mEnabledQuicVersions; 29 30 private final Set<String> mConnectionOptions; 31 private final Set<String> mClientConnectionOptions; 32 @Nullable 33 private final Integer mInMemoryServerConfigsCacheSize; 34 @Nullable 35 private final String mHandshakeUserAgent; 36 @Nullable 37 private final Boolean mRetryWithoutAltSvcOnQuicErrors; 38 @Nullable 39 private final Boolean mEnableTlsZeroRtt; 40 41 @Nullable 42 private final Duration mPreCryptoHandshakeIdleTimeout; 43 @Nullable 44 private final Duration mCryptoHandshakeTimeout; 45 46 @Nullable 47 private final Duration mIdleConnectionTimeout; 48 @Nullable 49 private final Duration mRetransmittableOnWireTimeout; 50 51 @Nullable 52 private final Boolean mCloseSessionsOnIpChange; 53 @Nullable 54 private final Boolean mGoawaySessionsOnIpChange; 55 56 @Nullable 57 private final Duration mInitialBrokenServicePeriod; 58 @Nullable 59 private final Boolean mIncreaseBrokenServicePeriodExponentially; 60 @Nullable 61 private final Boolean mDelayJobsWithAvailableSpdySession; 62 63 private final Set<String> mExtraQuicheFlags; 64 QuicOptions(Builder builder)65 QuicOptions(Builder builder) { 66 this.mQuicHostAllowlist = 67 Collections.unmodifiableSet(new LinkedHashSet<>(builder.mQuicHostAllowlist)); 68 this.mEnabledQuicVersions = 69 Collections.unmodifiableSet(new LinkedHashSet<>(builder.mEnabledQuicVersions)); 70 this.mConnectionOptions = 71 Collections.unmodifiableSet(new LinkedHashSet<>(builder.mConnectionOptions)); 72 this.mClientConnectionOptions = 73 Collections.unmodifiableSet(new LinkedHashSet<>(builder.mClientConnectionOptions)); 74 this.mInMemoryServerConfigsCacheSize = builder.mInMemoryServerConfigsCacheSize; 75 this.mHandshakeUserAgent = builder.mHandshakeUserAgent; 76 this.mRetryWithoutAltSvcOnQuicErrors = builder.mRetryWithoutAltSvcOnQuicErrors; 77 this.mEnableTlsZeroRtt = builder.mEnableTlsZeroRtt; 78 this.mPreCryptoHandshakeIdleTimeout = builder.mPreCryptoHandshakeIdleTimeout; 79 this.mCryptoHandshakeTimeout = builder.mCryptoHandshakeTimeout; 80 this.mIdleConnectionTimeout = builder.mIdleConnectionTimeout; 81 this.mRetransmittableOnWireTimeout = builder.mRetransmittableOnWireTimeout; 82 this.mCloseSessionsOnIpChange = builder.mCloseSessionsOnIpChange; 83 this.mGoawaySessionsOnIpChange = builder.mGoawaySessionsOnIpChange; 84 this.mInitialBrokenServicePeriod = builder.mInitialBrokenServicePeriod; 85 this.mIncreaseBrokenServicePeriodExponentially = 86 builder.mIncreaseBrokenServicePeriodExponentially; 87 this.mDelayJobsWithAvailableSpdySession = builder.mDelayJobsWithAvailableSpdySession; 88 this.mExtraQuicheFlags = 89 Collections.unmodifiableSet(new LinkedHashSet<>(builder.mExtraQuicheFlags)); 90 } 91 92 /** 93 * See {@link Builder#addAllowedQuicHost} 94 */ 95 @NonNull getAllowedQuicHosts()96 public Set<String> getAllowedQuicHosts() { 97 return mQuicHostAllowlist; 98 } 99 100 101 /** 102 * See {@link Builder#setInMemoryServerConfigsCacheSize} 103 */ hasInMemoryServerConfigsCacheSize()104 public boolean hasInMemoryServerConfigsCacheSize() { 105 return mInMemoryServerConfigsCacheSize != null; 106 } 107 108 /** 109 * See {@link Builder#setInMemoryServerConfigsCacheSize} 110 */ getInMemoryServerConfigsCacheSize()111 public int getInMemoryServerConfigsCacheSize() { 112 if (!hasInMemoryServerConfigsCacheSize()) { 113 throw new IllegalStateException("InMemoryServerConfigsCacheSize is not set"); 114 } 115 return mInMemoryServerConfigsCacheSize; 116 } 117 118 /** 119 * See {@link Builder#setHandshakeUserAgent} 120 */ 121 @Nullable getHandshakeUserAgent()122 public String getHandshakeUserAgent() { 123 return mHandshakeUserAgent; 124 } 125 126 /** 127 * See {@link Builder#setIdleConnectionTimeout} 128 */ 129 @Nullable getIdleConnectionTimeout()130 public Duration getIdleConnectionTimeout() { 131 return mIdleConnectionTimeout; 132 } 133 134 /** 135 * Create a new {@code QuicOptions} builder. 136 * 137 * {@hide} 138 */ builder()139 public static Builder builder() { 140 return new Builder(); 141 } 142 143 /** 144 * Builder for {@link QuicOptions}. 145 */ 146 public static final class Builder { 147 private final Set<String> mQuicHostAllowlist = new LinkedHashSet<>(); 148 private final Set<String> mEnabledQuicVersions = new LinkedHashSet<>(); 149 private final Set<String> mConnectionOptions = new LinkedHashSet<>(); 150 private final Set<String> mClientConnectionOptions = new LinkedHashSet<>(); 151 @Nullable 152 private Integer mInMemoryServerConfigsCacheSize; 153 @Nullable 154 private String mHandshakeUserAgent; 155 @Nullable 156 private Boolean mRetryWithoutAltSvcOnQuicErrors; 157 @Nullable 158 private Boolean mEnableTlsZeroRtt; 159 @Nullable 160 private Duration mPreCryptoHandshakeIdleTimeout; 161 @Nullable 162 private Duration mCryptoHandshakeTimeout; 163 @Nullable 164 private Duration mIdleConnectionTimeout; 165 @Nullable 166 private Duration mRetransmittableOnWireTimeout; 167 @Nullable 168 private Boolean mCloseSessionsOnIpChange; 169 @Nullable 170 private Boolean mGoawaySessionsOnIpChange; 171 @Nullable 172 private Duration mInitialBrokenServicePeriod; 173 @Nullable 174 private Boolean mIncreaseBrokenServicePeriodExponentially; 175 @Nullable 176 private Boolean mDelayJobsWithAvailableSpdySession; 177 private final Set<String> mExtraQuicheFlags = new LinkedHashSet<>(); 178 Builder()179 public Builder() {} 180 181 /** 182 * Adds a host to the QUIC allowlist. 183 * 184 * <p>If no hosts are specified, the per-host allowlist functionality is disabled. 185 * Otherwise, the HTTP stack will only use QUIC when talking to hosts on the allowlist. 186 * 187 * @return the builder for chaining 188 */ 189 @NonNull addAllowedQuicHost(@onNull String quicHost)190 public Builder addAllowedQuicHost(@NonNull String quicHost) { 191 mQuicHostAllowlist.add(quicHost); 192 return this; 193 } 194 195 /** 196 * Sets how many server configurations (metadata like list of alt svc, whether QUIC is 197 * supported, etc.) should be held in memory. 198 * 199 * <p>If the storage path is set ({@link HttpEngine.Builder#setStoragePath(String)}, 200 * the HTTP stack will also persist the server configurations on disk. 201 * 202 * @return the builder for chaining 203 */ 204 @NonNull setInMemoryServerConfigsCacheSize(int inMemoryServerConfigsCacheSize)205 public Builder setInMemoryServerConfigsCacheSize(int inMemoryServerConfigsCacheSize) { 206 this.mInMemoryServerConfigsCacheSize = inMemoryServerConfigsCacheSize; 207 return this; 208 } 209 210 /** 211 * Sets the user agent to be used outside of HTTP requests (for example for QUIC 212 * handshakes). 213 * 214 * <p>To set the default user agent for HTTP requests, use 215 * {@link HttpEngine.Builder#setUserAgent(String)} instead. 216 * 217 * @return the builder for chaining 218 */ 219 @NonNull setHandshakeUserAgent(@onNull String handshakeUserAgent)220 public Builder setHandshakeUserAgent(@NonNull String handshakeUserAgent) { 221 this.mHandshakeUserAgent = handshakeUserAgent; 222 return this; 223 } 224 225 /** 226 * Sets the maximum idle time for a connection. The actual value for the idle timeout is 227 * the minimum of this value and the server's and is negotiated during the handshake. Thus, 228 * it only applies after the handshake has completed. If no activity is detected 229 * on the connection for the set duration, the connection is closed. 230 * 231 * <p>See <a href="https://www.rfc-editor.org/rfc/rfc9114.html#name-idle-connections">RFC 232 * 9114, section 5.1 </a> for more details. 233 * 234 * @return the builder for chaining 235 */ 236 @NonNull setIdleConnectionTimeout(@onNull Duration idleConnectionTimeout)237 public Builder setIdleConnectionTimeout(@NonNull Duration idleConnectionTimeout) { 238 this.mIdleConnectionTimeout = idleConnectionTimeout; 239 return this; 240 } 241 242 /** 243 * Creates and returns the final {@link QuicOptions} instance, based on the values 244 * in this builder. 245 */ 246 @NonNull build()247 public QuicOptions build() { 248 return new QuicOptions(this); 249 } 250 } 251 252 /** 253 * An annotation for APIs which are not considered stable yet. 254 * 255 * <p>Applications using experimental APIs must acknowledge that they're aware of using APIs 256 * that are not considered stable. The APIs might change functionality, break or cease to exist 257 * without notice. 258 * 259 * <p>It's highly recommended to reach out to Cronet maintainers ({@code net-dev@chromium.org}) 260 * before using one of the APIs annotated as experimental outside of debugging 261 * and proof-of-concept code. Be ready to help to help polishing the API, or for a "sorry, 262 * really not production ready yet". 263 * 264 * <p>If you still want to use an experimental API in production, you're doing so at your 265 * own risk. You have been warned. 266 * 267 * {@hide} 268 */ 269 public @interface Experimental {} 270 } 271