Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(564)

Side by Side Diff: components/cronet/android/java/src/org/chromium/net/impl/CronetEngineBuilderImpl.java

Issue 2339223002: Cronet API Refactoring (Closed)
Patch Set: Rebase + conflict resolution Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 package org.chromium.net.impl;
5
6 import android.content.Context;
7 import android.support.annotation.IntDef;
8
9 import static org.chromium.net.CronetEngine.Builder.HTTP_CACHE_DISABLED;
10 import static org.chromium.net.CronetEngine.Builder.HTTP_CACHE_DISK;
11 import static org.chromium.net.CronetEngine.Builder.HTTP_CACHE_DISK_NO_HTTP;
12 import static org.chromium.net.CronetEngine.Builder.HTTP_CACHE_IN_MEMORY;
13
14 import org.chromium.base.Log;
15 import org.chromium.base.VisibleForTesting;
16 import org.chromium.net.CronetEngine;
17 import org.chromium.net.ExperimentalCronetEngine;
18 import org.chromium.net.ICronetEngineBuilder;
19
20 import java.io.File;
21 import java.lang.annotation.Retention;
22 import java.lang.annotation.RetentionPolicy;
23 import java.net.IDN;
24 import java.util.Date;
25 import java.util.HashSet;
26 import java.util.LinkedList;
27 import java.util.List;
28 import java.util.Set;
29 import java.util.regex.Pattern;
30
31 /**
32 * Implementation of {@link ICronetEngineBuilder}.
33 */
34 public class CronetEngineBuilderImpl extends ICronetEngineBuilder {
35 /**
36 * A hint that a host supports QUIC.
37 */
38 public static class QuicHint {
39 // The host.
40 final String mHost;
41 // Port of the server that supports QUIC.
42 final int mPort;
43 // Alternate protocol port.
44 final int mAlternatePort;
45
46 QuicHint(String host, int port, int alternatePort) {
47 mHost = host;
48 mPort = port;
49 mAlternatePort = alternatePort;
50 }
51 }
52
53 /**
54 * A public key pin.
55 */
56 public static class Pkp {
57 // Host to pin for.
58 final String mHost;
59 // Array of SHA-256 hashes of keys.
60 final byte[][] mHashes;
61 // Should pin apply to subdomains?
62 final boolean mIncludeSubdomains;
63 // When the pin expires.
64 final Date mExpirationDate;
65
66 Pkp(String host, byte[][] hashes, boolean includeSubdomains, Date expira tionDate) {
67 mHost = host;
68 mHashes = hashes;
69 mIncludeSubdomains = includeSubdomains;
70 mExpirationDate = expirationDate;
71 }
72 }
73
74 private static final String TAG = "CronetEngineBuilder";
75 private static final Pattern INVALID_PKP_HOST_NAME = Pattern.compile("^[0-9\ \.]*$");
76
77 // Private fields are simply storage of configuration for the resulting Cron etEngine.
78 // See setters below for verbose descriptions.
79 private final Context mContext;
80 private final List<QuicHint> mQuicHints = new LinkedList<>();
81 private final List<Pkp> mPkps = new LinkedList<>();
82 private boolean mPublicKeyPinningBypassForLocalTrustAnchorsEnabled;
83 private String mUserAgent;
84 private String mStoragePath;
85 private boolean mLegacyModeEnabled;
86 private CronetEngine.Builder.LibraryLoader mLibraryLoader;
87 private String mLibraryName;
88 private boolean mQuicEnabled;
89 private boolean mHttp2Enabled;
90 private boolean mSdchEnabled;
91 private String mDataReductionProxyKey;
92 private String mDataReductionProxyPrimaryProxy;
93 private String mDataReductionProxyFallbackProxy;
94 private String mDataReductionProxySecureProxyCheckUrl;
95 private boolean mDisableCache;
96 private int mHttpCacheMode;
97 private long mHttpCacheMaxSize;
98 private String mExperimentalOptions;
99 private long mMockCertVerifier;
100 private boolean mNetworkQualityEstimatorEnabled;
101 private String mCertVerifierData;
102
103 /**
104 * Default config enables SPDY, disables QUIC, SDCH and HTTP cache.
105 * @param context Android {@link Context} for engine to use.
106 */
107 public CronetEngineBuilderImpl(Context context) {
108 mContext = context;
109 setLibraryName("cronet");
110 enableLegacyMode(false);
111 enableQuic(false);
112 enableHttp2(true);
113 enableSdch(false);
114 enableHttpCache(HTTP_CACHE_DISABLED, 0);
115 enableNetworkQualityEstimator(false);
116 enablePublicKeyPinningBypassForLocalTrustAnchors(true);
117 }
118
119 @Override
120 public String getDefaultUserAgent() {
121 return UserAgent.from(mContext);
122 }
123
124 @Override
125 public CronetEngineBuilderImpl setUserAgent(String userAgent) {
126 mUserAgent = userAgent;
127 return this;
128 }
129
130 String getUserAgent() {
131 return mUserAgent;
132 }
133
134 @Override
135 public CronetEngineBuilderImpl setStoragePath(String value) {
136 if (!new File(value).isDirectory()) {
137 throw new IllegalArgumentException("Storage path must be set to exis ting directory");
138 }
139 mStoragePath = value;
140 return this;
141 }
142
143 String storagePath() {
144 return mStoragePath;
145 }
146
147 @Override
148 public CronetEngineBuilderImpl enableLegacyMode(boolean value) {
149 mLegacyModeEnabled = value;
150 return this;
151 }
152
153 private boolean legacyMode() {
154 return mLegacyModeEnabled;
155 }
156
157 /**
158 * Overrides the name of the native library backing Cronet.
159 * @param libName the name of the native library backing Cronet.
160 * @return the builder to facilitate chaining.
161 */
162 public CronetEngineBuilderImpl setLibraryName(String libName) {
163 mLibraryName = libName;
164 return this;
165 }
166
167 String libraryName() {
168 return mLibraryName;
169 }
170
171 @Override
172 public CronetEngineBuilderImpl setLibraryLoader(CronetEngine.Builder.Library Loader loader) {
173 mLibraryLoader = loader;
174 return this;
175 }
176
177 CronetEngine.Builder.LibraryLoader libraryLoader() {
178 return mLibraryLoader;
179 }
180
181 @Override
182 public CronetEngineBuilderImpl enableQuic(boolean value) {
183 mQuicEnabled = value;
184 return this;
185 }
186
187 boolean quicEnabled() {
188 return mQuicEnabled;
189 }
190
191 /**
192 * Constructs default QUIC User Agent Id string including application name
193 * and Cronet version. Returns empty string if QUIC is not enabled.
194 *
195 * @return QUIC User Agent ID string.
196 */
197 String getDefaultQuicUserAgentId() {
198 return mQuicEnabled ? UserAgent.getQuicUserAgentIdFrom(mContext) : "";
199 }
200
201 @Override
202 public CronetEngineBuilderImpl enableHttp2(boolean value) {
203 mHttp2Enabled = value;
204 return this;
205 }
206
207 boolean http2Enabled() {
208 return mHttp2Enabled;
209 }
210
211 @Override
212 public CronetEngineBuilderImpl enableSdch(boolean value) {
213 mSdchEnabled = value;
214 return this;
215 }
216
217 boolean sdchEnabled() {
218 return mSdchEnabled;
219 }
220
221 @Override
222 public CronetEngineBuilderImpl enableDataReductionProxy(String key) {
223 mDataReductionProxyKey = key;
224 return this;
225 }
226
227 String dataReductionProxyKey() {
228 return mDataReductionProxyKey;
229 }
230
231 @Override
232 public CronetEngineBuilderImpl setDataReductionProxyOptions(
233 String primaryProxy, String fallbackProxy, String secureProxyCheckUr l) {
234 if (primaryProxy.isEmpty() || fallbackProxy.isEmpty() || secureProxyChec kUrl.isEmpty()) {
235 throw new IllegalArgumentException(
236 "Primary and fallback proxies and check url must be set");
237 }
238 mDataReductionProxyPrimaryProxy = primaryProxy;
239 mDataReductionProxyFallbackProxy = fallbackProxy;
240 mDataReductionProxySecureProxyCheckUrl = secureProxyCheckUrl;
241 return this;
242 }
243
244 String dataReductionProxyPrimaryProxy() {
245 return mDataReductionProxyPrimaryProxy;
246 }
247
248 String dataReductionProxyFallbackProxy() {
249 return mDataReductionProxyFallbackProxy;
250 }
251
252 String dataReductionProxySecureProxyCheckUrl() {
253 return mDataReductionProxySecureProxyCheckUrl;
254 }
255
256 @IntDef({
257 HTTP_CACHE_DISABLED, HTTP_CACHE_IN_MEMORY, HTTP_CACHE_DISK_NO_HTTP, HTTP_CACHE_DISK,
258 })
259 @Retention(RetentionPolicy.SOURCE)
260 public @interface HttpCacheSetting {}
261
262 @Override
263 public CronetEngineBuilderImpl enableHttpCache(@HttpCacheSetting int cacheMo de, long maxSize) {
264 if (cacheMode == HTTP_CACHE_DISK || cacheMode == HTTP_CACHE_DISK_NO_HTTP ) {
265 if (storagePath() == null) {
266 throw new IllegalArgumentException("Storage path must be set");
267 }
268 } else {
269 if (storagePath() != null) {
270 throw new IllegalArgumentException("Storage path must not be set ");
271 }
272 }
273 mDisableCache = (cacheMode == HTTP_CACHE_DISABLED || cacheMode == HTTP_C ACHE_DISK_NO_HTTP);
274 mHttpCacheMaxSize = maxSize;
275
276 switch (cacheMode) {
277 case HTTP_CACHE_DISABLED:
278 mHttpCacheMode = HttpCacheType.DISABLED;
279 break;
280 case HTTP_CACHE_DISK_NO_HTTP:
281 case HTTP_CACHE_DISK:
282 mHttpCacheMode = HttpCacheType.DISK;
283 break;
284 case HTTP_CACHE_IN_MEMORY:
285 mHttpCacheMode = HttpCacheType.MEMORY;
286 break;
287 default:
288 throw new IllegalArgumentException("Unknown cache mode");
289 }
290 return this;
291 }
292
293 boolean cacheDisabled() {
294 return mDisableCache;
295 }
296
297 long httpCacheMaxSize() {
298 return mHttpCacheMaxSize;
299 }
300
301 int httpCacheMode() {
302 return mHttpCacheMode;
303 }
304
305 @Override
306 public CronetEngineBuilderImpl addQuicHint(String host, int port, int altern atePort) {
307 if (host.contains("/")) {
308 throw new IllegalArgumentException("Illegal QUIC Hint Host: " + host );
309 }
310 mQuicHints.add(new QuicHint(host, port, alternatePort));
311 return this;
312 }
313
314 List<QuicHint> quicHints() {
315 return mQuicHints;
316 }
317
318 @Override
319 public CronetEngineBuilderImpl addPublicKeyPins(String hostName, Set<byte[]> pinsSha256,
320 boolean includeSubdomains, Date expirationDate) {
321 if (hostName == null) {
322 throw new NullPointerException("The hostname cannot be null");
323 }
324 if (pinsSha256 == null) {
325 throw new NullPointerException("The set of SHA256 pins cannot be nul l");
326 }
327 if (expirationDate == null) {
328 throw new NullPointerException("The pin expiration date cannot be nu ll");
329 }
330 String idnHostName = validateHostNameForPinningAndConvert(hostName);
331 // Convert the pin to BASE64 encoding. The hash set will eliminate dupli cations.
332 Set<byte[]> hashes = new HashSet<>(pinsSha256.size());
333 for (byte[] pinSha256 : pinsSha256) {
334 if (pinSha256 == null || pinSha256.length != 32) {
335 throw new IllegalArgumentException("Public key pin is invalid");
336 }
337 hashes.add(pinSha256);
338 }
339 // Add new element to PKP list.
340 mPkps.add(new Pkp(idnHostName, hashes.toArray(new byte[hashes.size()][]) , includeSubdomains,
341 expirationDate));
342 return this;
343 }
344
345 /**
346 * Returns list of public key pins.
347 * @return list of public key pins.
348 */
349 List<Pkp> publicKeyPins() {
350 return mPkps;
351 }
352
353 @Override
354 public CronetEngineBuilderImpl enablePublicKeyPinningBypassForLocalTrustAnch ors(boolean value) {
355 mPublicKeyPinningBypassForLocalTrustAnchorsEnabled = value;
356 return this;
357 }
358
359 boolean publicKeyPinningBypassForLocalTrustAnchorsEnabled() {
360 return mPublicKeyPinningBypassForLocalTrustAnchorsEnabled;
361 }
362
363 /**
364 * Checks whether a given string represents a valid host name for PKP and co nverts it
365 * to ASCII Compatible Encoding representation according to RFC 1122, RFC 11 23 and
366 * RFC 3490. This method is more restrictive than required by RFC 7469. Thus , a host
367 * that contains digits and the dot character only is considered invalid.
368 *
369 * Note: Currently Cronet doesn't have native implementation of host name va lidation that
370 * can be used. There is code that parses a provided URL but doesn't e nsure its
371 * correctness. The implementation relies on {@code getaddrinfo} funct ion.
372 *
373 * @param hostName host name to check and convert.
374 * @return true if the string is a valid host name.
375 * @throws IllegalArgumentException if the the given string does not represe nt a valid
376 * hostname.
377 */
378 private static String validateHostNameForPinningAndConvert(String hostName)
379 throws IllegalArgumentException {
380 if (INVALID_PKP_HOST_NAME.matcher(hostName).matches()) {
381 throw new IllegalArgumentException("Hostname " + hostName + " is ill egal."
382 + " A hostname should not consist of digits and/or dots only .");
383 }
384 // Workaround for crash, see crbug.com/634914
385 if (hostName.length() > 255) {
386 throw new IllegalArgumentException("Hostname " + hostName + " is too long."
387 + " The name of the host does not comply with RFC 1122 and R FC 1123.");
388 }
389 try {
390 return IDN.toASCII(hostName, IDN.USE_STD3_ASCII_RULES);
391 } catch (IllegalArgumentException ex) {
392 throw new IllegalArgumentException("Hostname " + hostName + " is ill egal."
393 + " The name of the host does not comply with RFC 1122 and R FC 1123.");
394 }
395 }
396
397 @Override
398 public CronetEngineBuilderImpl setExperimentalOptions(String options) {
399 mExperimentalOptions = options;
400 return this;
401 }
402
403 public String experimentalOptions() {
404 return mExperimentalOptions;
405 }
406
407 /**
408 * Sets a native MockCertVerifier for testing. See
409 * {@code MockCertVerifier.createMockCertVerifier} for a method that
410 * can be used to create a MockCertVerifier.
411 * @param mockCertVerifier pointer to native MockCertVerifier.
412 * @return the builder to facilitate chaining.
413 */
414 @VisibleForTesting
415 public CronetEngineBuilderImpl setMockCertVerifierForTesting(long mockCertVe rifier) {
416 mMockCertVerifier = mockCertVerifier;
417 return this;
418 }
419
420 long mockCertVerifier() {
421 return mMockCertVerifier;
422 }
423
424 /**
425 * @return true if the network quality estimator has been enabled for
426 * this builder.
427 */
428 boolean networkQualityEstimatorEnabled() {
429 return mNetworkQualityEstimatorEnabled;
430 }
431
432 @Override
433 public CronetEngineBuilderImpl setCertVerifierData(String certVerifierData) {
434 mCertVerifierData = certVerifierData;
435 return this;
436 }
437
438 @Override
439 public CronetEngineBuilderImpl enableNetworkQualityEstimator(boolean value) {
440 mNetworkQualityEstimatorEnabled = value;
441 return this;
442 }
443
444 String certVerifierData() {
445 return mCertVerifierData;
446 }
447
448 /**
449 * Returns {@link Context} for builder.
450 *
451 * @return {@link Context} for builder.
452 */
453 Context getContext() {
454 return mContext;
455 }
456
457 @Override
458 public ExperimentalCronetEngine build() {
459 if (getUserAgent() == null) {
460 setUserAgent(getDefaultUserAgent());
461 }
462 final ExperimentalCronetEngine cronetEngine;
463 if (!legacyMode()) {
464 cronetEngine = new CronetUrlRequestContext(this);
465 } else {
466 cronetEngine = new JavaCronetEngine(getUserAgent());
467 }
468 Log.i(TAG, "Using network stack: " + cronetEngine.getVersionString());
469 // Clear MOCK_CERT_VERIFIER reference if there is any, since
470 // the ownership has been transferred to the engine.
471 mMockCertVerifier = 0;
472 return cronetEngine;
473 }
474 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698