Index: components/cronet/android/api/src/org/chromium/net/CronetEngine.java |
diff --git a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java |
index 9170046eb779ed34411aec3f24a54ef4735f2a68..4bf88d7d8f3803f7a889188bf25592bf97600e82 100644 |
--- a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java |
+++ b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java |
@@ -6,13 +6,8 @@ package org.chromium.net; |
import android.content.Context; |
import android.support.annotation.IntDef; |
-import android.util.Base64; |
import android.util.Log; |
-import org.json.JSONArray; |
-import org.json.JSONException; |
-import org.json.JSONObject; |
- |
import java.io.File; |
import java.lang.annotation.Retention; |
import java.lang.annotation.RetentionPolicy; |
@@ -24,6 +19,7 @@ import java.net.URLConnection; |
import java.net.URLStreamHandlerFactory; |
import java.util.Date; |
import java.util.HashSet; |
+import java.util.LinkedList; |
import java.util.List; |
import java.util.Map; |
import java.util.Set; |
@@ -41,18 +37,72 @@ public abstract class CronetEngine { |
* then {@link #build} is called to create the {@code CronetEngine}. |
*/ |
public static class Builder { |
+ // A hint that a host supports QUIC. |
+ static class QuicHint { |
+ // The host. |
+ final String mHost; |
+ // Port of the server that supports QUIC. |
+ final int mPort; |
+ // Alternate protocol port. |
+ final int mAlternatePort; |
+ |
+ QuicHint(String host, int port, int alternatePort) { |
+ mHost = host; |
+ mPort = port; |
+ mAlternatePort = alternatePort; |
+ } |
+ } |
+ |
+ // A public key pin. |
+ static class Pkp { |
+ // Host to pin for. |
+ final String mHost; |
+ // Array of SHA-256 hashes of keys. |
+ final byte[][] mHashes; |
+ // Should pin apply to subdomains? |
+ final boolean mIncludeSubdomains; |
+ // When the pin expires. |
+ final Date mExpirationDate; |
+ |
+ Pkp(String host, byte[][] hashes, boolean includeSubdomains, Date expirationDate) { |
+ mHost = host; |
+ mHashes = hashes; |
+ mIncludeSubdomains = includeSubdomains; |
+ mExpirationDate = expirationDate; |
+ } |
+ } |
+ |
private static final Pattern INVALID_PKP_HOST_NAME = Pattern.compile("^[0-9\\.]*$"); |
- private final JSONObject mConfig; |
+ // Private fields are simply storage of configuration for the resulting CronetEngine. |
+ // See setters below for verbose descriptions. |
private final Context mContext; |
+ private final List<QuicHint> mQuicHints = new LinkedList<QuicHint>(); |
+ private final List<Pkp> mPkps = new LinkedList<Pkp>(); |
+ private String mUserAgent; |
+ private String mStoragePath; |
+ private boolean mLegacyModeEnabled; |
+ private String mLibraryName; |
+ private boolean mQuicEnabled; |
+ private boolean mHttp2Enabled; |
+ private boolean mSdchEnabled; |
+ private String mDataReductionProxyKey; |
+ private String mDataReductionProxyPrimaryProxy; |
+ private String mDataReductionProxyFallbackProxy; |
+ private String mDataReductionProxySecureProxyCheckUrl; |
+ private boolean mDisableCache; |
+ private int mHttpCacheMode; |
+ private long mHttpCacheMaxSize; |
+ private String mExperimentalOptions; |
+ private long mMockCertVerifier; |
/** |
* Default config enables SPDY, disables QUIC, SDCH and HTTP cache. |
* @param context Android {@link Context} for engine to use. |
*/ |
public Builder(Context context) { |
- mConfig = new JSONObject(); |
mContext = context; |
+ setLibraryName("cronet"); |
enableLegacyMode(false); |
enableQUIC(false); |
enableHTTP2(true); |
@@ -75,11 +125,12 @@ public abstract class CronetEngine { |
* @return the builder to facilitate chaining. |
*/ |
public Builder setUserAgent(String userAgent) { |
- return putString(CronetEngineBuilderList.USER_AGENT, userAgent); |
+ mUserAgent = userAgent; |
+ return this; |
} |
String getUserAgent() { |
- return mConfig.optString(CronetEngineBuilderList.USER_AGENT); |
+ return mUserAgent; |
} |
/** |
@@ -98,12 +149,12 @@ public abstract class CronetEngine { |
throw new IllegalArgumentException( |
"Storage path must be set to existing directory"); |
} |
- |
- return putString(CronetEngineBuilderList.STORAGE_PATH, value); |
+ mStoragePath = value; |
+ return this; |
} |
String storagePath() { |
- return mConfig.optString(CronetEngineBuilderList.STORAGE_PATH); |
+ return mStoragePath; |
} |
/** |
@@ -115,11 +166,12 @@ public abstract class CronetEngine { |
*/ |
@Deprecated |
public Builder enableLegacyMode(boolean value) { |
- return putBoolean(CronetEngineBuilderList.ENABLE_LEGACY_MODE, value); |
+ mLegacyModeEnabled = value; |
+ return this; |
} |
boolean legacyMode() { |
- return mConfig.optBoolean(CronetEngineBuilderList.ENABLE_LEGACY_MODE); |
+ return mLegacyModeEnabled; |
} |
/** |
@@ -127,11 +179,12 @@ public abstract class CronetEngine { |
* @return the builder to facilitate chaining. |
*/ |
Builder setLibraryName(String libName) { |
- return putString(CronetEngineBuilderList.NATIVE_LIBRARY_NAME, libName); |
+ mLibraryName = libName; |
+ return this; |
} |
String libraryName() { |
- return mConfig.optString(CronetEngineBuilderList.NATIVE_LIBRARY_NAME, "cronet"); |
+ return mLibraryName; |
} |
/** |
@@ -140,7 +193,12 @@ public abstract class CronetEngine { |
* @return the builder to facilitate chaining. |
*/ |
public Builder enableQUIC(boolean value) { |
- return putBoolean(CronetEngineBuilderList.ENABLE_QUIC, value); |
+ mQuicEnabled = value; |
+ return this; |
+ } |
+ |
+ boolean quicEnabled() { |
+ return mQuicEnabled; |
} |
/** |
@@ -149,7 +207,12 @@ public abstract class CronetEngine { |
* @return the builder to facilitate chaining. |
*/ |
public Builder enableHTTP2(boolean value) { |
- return putBoolean(CronetEngineBuilderList.ENABLE_SPDY, value); |
+ mHttp2Enabled = value; |
+ return this; |
+ } |
+ |
+ boolean http2Enabled() { |
+ return mHttp2Enabled; |
} |
/** |
@@ -160,7 +223,12 @@ public abstract class CronetEngine { |
* @return the builder to facilitate chaining. |
*/ |
public Builder enableSDCH(boolean value) { |
- return putBoolean(CronetEngineBuilderList.ENABLE_SDCH, value); |
+ mSdchEnabled = value; |
+ return this; |
+ } |
+ |
+ boolean sdchEnabled() { |
+ return mSdchEnabled; |
} |
/** |
@@ -171,7 +239,12 @@ public abstract class CronetEngine { |
* @return the builder to facilitate chaining. |
*/ |
public Builder enableDataReductionProxy(String key) { |
- return (putString(CronetEngineBuilderList.DATA_REDUCTION_PROXY_KEY, key)); |
+ mDataReductionProxyKey = key; |
+ return this; |
+ } |
+ |
+ String dataReductionProxyKey() { |
+ return mDataReductionProxyKey; |
} |
/** |
@@ -197,13 +270,24 @@ public abstract class CronetEngine { |
throw new IllegalArgumentException( |
"Primary and fallback proxies and check url must be set"); |
} |
- putString(CronetEngineBuilderList.DATA_REDUCTION_PRIMARY_PROXY, primaryProxy); |
- putString(CronetEngineBuilderList.DATA_REDUCTION_FALLBACK_PROXY, fallbackProxy); |
- putString(CronetEngineBuilderList.DATA_REDUCTION_SECURE_PROXY_CHECK_URL, |
- secureProxyCheckUrl); |
+ mDataReductionProxyPrimaryProxy = primaryProxy; |
+ mDataReductionProxyFallbackProxy = fallbackProxy; |
+ mDataReductionProxySecureProxyCheckUrl = secureProxyCheckUrl; |
return this; |
} |
+ String dataReductionProxyPrimaryProxy() { |
+ return mDataReductionProxyPrimaryProxy; |
+ } |
+ |
+ String dataReductionProxyFallbackProxy() { |
+ return mDataReductionProxyFallbackProxy; |
+ } |
+ |
+ String dataReductionProxySecureProxyCheckUrl() { |
+ return mDataReductionProxySecureProxyCheckUrl; |
+ } |
+ |
/** @deprecated not really deprecated but hidden. */ |
@IntDef({ |
HTTP_CACHE_DISABLED, HTTP_CACHE_IN_MEMORY, HTTP_CACHE_DISK_NO_HTTP, HTTP_CACHE_DISK, |
@@ -249,34 +333,47 @@ public abstract class CronetEngine { |
*/ |
public Builder enableHttpCache(@HttpCacheSetting int cacheMode, long maxSize) { |
if (cacheMode == HTTP_CACHE_DISK || cacheMode == HTTP_CACHE_DISK_NO_HTTP) { |
- if (storagePath().isEmpty()) { |
+ if (storagePath() == null) { |
throw new IllegalArgumentException("Storage path must be set"); |
} |
} else { |
- if (!storagePath().isEmpty()) { |
- throw new IllegalArgumentException("Storage path must be empty"); |
+ if (storagePath() != null) { |
+ throw new IllegalArgumentException("Storage path must not be set"); |
} |
} |
- putBoolean(CronetEngineBuilderList.LOAD_DISABLE_CACHE, |
- cacheMode == HTTP_CACHE_DISABLED || cacheMode == HTTP_CACHE_DISK_NO_HTTP); |
- putLong(CronetEngineBuilderList.HTTP_CACHE_MAX_SIZE, maxSize); |
+ mDisableCache = |
+ (cacheMode == HTTP_CACHE_DISABLED || cacheMode == HTTP_CACHE_DISK_NO_HTTP); |
+ mHttpCacheMaxSize = maxSize; |
switch (cacheMode) { |
case HTTP_CACHE_DISABLED: |
- return putString(CronetEngineBuilderList.HTTP_CACHE, |
- CronetEngineBuilderList.HTTP_CACHE_DISABLED); |
+ mHttpCacheMode = HttpCacheType.DISABLED; |
+ break; |
case HTTP_CACHE_DISK_NO_HTTP: |
case HTTP_CACHE_DISK: |
- return putString(CronetEngineBuilderList.HTTP_CACHE, |
- CronetEngineBuilderList.HTTP_CACHE_DISK); |
- |
+ mHttpCacheMode = HttpCacheType.DISK; |
+ break; |
case HTTP_CACHE_IN_MEMORY: |
- return putString(CronetEngineBuilderList.HTTP_CACHE, |
- CronetEngineBuilderList.HTTP_CACHE_MEMORY); |
+ mHttpCacheMode = HttpCacheType.MEMORY; |
+ break; |
+ default: |
+ throw new IllegalArgumentException("Unknown cache mode"); |
} |
return this; |
} |
+ boolean cacheDisabled() { |
+ return mDisableCache; |
+ } |
+ |
+ long httpCacheMaxSize() { |
+ return mHttpCacheMaxSize; |
+ } |
+ |
+ int httpCacheMode() { |
+ return mHttpCacheMode; |
+ } |
+ |
/** |
* Adds hint that {@code host} supports QUIC. |
* Note that {@link #enableHttpCache enableHttpCache} |
@@ -292,24 +389,14 @@ public abstract class CronetEngine { |
if (host.contains("/")) { |
throw new IllegalArgumentException("Illegal QUIC Hint Host: " + host); |
} |
- try { |
- JSONArray quicHints = mConfig.optJSONArray(CronetEngineBuilderList.QUIC_HINTS); |
- if (quicHints == null) { |
- quicHints = new JSONArray(); |
- mConfig.put(CronetEngineBuilderList.QUIC_HINTS, quicHints); |
- } |
- |
- JSONObject hint = new JSONObject(); |
- hint.put(CronetEngineBuilderList.QUIC_HINT_HOST, host); |
- hint.put(CronetEngineBuilderList.QUIC_HINT_PORT, port); |
- hint.put(CronetEngineBuilderList.QUIC_HINT_ALT_PORT, alternatePort); |
- quicHints.put(hint); |
- } catch (JSONException e) { |
- // Intentionally do nothing. |
- } |
+ mQuicHints.add(new QuicHint(host, port, alternatePort)); |
return this; |
} |
+ List<QuicHint> quicHints() { |
+ return mQuicHints; |
+ } |
+ |
/** |
* <p> |
* Pins a set of public keys for a given host. By pinning a set of public keys, |
@@ -363,51 +450,25 @@ public abstract class CronetEngine { |
throw new NullPointerException("The pin expiration date cannot be null"); |
} |
String idnHostName = validateHostNameForPinningAndConvert(hostName); |
- try { |
- // Add PKP_LIST JSON array element if it is not present. |
- JSONArray pkpList = mConfig.optJSONArray(CronetEngineBuilderList.PKP_LIST); |
- if (pkpList == null) { |
- pkpList = new JSONArray(); |
- mConfig.put(CronetEngineBuilderList.PKP_LIST, pkpList); |
- } |
- |
- // Convert the pin to BASE64 encoding. The hash set will eliminate duplications. |
- Set<String> hashes = new HashSet<>(pinsSha256.size()); |
- for (byte[] pinSha256 : pinsSha256) { |
- hashes.add(convertSha256ToBase64WithPrefix(pinSha256)); |
+ // Convert the pin to BASE64 encoding. The hash set will eliminate duplications. |
+ Set<byte[]> hashes = new HashSet<>(pinsSha256.size()); |
+ for (byte[] pinSha256 : pinsSha256) { |
+ if (pinSha256 == null || pinSha256.length != 32) { |
+ throw new IllegalArgumentException("Public key pin is invalid"); |
} |
- |
- // Add new element to PKP_LIST JSON array. |
- JSONObject pkp = new JSONObject(); |
- pkp.put(CronetEngineBuilderList.PKP_HOST, idnHostName); |
- pkp.put(CronetEngineBuilderList.PKP_PIN_HASHES, new JSONArray(hashes)); |
- pkp.put(CronetEngineBuilderList.PKP_INCLUDE_SUBDOMAINS, includeSubdomains); |
- // The expiration time is passed as a double, in seconds since January 1, 1970. |
- pkp.put(CronetEngineBuilderList.PKP_EXPIRATION_DATE, |
- (double) expirationDate.getTime() / 1000); |
- pkpList.put(pkp); |
- } catch (JSONException e) { |
- // This exception should never happen. |
- throw new RuntimeException( |
- "Failed to add pubic key pins with the given arguments", e); |
+ hashes.add(pinSha256); |
} |
+ // Add new element to PKP list. |
+ mPkps.add(new Pkp(idnHostName, hashes.toArray(new byte[hashes.size()][]), |
+ includeSubdomains, expirationDate)); |
return this; |
} |
/** |
- * Converts a given SHA256 array of bytes to BASE64 encoded string and prepends |
- * {@code sha256/} prefix to it. The format corresponds to the format that is expected by |
- * {@code net::HashValue} class. |
- * |
- * @param sha256 SHA256 bytes to convert to BASE64. |
- * @return the BASE64 encoded SHA256 with the prefix. |
- * @throws IllegalArgumentException if the provided pin is invalid. |
+ * Returns list of public key pins. |
*/ |
- private static String convertSha256ToBase64WithPrefix(byte[] sha256) { |
- if (sha256 == null || sha256.length != 32) { |
- throw new IllegalArgumentException("Public key pin is invalid"); |
- } |
- return "sha256/" + Base64.encodeToString(sha256, Base64.NO_WRAP); |
+ List<Pkp> publicKeyPins() { |
+ return mPkps; |
} |
/** |
@@ -446,22 +507,24 @@ public abstract class CronetEngine { |
* @return the builder to facilitate chaining. |
*/ |
public Builder setExperimentalOptions(String options) { |
- return putString(CronetEngineBuilderList.EXPERIMENTAL_OPTIONS, options); |
+ mExperimentalOptions = options; |
+ return this; |
+ } |
+ |
+ String experimentalOptions() { |
+ return mExperimentalOptions; |
} |
/** |
* Sets a native MockCertVerifier for testing. |
*/ |
Builder setMockCertVerifierForTesting(long mockCertVerifier) { |
- return putString( |
- CronetEngineBuilderList.MOCK_CERT_VERIFIER, String.valueOf(mockCertVerifier)); |
+ mMockCertVerifier = mockCertVerifier; |
+ return this; |
} |
- /** |
- * Gets a JSON string representation of the builder. |
- */ |
- String toJSONString() { |
- return mConfig.toString(); |
+ long mockCertVerifier() { |
+ return mMockCertVerifier; |
} |
/** |
@@ -474,55 +537,13 @@ public abstract class CronetEngine { |
} |
/** |
- * Sets a boolean value in the config. Returns a reference to the same |
- * config object, so you can chain put calls together. |
- * @return the builder to facilitate chaining. |
- */ |
- private Builder putBoolean(String key, boolean value) { |
- try { |
- mConfig.put(key, value); |
- } catch (JSONException e) { |
- // Intentionally do nothing. |
- } |
- return this; |
- } |
- |
- /** |
- * Sets a long value in the config. Returns a reference to the same |
- * config object, so you can chain put calls together. |
- * @return the builder to facilitate chaining. |
- */ |
- private Builder putLong(String key, long value) { |
- try { |
- mConfig.put(key, value); |
- } catch (JSONException e) { |
- // Intentionally do nothing. |
- } |
- return this; |
- } |
- |
- /** |
- * Sets a string value in the config. Returns a reference to the same |
- * config object, so you can chain put calls together. |
- * @return the builder to facilitate chaining. |
- */ |
- private Builder putString(String key, String value) { |
- try { |
- mConfig.put(key, value); |
- } catch (JSONException e) { |
- // Intentionally do nothing. |
- } |
- return this; |
- } |
- |
- /** |
* Build a {@link CronetEngine} using this builder's configuration. |
*/ |
public CronetEngine build() { |
CronetEngine engine = createContext(this); |
// Clear MOCK_CERT_VERIFIER reference if there is any, since |
// the ownership has been transferred to the engine. |
- mConfig.remove(CronetEngineBuilderList.MOCK_CERT_VERIFIER); |
+ mMockCertVerifier = 0; |
return engine; |
} |
} |
@@ -798,7 +819,7 @@ public abstract class CronetEngine { |
@Deprecated |
public static CronetEngine createContext(Builder builder) { |
CronetEngine cronetEngine = null; |
- if (builder.getUserAgent().isEmpty()) { |
+ if (builder.getUserAgent() == null) { |
builder.setUserAgent(builder.getDefaultUserAgent()); |
} |
if (!builder.legacyMode()) { |