OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.net; | 5 package org.chromium.net; |
6 | 6 |
7 import android.content.Context; | 7 import android.content.Context; |
8 import android.support.annotation.IntDef; | 8 import android.support.annotation.IntDef; |
9 import android.util.Base64; | |
10 import android.util.Log; | 9 import android.util.Log; |
11 | 10 |
12 import org.json.JSONArray; | |
13 import org.json.JSONException; | |
14 import org.json.JSONObject; | |
15 | |
16 import java.io.File; | 11 import java.io.File; |
17 import java.lang.annotation.Retention; | 12 import java.lang.annotation.Retention; |
18 import java.lang.annotation.RetentionPolicy; | 13 import java.lang.annotation.RetentionPolicy; |
19 import java.lang.reflect.Constructor; | 14 import java.lang.reflect.Constructor; |
20 import java.net.IDN; | 15 import java.net.IDN; |
21 import java.net.Proxy; | 16 import java.net.Proxy; |
22 import java.net.URL; | 17 import java.net.URL; |
23 import java.net.URLConnection; | 18 import java.net.URLConnection; |
24 import java.net.URLStreamHandlerFactory; | 19 import java.net.URLStreamHandlerFactory; |
25 import java.util.Date; | 20 import java.util.Date; |
26 import java.util.HashSet; | 21 import java.util.HashSet; |
| 22 import java.util.LinkedList; |
27 import java.util.List; | 23 import java.util.List; |
28 import java.util.Map; | 24 import java.util.Map; |
29 import java.util.Set; | 25 import java.util.Set; |
30 import java.util.concurrent.Executor; | 26 import java.util.concurrent.Executor; |
31 import java.util.regex.Pattern; | 27 import java.util.regex.Pattern; |
32 | 28 |
33 /** | 29 /** |
34 * An engine to process {@link UrlRequest}s, which uses the best HTTP stack | 30 * An engine to process {@link UrlRequest}s, which uses the best HTTP stack |
35 * available on the current platform. | 31 * available on the current platform. |
36 */ | 32 */ |
37 public abstract class CronetEngine { | 33 public abstract class CronetEngine { |
38 /** | 34 /** |
39 * A builder for {@link CronetEngine}s, which allows runtime configuration o
f | 35 * A builder for {@link CronetEngine}s, which allows runtime configuration o
f |
40 * {@code CronetEngine}. Configuration options are set on the builder and | 36 * {@code CronetEngine}. Configuration options are set on the builder and |
41 * then {@link #build} is called to create the {@code CronetEngine}. | 37 * then {@link #build} is called to create the {@code CronetEngine}. |
42 */ | 38 */ |
43 public static class Builder { | 39 public static class Builder { |
| 40 // A hint that a host supports QUIC. |
| 41 static class QuicHint { |
| 42 // The host. |
| 43 final String mHost; |
| 44 // Port of the server that supports QUIC. |
| 45 final int mPort; |
| 46 // Alternate protocol port. |
| 47 final int mAlternatePort; |
| 48 |
| 49 QuicHint(String host, int port, int alternatePort) { |
| 50 mHost = host; |
| 51 mPort = port; |
| 52 mAlternatePort = alternatePort; |
| 53 } |
| 54 } |
| 55 |
| 56 // A public key pin. |
| 57 static class Pkp { |
| 58 // Host to pin for. |
| 59 final String mHost; |
| 60 // Array of SHA-256 hashes of keys. |
| 61 final byte[][] mHashes; |
| 62 // Should pin apply to subdomains? |
| 63 final boolean mIncludeSubdomains; |
| 64 // When the pin expires. |
| 65 final Date mExpirationDate; |
| 66 |
| 67 Pkp(String host, byte[][] hashes, boolean includeSubdomains, Date ex
pirationDate) { |
| 68 mHost = host; |
| 69 mHashes = hashes; |
| 70 mIncludeSubdomains = includeSubdomains; |
| 71 mExpirationDate = expirationDate; |
| 72 } |
| 73 } |
| 74 |
44 private static final Pattern INVALID_PKP_HOST_NAME = Pattern.compile("^[
0-9\\.]*$"); | 75 private static final Pattern INVALID_PKP_HOST_NAME = Pattern.compile("^[
0-9\\.]*$"); |
45 | 76 |
46 private final JSONObject mConfig; | 77 // Private fields are simply storage of configuration for the resulting
CronetEngine. |
| 78 // See setters below for verbose descriptions. |
47 private final Context mContext; | 79 private final Context mContext; |
| 80 private final List<QuicHint> mQuicHints = new LinkedList<QuicHint>(); |
| 81 private final List<Pkp> mPkps = new LinkedList<Pkp>(); |
| 82 private String mUserAgent; |
| 83 private String mStoragePath; |
| 84 private boolean mLegacyModeEnabled; |
| 85 private String mLibraryName; |
| 86 private boolean mQuicEnabled; |
| 87 private boolean mHttp2Enabled; |
| 88 private boolean mSdchEnabled; |
| 89 private String mDataReductionProxyKey; |
| 90 private String mDataReductionProxyPrimaryProxy; |
| 91 private String mDataReductionProxyFallbackProxy; |
| 92 private String mDataReductionProxySecureProxyCheckUrl; |
| 93 private boolean mDisableCache; |
| 94 private int mHttpCacheMode; |
| 95 private long mHttpCacheMaxSize; |
| 96 private String mExperimentalOptions; |
| 97 private long mMockCertVerifier; |
48 | 98 |
49 /** | 99 /** |
50 * Default config enables SPDY, disables QUIC, SDCH and HTTP cache. | 100 * Default config enables SPDY, disables QUIC, SDCH and HTTP cache. |
51 * @param context Android {@link Context} for engine to use. | 101 * @param context Android {@link Context} for engine to use. |
52 */ | 102 */ |
53 public Builder(Context context) { | 103 public Builder(Context context) { |
54 mConfig = new JSONObject(); | |
55 mContext = context; | 104 mContext = context; |
| 105 setLibraryName("cronet"); |
56 enableLegacyMode(false); | 106 enableLegacyMode(false); |
57 enableQUIC(false); | 107 enableQUIC(false); |
58 enableHTTP2(true); | 108 enableHTTP2(true); |
59 enableSDCH(false); | 109 enableSDCH(false); |
60 enableHttpCache(HTTP_CACHE_DISABLED, 0); | 110 enableHttpCache(HTTP_CACHE_DISABLED, 0); |
61 } | 111 } |
62 | 112 |
63 /** | 113 /** |
64 * Constructs a User-Agent string including Cronet version, and | 114 * Constructs a User-Agent string including Cronet version, and |
65 * application name and version. | 115 * application name and version. |
66 * | 116 * |
67 * @return User-Agent string. | 117 * @return User-Agent string. |
68 */ | 118 */ |
69 public String getDefaultUserAgent() { | 119 public String getDefaultUserAgent() { |
70 return UserAgent.from(mContext); | 120 return UserAgent.from(mContext); |
71 } | 121 } |
72 | 122 |
73 /** | 123 /** |
74 * Overrides the User-Agent header for all requests. | 124 * Overrides the User-Agent header for all requests. |
75 * @return the builder to facilitate chaining. | 125 * @return the builder to facilitate chaining. |
76 */ | 126 */ |
77 public Builder setUserAgent(String userAgent) { | 127 public Builder setUserAgent(String userAgent) { |
78 return putString(CronetEngineBuilderList.USER_AGENT, userAgent); | 128 mUserAgent = userAgent; |
| 129 return this; |
79 } | 130 } |
80 | 131 |
81 String getUserAgent() { | 132 String getUserAgent() { |
82 return mConfig.optString(CronetEngineBuilderList.USER_AGENT); | 133 return mUserAgent; |
83 } | 134 } |
84 | 135 |
85 /** | 136 /** |
86 * Sets directory for HTTP Cache and Cookie Storage. The directory must | 137 * Sets directory for HTTP Cache and Cookie Storage. The directory must |
87 * exist. | 138 * exist. |
88 * <p> | 139 * <p> |
89 * <b>NOTE:</b> Do not use the same storage directory with more than one | 140 * <b>NOTE:</b> Do not use the same storage directory with more than one |
90 * {@code CronetEngine} at a time. Access to the storage directory does | 141 * {@code CronetEngine} at a time. Access to the storage directory does |
91 * not support concurrent access by multiple {@code CronetEngine}s. | 142 * not support concurrent access by multiple {@code CronetEngine}s. |
92 * | 143 * |
93 * @param value path to existing directory. | 144 * @param value path to existing directory. |
94 * @return the builder to facilitate chaining. | 145 * @return the builder to facilitate chaining. |
95 */ | 146 */ |
96 public Builder setStoragePath(String value) { | 147 public Builder setStoragePath(String value) { |
97 if (!new File(value).isDirectory()) { | 148 if (!new File(value).isDirectory()) { |
98 throw new IllegalArgumentException( | 149 throw new IllegalArgumentException( |
99 "Storage path must be set to existing directory"); | 150 "Storage path must be set to existing directory"); |
100 } | 151 } |
101 | 152 mStoragePath = value; |
102 return putString(CronetEngineBuilderList.STORAGE_PATH, value); | 153 return this; |
103 } | 154 } |
104 | 155 |
105 String storagePath() { | 156 String storagePath() { |
106 return mConfig.optString(CronetEngineBuilderList.STORAGE_PATH); | 157 return mStoragePath; |
107 } | 158 } |
108 | 159 |
109 /** | 160 /** |
110 * Sets whether falling back to implementation based on system's | 161 * Sets whether falling back to implementation based on system's |
111 * {@link java.net.HttpURLConnection} implementation is enabled. | 162 * {@link java.net.HttpURLConnection} implementation is enabled. |
112 * Defaults to disabled. | 163 * Defaults to disabled. |
113 * @return the builder to facilitate chaining. | 164 * @return the builder to facilitate chaining. |
114 * @deprecated Not supported by the new API. | 165 * @deprecated Not supported by the new API. |
115 */ | 166 */ |
116 @Deprecated | 167 @Deprecated |
117 public Builder enableLegacyMode(boolean value) { | 168 public Builder enableLegacyMode(boolean value) { |
118 return putBoolean(CronetEngineBuilderList.ENABLE_LEGACY_MODE, value)
; | 169 mLegacyModeEnabled = value; |
| 170 return this; |
119 } | 171 } |
120 | 172 |
121 boolean legacyMode() { | 173 boolean legacyMode() { |
122 return mConfig.optBoolean(CronetEngineBuilderList.ENABLE_LEGACY_MODE
); | 174 return mLegacyModeEnabled; |
123 } | 175 } |
124 | 176 |
125 /** | 177 /** |
126 * Overrides the name of the native library backing Cronet. | 178 * Overrides the name of the native library backing Cronet. |
127 * @return the builder to facilitate chaining. | 179 * @return the builder to facilitate chaining. |
128 */ | 180 */ |
129 Builder setLibraryName(String libName) { | 181 Builder setLibraryName(String libName) { |
130 return putString(CronetEngineBuilderList.NATIVE_LIBRARY_NAME, libNam
e); | 182 mLibraryName = libName; |
| 183 return this; |
131 } | 184 } |
132 | 185 |
133 String libraryName() { | 186 String libraryName() { |
134 return mConfig.optString(CronetEngineBuilderList.NATIVE_LIBRARY_NAME
, "cronet"); | 187 return mLibraryName; |
135 } | 188 } |
136 | 189 |
137 /** | 190 /** |
138 * Sets whether <a href="https://www.chromium.org/quic">QUIC</a> protoco
l | 191 * Sets whether <a href="https://www.chromium.org/quic">QUIC</a> protoco
l |
139 * is enabled. Defaults to disabled. | 192 * is enabled. Defaults to disabled. |
140 * @return the builder to facilitate chaining. | 193 * @return the builder to facilitate chaining. |
141 */ | 194 */ |
142 public Builder enableQUIC(boolean value) { | 195 public Builder enableQUIC(boolean value) { |
143 return putBoolean(CronetEngineBuilderList.ENABLE_QUIC, value); | 196 mQuicEnabled = value; |
| 197 return this; |
| 198 } |
| 199 |
| 200 boolean quicEnabled() { |
| 201 return mQuicEnabled; |
144 } | 202 } |
145 | 203 |
146 /** | 204 /** |
147 * Sets whether <a href="https://tools.ietf.org/html/rfc7540">HTTP/2</a> | 205 * Sets whether <a href="https://tools.ietf.org/html/rfc7540">HTTP/2</a> |
148 * protocol is enabled. Defaults to enabled. | 206 * protocol is enabled. Defaults to enabled. |
149 * @return the builder to facilitate chaining. | 207 * @return the builder to facilitate chaining. |
150 */ | 208 */ |
151 public Builder enableHTTP2(boolean value) { | 209 public Builder enableHTTP2(boolean value) { |
152 return putBoolean(CronetEngineBuilderList.ENABLE_SPDY, value); | 210 mHttp2Enabled = value; |
| 211 return this; |
| 212 } |
| 213 |
| 214 boolean http2Enabled() { |
| 215 return mHttp2Enabled; |
153 } | 216 } |
154 | 217 |
155 /** | 218 /** |
156 * Sets whether | 219 * Sets whether |
157 * <a | 220 * <a |
158 * href="https://lists.w3.org/Archives/Public/ietf-http-wg/2008JulSep/at
t-0441/Shared_Dictionary_Compression_over_HTTP.pdf"> | 221 * href="https://lists.w3.org/Archives/Public/ietf-http-wg/2008JulSep/at
t-0441/Shared_Dictionary_Compression_over_HTTP.pdf"> |
159 * SDCH</a> compression is enabled. Defaults to disabled. | 222 * SDCH</a> compression is enabled. Defaults to disabled. |
160 * @return the builder to facilitate chaining. | 223 * @return the builder to facilitate chaining. |
161 */ | 224 */ |
162 public Builder enableSDCH(boolean value) { | 225 public Builder enableSDCH(boolean value) { |
163 return putBoolean(CronetEngineBuilderList.ENABLE_SDCH, value); | 226 mSdchEnabled = value; |
| 227 return this; |
| 228 } |
| 229 |
| 230 boolean sdchEnabled() { |
| 231 return mSdchEnabled; |
164 } | 232 } |
165 | 233 |
166 /** | 234 /** |
167 * Enables | 235 * Enables |
168 * <a href="https://developer.chrome.com/multidevice/data-compression">D
ata | 236 * <a href="https://developer.chrome.com/multidevice/data-compression">D
ata |
169 * Reduction Proxy</a>. Defaults to disabled. | 237 * Reduction Proxy</a>. Defaults to disabled. |
170 * @param key key to use when authenticating with the proxy. | 238 * @param key key to use when authenticating with the proxy. |
171 * @return the builder to facilitate chaining. | 239 * @return the builder to facilitate chaining. |
172 */ | 240 */ |
173 public Builder enableDataReductionProxy(String key) { | 241 public Builder enableDataReductionProxy(String key) { |
174 return (putString(CronetEngineBuilderList.DATA_REDUCTION_PROXY_KEY,
key)); | 242 mDataReductionProxyKey = key; |
| 243 return this; |
| 244 } |
| 245 |
| 246 String dataReductionProxyKey() { |
| 247 return mDataReductionProxyKey; |
175 } | 248 } |
176 | 249 |
177 /** | 250 /** |
178 * Overrides | 251 * Overrides |
179 * <a href="https://developer.chrome.com/multidevice/data-compression"> | 252 * <a href="https://developer.chrome.com/multidevice/data-compression"> |
180 * Data Reduction Proxy</a> configuration parameters with a primary | 253 * Data Reduction Proxy</a> configuration parameters with a primary |
181 * proxy name, fallback proxy name, and a secure proxy check URL. Proxie
s | 254 * proxy name, fallback proxy name, and a secure proxy check URL. Proxie
s |
182 * are specified as [scheme://]host[:port]. Used for testing. | 255 * are specified as [scheme://]host[:port]. Used for testing. |
183 * @param primaryProxy the primary data reduction proxy to use. | 256 * @param primaryProxy the primary data reduction proxy to use. |
184 * @param fallbackProxy a fallback data reduction proxy to use. | 257 * @param fallbackProxy a fallback data reduction proxy to use. |
185 * @param secureProxyCheckUrl a URL to fetch to determine if using a sec
ure | 258 * @param secureProxyCheckUrl a URL to fetch to determine if using a sec
ure |
186 * proxy is allowed. | 259 * proxy is allowed. |
187 * @return the builder to facilitate chaining. | 260 * @return the builder to facilitate chaining. |
188 * @hide | 261 * @hide |
189 * @deprecated Marked as deprecated because @hide doesn't properly hide
but | 262 * @deprecated Marked as deprecated because @hide doesn't properly hide
but |
190 * javadocs are built with nodeprecated="yes". | 263 * javadocs are built with nodeprecated="yes". |
191 */ | 264 */ |
192 @SuppressWarnings("DepAnn") | 265 @SuppressWarnings("DepAnn") |
193 public Builder setDataReductionProxyOptions( | 266 public Builder setDataReductionProxyOptions( |
194 String primaryProxy, String fallbackProxy, String secureProxyChe
ckUrl) { | 267 String primaryProxy, String fallbackProxy, String secureProxyChe
ckUrl) { |
195 if (primaryProxy.isEmpty() || fallbackProxy.isEmpty() | 268 if (primaryProxy.isEmpty() || fallbackProxy.isEmpty() |
196 || secureProxyCheckUrl.isEmpty()) { | 269 || secureProxyCheckUrl.isEmpty()) { |
197 throw new IllegalArgumentException( | 270 throw new IllegalArgumentException( |
198 "Primary and fallback proxies and check url must be set"
); | 271 "Primary and fallback proxies and check url must be set"
); |
199 } | 272 } |
200 putString(CronetEngineBuilderList.DATA_REDUCTION_PRIMARY_PROXY, prim
aryProxy); | 273 mDataReductionProxyPrimaryProxy = primaryProxy; |
201 putString(CronetEngineBuilderList.DATA_REDUCTION_FALLBACK_PROXY, fal
lbackProxy); | 274 mDataReductionProxyFallbackProxy = fallbackProxy; |
202 putString(CronetEngineBuilderList.DATA_REDUCTION_SECURE_PROXY_CHECK_
URL, | 275 mDataReductionProxySecureProxyCheckUrl = secureProxyCheckUrl; |
203 secureProxyCheckUrl); | |
204 return this; | 276 return this; |
205 } | 277 } |
206 | 278 |
| 279 String dataReductionProxyPrimaryProxy() { |
| 280 return mDataReductionProxyPrimaryProxy; |
| 281 } |
| 282 |
| 283 String dataReductionProxyFallbackProxy() { |
| 284 return mDataReductionProxyFallbackProxy; |
| 285 } |
| 286 |
| 287 String dataReductionProxySecureProxyCheckUrl() { |
| 288 return mDataReductionProxySecureProxyCheckUrl; |
| 289 } |
| 290 |
207 /** @deprecated not really deprecated but hidden. */ | 291 /** @deprecated not really deprecated but hidden. */ |
208 @IntDef({ | 292 @IntDef({ |
209 HTTP_CACHE_DISABLED, HTTP_CACHE_IN_MEMORY, HTTP_CACHE_DISK_NO_HT
TP, HTTP_CACHE_DISK, | 293 HTTP_CACHE_DISABLED, HTTP_CACHE_IN_MEMORY, HTTP_CACHE_DISK_NO_HT
TP, HTTP_CACHE_DISK, |
210 }) | 294 }) |
211 @Retention(RetentionPolicy.SOURCE) | 295 @Retention(RetentionPolicy.SOURCE) |
212 @SuppressWarnings("DepAnn") | 296 @SuppressWarnings("DepAnn") |
213 public @interface HttpCacheSetting {} | 297 public @interface HttpCacheSetting {} |
214 | 298 |
215 /** | 299 /** |
216 * Setting to disable HTTP cache. Some data may still be temporarily sto
red in memory. | 300 * Setting to disable HTTP cache. Some data may still be temporarily sto
red in memory. |
(...skipping 25 matching lines...) Expand all Loading... |
242 * Enables or disables caching of HTTP data and other information like Q
UIC | 326 * Enables or disables caching of HTTP data and other information like Q
UIC |
243 * server information. | 327 * server information. |
244 * @param cacheMode control location and type of cached data. Must be on
e of | 328 * @param cacheMode control location and type of cached data. Must be on
e of |
245 * {@link #HTTP_CACHE_DISABLED HTTP_CACHE_*}. | 329 * {@link #HTTP_CACHE_DISABLED HTTP_CACHE_*}. |
246 * @param maxSize maximum size in bytes used to cache data (advisory and
maybe | 330 * @param maxSize maximum size in bytes used to cache data (advisory and
maybe |
247 * exceeded at times). | 331 * exceeded at times). |
248 * @return the builder to facilitate chaining. | 332 * @return the builder to facilitate chaining. |
249 */ | 333 */ |
250 public Builder enableHttpCache(@HttpCacheSetting int cacheMode, long max
Size) { | 334 public Builder enableHttpCache(@HttpCacheSetting int cacheMode, long max
Size) { |
251 if (cacheMode == HTTP_CACHE_DISK || cacheMode == HTTP_CACHE_DISK_NO_
HTTP) { | 335 if (cacheMode == HTTP_CACHE_DISK || cacheMode == HTTP_CACHE_DISK_NO_
HTTP) { |
252 if (storagePath().isEmpty()) { | 336 if (storagePath() == null) { |
253 throw new IllegalArgumentException("Storage path must be set
"); | 337 throw new IllegalArgumentException("Storage path must be set
"); |
254 } | 338 } |
255 } else { | 339 } else { |
256 if (!storagePath().isEmpty()) { | 340 if (storagePath() != null) { |
257 throw new IllegalArgumentException("Storage path must be emp
ty"); | 341 throw new IllegalArgumentException("Storage path must not be
set"); |
258 } | 342 } |
259 } | 343 } |
260 putBoolean(CronetEngineBuilderList.LOAD_DISABLE_CACHE, | 344 mDisableCache = |
261 cacheMode == HTTP_CACHE_DISABLED || cacheMode == HTTP_CACHE_
DISK_NO_HTTP); | 345 (cacheMode == HTTP_CACHE_DISABLED || cacheMode == HTTP_CACHE
_DISK_NO_HTTP); |
262 putLong(CronetEngineBuilderList.HTTP_CACHE_MAX_SIZE, maxSize); | 346 mHttpCacheMaxSize = maxSize; |
263 | 347 |
264 switch (cacheMode) { | 348 switch (cacheMode) { |
265 case HTTP_CACHE_DISABLED: | 349 case HTTP_CACHE_DISABLED: |
266 return putString(CronetEngineBuilderList.HTTP_CACHE, | 350 mHttpCacheMode = HttpCacheType.DISABLED; |
267 CronetEngineBuilderList.HTTP_CACHE_DISABLED); | 351 break; |
268 case HTTP_CACHE_DISK_NO_HTTP: | 352 case HTTP_CACHE_DISK_NO_HTTP: |
269 case HTTP_CACHE_DISK: | 353 case HTTP_CACHE_DISK: |
270 return putString(CronetEngineBuilderList.HTTP_CACHE, | 354 mHttpCacheMode = HttpCacheType.DISK; |
271 CronetEngineBuilderList.HTTP_CACHE_DISK); | 355 break; |
272 | |
273 case HTTP_CACHE_IN_MEMORY: | 356 case HTTP_CACHE_IN_MEMORY: |
274 return putString(CronetEngineBuilderList.HTTP_CACHE, | 357 mHttpCacheMode = HttpCacheType.MEMORY; |
275 CronetEngineBuilderList.HTTP_CACHE_MEMORY); | 358 break; |
| 359 default: |
| 360 throw new IllegalArgumentException("Unknown cache mode"); |
276 } | 361 } |
277 return this; | 362 return this; |
278 } | 363 } |
279 | 364 |
| 365 boolean cacheDisabled() { |
| 366 return mDisableCache; |
| 367 } |
| 368 |
| 369 long httpCacheMaxSize() { |
| 370 return mHttpCacheMaxSize; |
| 371 } |
| 372 |
| 373 int httpCacheMode() { |
| 374 return mHttpCacheMode; |
| 375 } |
| 376 |
280 /** | 377 /** |
281 * Adds hint that {@code host} supports QUIC. | 378 * Adds hint that {@code host} supports QUIC. |
282 * Note that {@link #enableHttpCache enableHttpCache} | 379 * Note that {@link #enableHttpCache enableHttpCache} |
283 * ({@link #HTTP_CACHE_DISK}) is needed to take advantage of 0-RTT | 380 * ({@link #HTTP_CACHE_DISK}) is needed to take advantage of 0-RTT |
284 * connection establishment between sessions. | 381 * connection establishment between sessions. |
285 * | 382 * |
286 * @param host hostname of the server that supports QUIC. | 383 * @param host hostname of the server that supports QUIC. |
287 * @param port host of the server that supports QUIC. | 384 * @param port host of the server that supports QUIC. |
288 * @param alternatePort alternate port to use for QUIC. | 385 * @param alternatePort alternate port to use for QUIC. |
289 * @return the builder to facilitate chaining. | 386 * @return the builder to facilitate chaining. |
290 */ | 387 */ |
291 public Builder addQuicHint(String host, int port, int alternatePort) { | 388 public Builder addQuicHint(String host, int port, int alternatePort) { |
292 if (host.contains("/")) { | 389 if (host.contains("/")) { |
293 throw new IllegalArgumentException("Illegal QUIC Hint Host: " +
host); | 390 throw new IllegalArgumentException("Illegal QUIC Hint Host: " +
host); |
294 } | 391 } |
295 try { | 392 mQuicHints.add(new QuicHint(host, port, alternatePort)); |
296 JSONArray quicHints = mConfig.optJSONArray(CronetEngineBuilderLi
st.QUIC_HINTS); | 393 return this; |
297 if (quicHints == null) { | 394 } |
298 quicHints = new JSONArray(); | |
299 mConfig.put(CronetEngineBuilderList.QUIC_HINTS, quicHints); | |
300 } | |
301 | 395 |
302 JSONObject hint = new JSONObject(); | 396 List<QuicHint> quicHints() { |
303 hint.put(CronetEngineBuilderList.QUIC_HINT_HOST, host); | 397 return mQuicHints; |
304 hint.put(CronetEngineBuilderList.QUIC_HINT_PORT, port); | |
305 hint.put(CronetEngineBuilderList.QUIC_HINT_ALT_PORT, alternatePo
rt); | |
306 quicHints.put(hint); | |
307 } catch (JSONException e) { | |
308 // Intentionally do nothing. | |
309 } | |
310 return this; | |
311 } | 398 } |
312 | 399 |
313 /** | 400 /** |
314 * <p> | 401 * <p> |
315 * Pins a set of public keys for a given host. By pinning a set of publi
c keys, | 402 * Pins a set of public keys for a given host. By pinning a set of publi
c keys, |
316 * {@code pinsSha256}, communication with {@code hostName} is required t
o | 403 * {@code pinsSha256}, communication with {@code hostName} is required t
o |
317 * authenticate with a certificate with a public key from the set of pin
ned ones. | 404 * authenticate with a certificate with a public key from the set of pin
ned ones. |
318 * An app can pin the public key of the root certificate, any of the int
ermediate | 405 * An app can pin the public key of the root certificate, any of the int
ermediate |
319 * certificates or the end-entry certificate. Authentication will fail a
nd secure | 406 * certificates or the end-entry certificate. Authentication will fail a
nd secure |
320 * communication will not be established if none of the public keys is p
resent in the | 407 * communication will not be established if none of the public keys is p
resent in the |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
356 if (hostName == null) { | 443 if (hostName == null) { |
357 throw new NullPointerException("The hostname cannot be null"); | 444 throw new NullPointerException("The hostname cannot be null"); |
358 } | 445 } |
359 if (pinsSha256 == null) { | 446 if (pinsSha256 == null) { |
360 throw new NullPointerException("The set of SHA256 pins cannot be
null"); | 447 throw new NullPointerException("The set of SHA256 pins cannot be
null"); |
361 } | 448 } |
362 if (expirationDate == null) { | 449 if (expirationDate == null) { |
363 throw new NullPointerException("The pin expiration date cannot b
e null"); | 450 throw new NullPointerException("The pin expiration date cannot b
e null"); |
364 } | 451 } |
365 String idnHostName = validateHostNameForPinningAndConvert(hostName); | 452 String idnHostName = validateHostNameForPinningAndConvert(hostName); |
366 try { | 453 // Convert the pin to BASE64 encoding. The hash set will eliminate d
uplications. |
367 // Add PKP_LIST JSON array element if it is not present. | 454 Set<byte[]> hashes = new HashSet<>(pinsSha256.size()); |
368 JSONArray pkpList = mConfig.optJSONArray(CronetEngineBuilderList
.PKP_LIST); | 455 for (byte[] pinSha256 : pinsSha256) { |
369 if (pkpList == null) { | 456 if (pinSha256 == null || pinSha256.length != 32) { |
370 pkpList = new JSONArray(); | 457 throw new IllegalArgumentException("Public key pin is invali
d"); |
371 mConfig.put(CronetEngineBuilderList.PKP_LIST, pkpList); | |
372 } | 458 } |
373 | 459 hashes.add(pinSha256); |
374 // Convert the pin to BASE64 encoding. The hash set will elimina
te duplications. | |
375 Set<String> hashes = new HashSet<>(pinsSha256.size()); | |
376 for (byte[] pinSha256 : pinsSha256) { | |
377 hashes.add(convertSha256ToBase64WithPrefix(pinSha256)); | |
378 } | |
379 | |
380 // Add new element to PKP_LIST JSON array. | |
381 JSONObject pkp = new JSONObject(); | |
382 pkp.put(CronetEngineBuilderList.PKP_HOST, idnHostName); | |
383 pkp.put(CronetEngineBuilderList.PKP_PIN_HASHES, new JSONArray(ha
shes)); | |
384 pkp.put(CronetEngineBuilderList.PKP_INCLUDE_SUBDOMAINS, includeS
ubdomains); | |
385 // The expiration time is passed as a double, in seconds since J
anuary 1, 1970. | |
386 pkp.put(CronetEngineBuilderList.PKP_EXPIRATION_DATE, | |
387 (double) expirationDate.getTime() / 1000); | |
388 pkpList.put(pkp); | |
389 } catch (JSONException e) { | |
390 // This exception should never happen. | |
391 throw new RuntimeException( | |
392 "Failed to add pubic key pins with the given arguments",
e); | |
393 } | 460 } |
| 461 // Add new element to PKP list. |
| 462 mPkps.add(new Pkp(idnHostName, hashes.toArray(new byte[hashes.size()
][]), |
| 463 includeSubdomains, expirationDate)); |
394 return this; | 464 return this; |
395 } | 465 } |
396 | 466 |
397 /** | 467 /** |
398 * Converts a given SHA256 array of bytes to BASE64 encoded string and p
repends | 468 * Returns list of public key pins. |
399 * {@code sha256/} prefix to it. The format corresponds to the format th
at is expected by | |
400 * {@code net::HashValue} class. | |
401 * | |
402 * @param sha256 SHA256 bytes to convert to BASE64. | |
403 * @return the BASE64 encoded SHA256 with the prefix. | |
404 * @throws IllegalArgumentException if the provided pin is invalid. | |
405 */ | 469 */ |
406 private static String convertSha256ToBase64WithPrefix(byte[] sha256) { | 470 List<Pkp> publicKeyPins() { |
407 if (sha256 == null || sha256.length != 32) { | 471 return mPkps; |
408 throw new IllegalArgumentException("Public key pin is invalid"); | |
409 } | |
410 return "sha256/" + Base64.encodeToString(sha256, Base64.NO_WRAP); | |
411 } | 472 } |
412 | 473 |
413 /** | 474 /** |
414 * Checks whether a given string represents a valid host name for PKP an
d converts it | 475 * Checks whether a given string represents a valid host name for PKP an
d converts it |
415 * to ASCII Compatible Encoding representation according to RFC 1122, RF
C 1123 and | 476 * to ASCII Compatible Encoding representation according to RFC 1122, RF
C 1123 and |
416 * RFC 3490. This method is more restrictive than required by RFC 7469.
Thus, a host | 477 * RFC 3490. This method is more restrictive than required by RFC 7469.
Thus, a host |
417 * that contains digits and the dot character only is considered invalid
. | 478 * that contains digits and the dot character only is considered invalid
. |
418 * | 479 * |
419 * Note: Currently Cronet doesn't have native implementation of host nam
e validation that | 480 * Note: Currently Cronet doesn't have native implementation of host nam
e validation that |
420 * can be used. There is code that parses a provided URL but doesn
't ensure its | 481 * can be used. There is code that parses a provided URL but doesn
't ensure its |
(...skipping 18 matching lines...) Expand all Loading... |
439 } | 500 } |
440 } | 501 } |
441 | 502 |
442 /** | 503 /** |
443 * Sets experimental options to be used in Cronet. | 504 * Sets experimental options to be used in Cronet. |
444 * | 505 * |
445 * @param options JSON formatted experimental options. | 506 * @param options JSON formatted experimental options. |
446 * @return the builder to facilitate chaining. | 507 * @return the builder to facilitate chaining. |
447 */ | 508 */ |
448 public Builder setExperimentalOptions(String options) { | 509 public Builder setExperimentalOptions(String options) { |
449 return putString(CronetEngineBuilderList.EXPERIMENTAL_OPTIONS, optio
ns); | 510 mExperimentalOptions = options; |
| 511 return this; |
| 512 } |
| 513 |
| 514 String experimentalOptions() { |
| 515 return mExperimentalOptions; |
450 } | 516 } |
451 | 517 |
452 /** | 518 /** |
453 * Sets a native MockCertVerifier for testing. | 519 * Sets a native MockCertVerifier for testing. |
454 */ | 520 */ |
455 Builder setMockCertVerifierForTesting(long mockCertVerifier) { | 521 Builder setMockCertVerifierForTesting(long mockCertVerifier) { |
456 return putString( | 522 mMockCertVerifier = mockCertVerifier; |
457 CronetEngineBuilderList.MOCK_CERT_VERIFIER, String.valueOf(m
ockCertVerifier)); | 523 return this; |
| 524 } |
| 525 |
| 526 long mockCertVerifier() { |
| 527 return mMockCertVerifier; |
458 } | 528 } |
459 | 529 |
460 /** | 530 /** |
461 * Gets a JSON string representation of the builder. | |
462 */ | |
463 String toJSONString() { | |
464 return mConfig.toString(); | |
465 } | |
466 | |
467 /** | |
468 * Returns {@link Context} for builder. | 531 * Returns {@link Context} for builder. |
469 * | 532 * |
470 * @return {@link Context} for builder. | 533 * @return {@link Context} for builder. |
471 */ | 534 */ |
472 Context getContext() { | 535 Context getContext() { |
473 return mContext; | 536 return mContext; |
474 } | 537 } |
475 | 538 |
476 /** | 539 /** |
477 * Sets a boolean value in the config. Returns a reference to the same | |
478 * config object, so you can chain put calls together. | |
479 * @return the builder to facilitate chaining. | |
480 */ | |
481 private Builder putBoolean(String key, boolean value) { | |
482 try { | |
483 mConfig.put(key, value); | |
484 } catch (JSONException e) { | |
485 // Intentionally do nothing. | |
486 } | |
487 return this; | |
488 } | |
489 | |
490 /** | |
491 * Sets a long value in the config. Returns a reference to the same | |
492 * config object, so you can chain put calls together. | |
493 * @return the builder to facilitate chaining. | |
494 */ | |
495 private Builder putLong(String key, long value) { | |
496 try { | |
497 mConfig.put(key, value); | |
498 } catch (JSONException e) { | |
499 // Intentionally do nothing. | |
500 } | |
501 return this; | |
502 } | |
503 | |
504 /** | |
505 * Sets a string value in the config. Returns a reference to the same | |
506 * config object, so you can chain put calls together. | |
507 * @return the builder to facilitate chaining. | |
508 */ | |
509 private Builder putString(String key, String value) { | |
510 try { | |
511 mConfig.put(key, value); | |
512 } catch (JSONException e) { | |
513 // Intentionally do nothing. | |
514 } | |
515 return this; | |
516 } | |
517 | |
518 /** | |
519 * Build a {@link CronetEngine} using this builder's configuration. | 540 * Build a {@link CronetEngine} using this builder's configuration. |
520 */ | 541 */ |
521 public CronetEngine build() { | 542 public CronetEngine build() { |
522 CronetEngine engine = createContext(this); | 543 CronetEngine engine = createContext(this); |
523 // Clear MOCK_CERT_VERIFIER reference if there is any, since | 544 // Clear MOCK_CERT_VERIFIER reference if there is any, since |
524 // the ownership has been transferred to the engine. | 545 // the ownership has been transferred to the engine. |
525 mConfig.remove(CronetEngineBuilderList.MOCK_CERT_VERIFIER); | 546 mMockCertVerifier = 0; |
526 return engine; | 547 return engine; |
527 } | 548 } |
528 } | 549 } |
529 | 550 |
530 private static final String TAG = "UrlRequestFactory"; | 551 private static final String TAG = "UrlRequestFactory"; |
531 private static final String CRONET_URL_REQUEST_CONTEXT = | 552 private static final String CRONET_URL_REQUEST_CONTEXT = |
532 "org.chromium.net.CronetUrlRequestContext"; | 553 "org.chromium.net.CronetUrlRequestContext"; |
533 | 554 |
534 /** | 555 /** |
535 * Creates a {@link UrlRequest} object. All callbacks will | 556 * Creates a {@link UrlRequest} object. All callbacks will |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
791 /** | 812 /** |
792 * Creates a {@link CronetEngine} with the given {@link Builder}. | 813 * Creates a {@link CronetEngine} with the given {@link Builder}. |
793 * | 814 * |
794 * @param builder builder to used for creating the CronetEngine instance. | 815 * @param builder builder to used for creating the CronetEngine instance. |
795 * @return the created CronetEngine instance. | 816 * @return the created CronetEngine instance. |
796 * @deprecated Use {@link CronetEngine.Builder}. | 817 * @deprecated Use {@link CronetEngine.Builder}. |
797 */ | 818 */ |
798 @Deprecated | 819 @Deprecated |
799 public static CronetEngine createContext(Builder builder) { | 820 public static CronetEngine createContext(Builder builder) { |
800 CronetEngine cronetEngine = null; | 821 CronetEngine cronetEngine = null; |
801 if (builder.getUserAgent().isEmpty()) { | 822 if (builder.getUserAgent() == null) { |
802 builder.setUserAgent(builder.getDefaultUserAgent()); | 823 builder.setUserAgent(builder.getDefaultUserAgent()); |
803 } | 824 } |
804 if (!builder.legacyMode()) { | 825 if (!builder.legacyMode()) { |
805 cronetEngine = createCronetEngine(builder); | 826 cronetEngine = createCronetEngine(builder); |
806 } | 827 } |
807 if (cronetEngine == null) { | 828 if (cronetEngine == null) { |
808 // TODO(mef): Fallback to stub implementation. Once stub | 829 // TODO(mef): Fallback to stub implementation. Once stub |
809 // implementation is available merge with createCronetFactory. | 830 // implementation is available merge with createCronetFactory. |
810 cronetEngine = createCronetEngine(builder); | 831 cronetEngine = createCronetEngine(builder); |
811 } | 832 } |
(...skipping 15 matching lines...) Expand all Loading... |
827 cronetEngine = possibleEngine; | 848 cronetEngine = possibleEngine; |
828 } | 849 } |
829 } catch (ClassNotFoundException e) { | 850 } catch (ClassNotFoundException e) { |
830 // Leave as null. | 851 // Leave as null. |
831 } catch (Exception e) { | 852 } catch (Exception e) { |
832 throw new IllegalStateException("Cannot instantiate: " + CRONET_URL_
REQUEST_CONTEXT, e); | 853 throw new IllegalStateException("Cannot instantiate: " + CRONET_URL_
REQUEST_CONTEXT, e); |
833 } | 854 } |
834 return cronetEngine; | 855 return cronetEngine; |
835 } | 856 } |
836 } | 857 } |
OLD | NEW |