summaryrefslogtreecommitdiffstats
path: root/core/java/android/net
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/net')
-rw-r--r--core/java/android/net/ConnectivityManager.java51
-rw-r--r--core/java/android/net/IConnectivityManager.aidl4
-rw-r--r--core/java/android/net/SSLCertificateSocketFactory.java102
-rw-r--r--core/java/android/net/Uri.java9
-rw-r--r--core/java/android/net/UrlQuerySanitizer.java126
-rw-r--r--core/java/android/net/http/AndroidHttpClient.java68
-rw-r--r--core/java/android/net/http/CertificateChainValidator.java154
-rw-r--r--core/java/android/net/http/RequestHandle.java10
8 files changed, 295 insertions, 229 deletions
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 213813a..1429bc1 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -16,6 +16,8 @@
package android.net;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.os.RemoteException;
/**
@@ -100,6 +102,18 @@ public class ConnectivityManager
*/
public static final String EXTRA_EXTRA_INFO = "extraInfo";
+ /**
+ * Broadcast Action: The setting for background data usage has changed
+ * values. Use {@link #getBackgroundDataSetting()} to get the current value.
+ * <p>
+ * If an application uses the network in the background, it should listen
+ * for this broadcast and stop using the background data if the value is
+ * false.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED =
+ "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
+
public static final int TYPE_MOBILE = 0;
public static final int TYPE_WIFI = 1;
@@ -224,6 +238,43 @@ public class ConnectivityManager
}
/**
+ * Returns the value of the setting for background data usage. If false,
+ * applications should not use the network if the application is not in the
+ * foreground. Developers should respect this setting, and check the value
+ * of this before performing any background data operations.
+ * <p>
+ * All applications that have background services that use the network
+ * should listen to {@link #ACTION_BACKGROUND_DATA_SETTING_CHANGED}.
+ *
+ * @return Whether background data usage is allowed.
+ */
+ public boolean getBackgroundDataSetting() {
+ try {
+ return mService.getBackgroundDataSetting();
+ } catch (RemoteException e) {
+ // Err on the side of safety
+ return false;
+ }
+ }
+
+ /**
+ * Sets the value of the setting for background data usage.
+ *
+ * @param allowBackgroundData Whether an application should use data while
+ * it is in the background.
+ *
+ * @attr ref android.Manifest.permission#CHANGE_BACKGROUND_DATA_SETTING
+ * @see #getBackgroundDataSetting()
+ * @hide
+ */
+ public void setBackgroundDataSetting(boolean allowBackgroundData) {
+ try {
+ mService.setBackgroundDataSetting(allowBackgroundData);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* Don't allow use of default constructor.
*/
@SuppressWarnings({"UnusedDeclaration"})
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index e1d921f..de68598 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -44,4 +44,8 @@ interface IConnectivityManager
int stopUsingNetworkFeature(int networkType, in String feature);
boolean requestRouteToHost(int networkType, int hostAddress);
+
+ boolean getBackgroundDataSetting();
+
+ void setBackgroundDataSetting(boolean allowBackgroundData);
}
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index f816caa..deaa3c3 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -16,38 +16,45 @@
package android.net;
-import android.util.Log;
-import android.util.Config;
import android.net.http.DomainNameChecker;
import android.os.SystemProperties;
-
-import javax.net.SocketFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509TrustManager;
+import android.util.Config;
+import android.util.Log;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
-import java.security.NoSuchAlgorithmException;
+import java.security.GeneralSecurityException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
-import java.security.GeneralSecurityException;
+import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
+import org.apache.harmony.xnet.provider.jsse.SSLContextImpl;
+
+/**
+ * SSLSocketFactory that provides optional (on debug devices, only) skipping of ssl certificfate
+ * chain validation and custom read timeouts used just when connecting to the server/negotiating
+ * an ssl session.
+ *
+ * You can skip the ssl certificate checking at runtime by setting socket.relaxsslcheck=yes on
+ * devices that do not have have ro.secure set.
+ */
public class SSLCertificateSocketFactory extends SSLSocketFactory {
- private static final boolean DBG = true;
private static final String LOG_TAG = "SSLCertificateSocketFactory";
-
- private static X509TrustManager sDefaultTrustManager;
- private final int socketReadTimeoutForSslHandshake;
+ private static X509TrustManager sDefaultTrustManager;
static {
try {
@@ -83,27 +90,56 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
}
};
- private SSLSocketFactory factory;
+ private final SSLSocketFactory mFactory;
+
+ private final int mSocketReadTimeoutForSslHandshake;
+ /**
+ * Do not use this constructor (will be deprecated). Use {@link #getDefault(int)} instead.
+ */
public SSLCertificateSocketFactory(int socketReadTimeoutForSslHandshake)
- throws NoSuchAlgorithmException, KeyManagementException {
- SSLContext context = SSLContext.getInstance("TLS");
- context.init(null, TRUST_MANAGER, new java.security.SecureRandom());
- factory = (SSLSocketFactory) context.getSocketFactory();
- this.socketReadTimeoutForSslHandshake = socketReadTimeoutForSslHandshake;
+ throws NoSuchAlgorithmException, KeyManagementException {
+ this(socketReadTimeoutForSslHandshake, null /* cache */);
+ }
+
+ private SSLCertificateSocketFactory(int socketReadTimeoutForSslHandshake,
+ SSLClientSessionCache cache) throws NoSuchAlgorithmException, KeyManagementException {
+ SSLContextImpl sslContext = new SSLContextImpl();
+ sslContext.engineInit(null /* kms */,
+ TRUST_MANAGER, new java.security.SecureRandom(),
+ cache /* client cache */, null /* server cache */);
+ this.mFactory = sslContext.engineGetSocketFactory();
+ this.mSocketReadTimeoutForSslHandshake = socketReadTimeoutForSslHandshake;
}
/**
- * Returns a default instantiation of a new socket factory which
- * only allows SSL connections with valid certificates.
+ * Returns a new instance of a socket factory using the specified socket read
+ * timeout while connecting with the server/negotiating an ssl session.
*
* @param socketReadTimeoutForSslHandshake the socket read timeout used for performing
* ssl handshake. The socket read timeout is set back to 0 after the handshake.
* @return a new SocketFactory, or null on error
*/
public static SocketFactory getDefault(int socketReadTimeoutForSslHandshake) {
+ return getDefault(socketReadTimeoutForSslHandshake, null /* cache */);
+ }
+
+ /**
+ * Returns a new instance of a socket factory using the specified socket read
+ * timeout while connecting with the server/negotiating an ssl session.
+ * Persists ssl sessions using the provided {@link SSLClientSessionCache}.
+ *
+ * @param socketReadTimeoutForSslHandshake the socket read timeout used for performing
+ * ssl handshake. The socket read timeout is set back to 0 after the handshake.
+ * @param cache The {@link SSLClientSessionCache} to use, if any.
+ * @return a new SocketFactory, or null on error
+ *
+ * @hide
+ */
+ public static SocketFactory getDefault(int socketReadTimeoutForSslHandshake,
+ SSLClientSessionCache cache) {
try {
- return new SSLCertificateSocketFactory(socketReadTimeoutForSslHandshake);
+ return new SSLCertificateSocketFactory(socketReadTimeoutForSslHandshake, cache);
} catch (NoSuchAlgorithmException e) {
Log.e(LOG_TAG,
"SSLCertifcateSocketFactory.getDefault" +
@@ -217,10 +253,10 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
}
public Socket createSocket(String s, int i, InetAddress inaddr, int j) throws IOException {
- SSLSocket sslSock = (SSLSocket) factory.createSocket(s, i, inaddr, j);
+ SSLSocket sslSock = (SSLSocket) mFactory.createSocket(s, i, inaddr, j);
- if (socketReadTimeoutForSslHandshake >= 0) {
- sslSock.setSoTimeout(socketReadTimeoutForSslHandshake);
+ if (mSocketReadTimeoutForSslHandshake >= 0) {
+ sslSock.setSoTimeout(mSocketReadTimeoutForSslHandshake);
}
validateSocket(sslSock,s);
@@ -230,10 +266,10 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
}
public Socket createSocket(String s, int i) throws IOException {
- SSLSocket sslSock = (SSLSocket) factory.createSocket(s, i);
+ SSLSocket sslSock = (SSLSocket) mFactory.createSocket(s, i);
- if (socketReadTimeoutForSslHandshake >= 0) {
- sslSock.setSoTimeout(socketReadTimeoutForSslHandshake);
+ if (mSocketReadTimeoutForSslHandshake >= 0) {
+ sslSock.setSoTimeout(mSocketReadTimeoutForSslHandshake);
}
validateSocket(sslSock,s);
@@ -243,11 +279,11 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
}
public String[] getDefaultCipherSuites() {
- return factory.getSupportedCipherSuites();
+ return mFactory.getSupportedCipherSuites();
}
public String[] getSupportedCipherSuites() {
- return factory.getSupportedCipherSuites();
+ return mFactory.getSupportedCipherSuites();
}
}
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 32a26e4..c23df21 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -2235,12 +2235,13 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
}
/**
- * Creates a new Uri by encoding and appending a path segment to a base Uri.
+ * Creates a new Uri by appending an already-encoded path segment to a
+ * base Uri.
*
* @param baseUri Uri to append path segment to
- * @param pathSegment to encode and append
- * @return a new Uri based on baseUri with the given segment encoded and
- * appended to the path
+ * @param pathSegment encoded path segment to append
+ * @return a new Uri based on baseUri with the given segment appended to
+ * the path
* @throws NullPointerException if baseUri is null
*/
public static Uri withAppendedPath(Uri baseUri, String pathSegment) {
diff --git a/core/java/android/net/UrlQuerySanitizer.java b/core/java/android/net/UrlQuerySanitizer.java
index 70e50b7..a6efcdd 100644
--- a/core/java/android/net/UrlQuerySanitizer.java
+++ b/core/java/android/net/UrlQuerySanitizer.java
@@ -23,7 +23,7 @@ import java.util.Set;
import java.util.StringTokenizer;
/**
- *
+ *
* Sanitizes the Query portion of a URL. Simple example:
* <code>
* UrlQuerySanitizer sanitizer = new UrlQuerySanitizer();
@@ -32,7 +32,7 @@ import java.util.StringTokenizer;
* String name = sanitizer.getValue("name"));
* // name now contains "Joe_User"
* </code>
- *
+ *
* Register ValueSanitizers to customize the way individual
* parameters are sanitized:
* <code>
@@ -46,7 +46,7 @@ import java.util.StringTokenizer;
* unregistered parameter sanitizer does not allow any special characters,
* and ' ' is a special character.)
* </code>
- *
+ *
* There are several ways to create ValueSanitizers. In order of increasing
* sophistication:
* <ol>
@@ -56,7 +56,7 @@ import java.util.StringTokenizer;
* <li>Subclass UrlQuerySanitizer.ValueSanitizer to define your own value
* sanitizer.
* </ol>
- *
+ *
*/
public class UrlQuerySanitizer {
@@ -84,7 +84,7 @@ public class UrlQuerySanitizer {
*/
public String mValue;
}
-
+
final private HashMap<String, ValueSanitizer> mSanitizers =
new HashMap<String, ValueSanitizer>();
final private HashMap<String, String> mEntries =
@@ -95,9 +95,9 @@ public class UrlQuerySanitizer {
private boolean mPreferFirstRepeatedParameter;
private ValueSanitizer mUnregisteredParameterValueSanitizer =
getAllIllegal();
-
+
/**
- * A functor used to sanitize a single query value.
+ * A functor used to sanitize a single query value.
*
*/
public static interface ValueSanitizer {
@@ -108,7 +108,7 @@ public class UrlQuerySanitizer {
*/
public String sanitize(String value);
}
-
+
/**
* Sanitize values based on which characters they contain. Illegal
* characters are replaced with either space or '_', depending upon
@@ -117,7 +117,7 @@ public class UrlQuerySanitizer {
public static class IllegalCharacterValueSanitizer implements
ValueSanitizer {
private int mFlags;
-
+
/**
* Allow space (' ') characters.
*/
@@ -165,21 +165,21 @@ public class UrlQuerySanitizer {
* such as "javascript:" or "vbscript:"
*/
public final static int SCRIPT_URL_OK = 1 << 10;
-
+
/**
* Mask with all fields set to OK
*/
public final static int ALL_OK = 0x7ff;
-
+
/**
* Mask with both regular space and other whitespace OK
*/
public final static int ALL_WHITESPACE_OK =
SPACE_OK | OTHER_WHITESPACE_OK;
-
+
// Common flag combinations:
-
+
/**
* <ul>
* <li>Deny all special characters.
@@ -262,18 +262,18 @@ public class UrlQuerySanitizer {
*/
public final static int ALL_BUT_NUL_AND_ANGLE_BRACKETS_LEGAL =
ALL_OK & ~(NUL_OK | LT_OK | GT_OK);
-
+
/**
* Script URL definitions
*/
-
+
private final static String JAVASCRIPT_PREFIX = "javascript:";
-
+
private final static String VBSCRIPT_PREFIX = "vbscript:";
-
+
private final static int MIN_SCRIPT_PREFIX_LENGTH = Math.min(
JAVASCRIPT_PREFIX.length(), VBSCRIPT_PREFIX.length());
-
+
/**
* Construct a sanitizer. The parameters set the behavior of the
* sanitizer.
@@ -312,7 +312,7 @@ public class UrlQuerySanitizer {
}
}
}
-
+
// If whitespace isn't OK, get rid of whitespace at beginning
// and end of value.
if ( (mFlags & ALL_WHITESPACE_OK) == 0) {
@@ -337,7 +337,7 @@ public class UrlQuerySanitizer {
}
return stringBuilder.toString();
}
-
+
/**
* Trim whitespace from the beginning and end of a string.
* <p>
@@ -361,7 +361,7 @@ public class UrlQuerySanitizer {
}
return value.substring(start, end + 1);
}
-
+
/**
* Check if c is whitespace.
* @param c character to test
@@ -380,7 +380,7 @@ public class UrlQuerySanitizer {
return false;
}
}
-
+
/**
* Check whether an individual character is legal. Uses the
* flag bit-set passed into the constructor.
@@ -400,11 +400,11 @@ public class UrlQuerySanitizer {
case '%' : return (mFlags & PCT_OK) != 0;
case '\0': return (mFlags & NUL_OK) != 0;
default : return (c >= 32 && c < 127) ||
- (c >= 128 && c <= 255 && ((mFlags & NON_7_BIT_ASCII_OK) != 0));
- }
+ ((c >= 128) && ((mFlags & NON_7_BIT_ASCII_OK) != 0));
+ }
}
}
-
+
/**
* Get the current value sanitizer used when processing
* unregistered parameter values.
@@ -412,14 +412,14 @@ public class UrlQuerySanitizer {
* <b>Note:</b> The default unregistered parameter value sanitizer is
* one that doesn't allow any special characters, similar to what
* is returned by calling createAllIllegal.
- *
+ *
* @return the current ValueSanitizer used to sanitize unregistered
* parameter values.
*/
public ValueSanitizer getUnregisteredParameterValueSanitizer() {
return mUnregisteredParameterValueSanitizer;
}
-
+
/**
* Set the value sanitizer used when processing unregistered
* parameter values.
@@ -430,46 +430,46 @@ public class UrlQuerySanitizer {
ValueSanitizer sanitizer) {
mUnregisteredParameterValueSanitizer = sanitizer;
}
-
-
+
+
// Private fields for singleton sanitizers:
-
+
private static final ValueSanitizer sAllIllegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.ALL_ILLEGAL);
-
+
private static final ValueSanitizer sAllButNulLegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.ALL_BUT_NUL_LEGAL);
-
+
private static final ValueSanitizer sAllButWhitespaceLegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.ALL_BUT_WHITESPACE_LEGAL);
-
+
private static final ValueSanitizer sURLLegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.URL_LEGAL);
-
+
private static final ValueSanitizer sUrlAndSpaceLegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.URL_AND_SPACE_LEGAL);
-
+
private static final ValueSanitizer sAmpLegal =
new IllegalCharacterValueSanitizer(
- IllegalCharacterValueSanitizer.AMP_LEGAL);
-
+ IllegalCharacterValueSanitizer.AMP_LEGAL);
+
private static final ValueSanitizer sAmpAndSpaceLegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.AMP_AND_SPACE_LEGAL);
-
+
private static final ValueSanitizer sSpaceLegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.SPACE_LEGAL);
-
+
private static final ValueSanitizer sAllButNulAndAngleBracketsLegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.ALL_BUT_NUL_AND_ANGLE_BRACKETS_LEGAL);
-
+
/**
* Return a value sanitizer that does not allow any special characters,
* and also does not allow script URLs.
@@ -478,7 +478,7 @@ public class UrlQuerySanitizer {
public static final ValueSanitizer getAllIllegal() {
return sAllIllegal;
}
-
+
/**
* Return a value sanitizer that allows everything except Nul ('\0')
* characters. Script URLs are allowed.
@@ -547,7 +547,7 @@ public class UrlQuerySanitizer {
public static final ValueSanitizer getAllButNulAndAngleBracketsLegal() {
return sAllButNulAndAngleBracketsLegal;
}
-
+
/**
* Constructs a UrlQuerySanitizer.
* <p>
@@ -560,7 +560,7 @@ public class UrlQuerySanitizer {
*/
public UrlQuerySanitizer() {
}
-
+
/**
* Constructs a UrlQuerySanitizer and parse a URL.
* This constructor is provided for convenience when the
@@ -585,7 +585,7 @@ public class UrlQuerySanitizer {
setAllowUnregisteredParamaters(true);
parseUrl(url);
}
-
+
/**
* Parse the query parameters out of an encoded URL.
* Works by extracting the query portion from the URL and then
@@ -604,7 +604,7 @@ public class UrlQuerySanitizer {
}
parseQuery(query);
}
-
+
/**
* Parse a query. A query string is any number of parameter-value clauses
* separated by any non-zero number of ampersands. A parameter-value clause
@@ -631,7 +631,7 @@ public class UrlQuerySanitizer {
}
}
}
-
+
/**
* Get a set of all of the parameters found in the sanitized query.
* <p>
@@ -641,7 +641,7 @@ public class UrlQuerySanitizer {
public Set<String> getParameterSet() {
return mEntries.keySet();
}
-
+
/**
* An array list of all of the parameter value pairs in the sanitized
* query, in the order they appeared in the query. May contain duplicate
@@ -691,7 +691,7 @@ public class UrlQuerySanitizer {
}
mSanitizers.put(parameter, valueSanitizer);
}
-
+
/**
* Register a value sanitizer for an array of parameters.
* @param parameters An array of unencoded parameter names.
@@ -705,7 +705,7 @@ public class UrlQuerySanitizer {
mSanitizers.put(parameters[i], valueSanitizer);
}
}
-
+
/**
* Set whether or not unregistered parameters are allowed. If they
* are not allowed, then they will be dropped when a query is sanitized.
@@ -718,7 +718,7 @@ public class UrlQuerySanitizer {
boolean allowUnregisteredParamaters) {
mAllowUnregisteredParamaters = allowUnregisteredParamaters;
}
-
+
/**
* Get whether or not unregistered parameters are allowed. If not
* allowed, they will be dropped when a query is parsed.
@@ -728,10 +728,10 @@ public class UrlQuerySanitizer {
public boolean getAllowUnregisteredParamaters() {
return mAllowUnregisteredParamaters;
}
-
+
/**
* Set whether or not the first occurrence of a repeated parameter is
- * preferred. True means the first repeated parameter is preferred.
+ * preferred. True means the first repeated parameter is preferred.
* False means that the last repeated parameter is preferred.
* <p>
* The preferred parameter is the one that is returned when getParameter
@@ -746,7 +746,7 @@ public class UrlQuerySanitizer {
boolean preferFirstRepeatedParameter) {
mPreferFirstRepeatedParameter = preferFirstRepeatedParameter;
}
-
+
/**
* Get whether or not the first occurrence of a repeated parameter is
* preferred.
@@ -757,10 +757,10 @@ public class UrlQuerySanitizer {
public boolean getPreferFirstRepeatedParameter() {
return mPreferFirstRepeatedParameter;
}
-
+
/**
* Parse an escaped parameter-value pair. The default implementation
- * unescapes both the parameter and the value, then looks up the
+ * unescapes both the parameter and the value, then looks up the
* effective value sanitizer for the parameter and uses it to sanitize
* the value. If all goes well then addSanitizedValue is called with
* the unescaped parameter and the sanitized unescaped value.
@@ -779,7 +779,7 @@ public class UrlQuerySanitizer {
String sanitizedValue = valueSanitizer.sanitize(unescapedValue);
addSanitizedEntry(unescapedParameter, sanitizedValue);
}
-
+
/**
* Record a sanitized parameter-value pair. Override if you want to
* do additional filtering or validation.
@@ -796,7 +796,7 @@ public class UrlQuerySanitizer {
}
mEntries.put(parameter, value);
}
-
+
/**
* Get the value sanitizer for a parameter. Returns null if there
* is no value sanitizer registered for the parameter.
@@ -807,7 +807,7 @@ public class UrlQuerySanitizer {
public ValueSanitizer getValueSanitizer(String parameter) {
return mSanitizers.get(parameter);
}
-
+
/**
* Get the effective value sanitizer for a parameter. Like getValueSanitizer,
* except if there is no value sanitizer registered for a parameter, and
@@ -823,7 +823,7 @@ public class UrlQuerySanitizer {
}
return sanitizer;
}
-
+
/**
* Unescape an escaped string.
* <ul>
@@ -867,7 +867,7 @@ public class UrlQuerySanitizer {
}
return stringBuilder.toString();
}
-
+
/**
* Test if a character is a hexidecimal digit. Both upper case and lower
* case hex digits are allowed.
@@ -877,7 +877,7 @@ public class UrlQuerySanitizer {
protected boolean isHexDigit(char c) {
return decodeHexDigit(c) >= 0;
}
-
+
/**
* Convert a character that represents a hexidecimal digit into an integer.
* If the character is not a hexidecimal digit, then -1 is returned.
@@ -885,7 +885,7 @@ public class UrlQuerySanitizer {
* @param c the hexidecimal digit.
* @return the integer value of the hexidecimal digit.
*/
-
+
protected int decodeHexDigit(char c) {
if (c >= '0' && c <= '9') {
return c - '0';
@@ -900,7 +900,7 @@ public class UrlQuerySanitizer {
return -1;
}
}
-
+
/**
* Clear the existing entries. Called to get ready to parse a new
* query string.
diff --git a/core/java/android/net/http/AndroidHttpClient.java b/core/java/android/net/http/AndroidHttpClient.java
index 01442ae..c2013d5 100644
--- a/core/java/android/net/http/AndroidHttpClient.java
+++ b/core/java/android/net/http/AndroidHttpClient.java
@@ -26,7 +26,6 @@ import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.entity.AbstractHttpEntity;
import org.apache.http.entity.ByteArrayEntity;
-import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.ClientProtocolException;
@@ -48,6 +47,8 @@ import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.BasicHttpContext;
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
+import org.apache.harmony.xnet.provider.jsse.SSLContextImpl;
import java.io.IOException;
import java.io.InputStream;
@@ -56,12 +57,13 @@ import java.io.OutputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.net.URI;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.security.KeyManagementException;
import android.util.Log;
import android.content.ContentResolver;
import android.provider.Settings;
import android.text.TextUtils;
+import android.os.SystemProperties;
/**
* Subclass of the Apache {@link DefaultHttpClient} that is configured with
@@ -100,10 +102,13 @@ public final class AndroidHttpClient implements HttpClient {
/**
* Create a new HttpClient with reasonable defaults (which you can update).
+ *
* @param userAgent to report in your HTTP requests.
+ * @param sessionCache persistent session cache
* @return AndroidHttpClient for you to use for all your requests.
*/
- public static AndroidHttpClient newInstance(String userAgent) {
+ public static AndroidHttpClient newInstance(String userAgent,
+ SSLClientSessionCache sessionCache) {
HttpParams params = new BasicHttpParams();
// Turn off stale checking. Our connections break all the time anyway,
@@ -125,7 +130,8 @@ public final class AndroidHttpClient implements HttpClient {
schemeRegistry.register(new Scheme("http",
PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https",
- SSLSocketFactory.getSocketFactory(), 443));
+ socketFactoryWithCache(sessionCache), 443));
+
ClientConnectionManager manager =
new ThreadSafeClientConnManager(params, schemeRegistry);
@@ -134,6 +140,41 @@ public final class AndroidHttpClient implements HttpClient {
return new AndroidHttpClient(manager, params);
}
+ /**
+ * Returns a socket factory backed by the given persistent session cache.
+ *
+ * @param sessionCache to retrieve sessions from, null for no cache
+ */
+ private static SSLSocketFactory socketFactoryWithCache(
+ SSLClientSessionCache sessionCache) {
+ if (sessionCache == null) {
+ // Use the default factory which doesn't support persistent
+ // caching.
+ return SSLSocketFactory.getSocketFactory();
+ }
+
+ // Create a new SSL context backed by the cache.
+ // TODO: Keep a weak *identity* hash map of caches to engines. In the
+ // mean time, if we have two engines for the same cache, they'll still
+ // share sessions but will have to do so through the persistent cache.
+ SSLContextImpl sslContext = new SSLContextImpl();
+ try {
+ sslContext.engineInit(null, null, null, sessionCache, null);
+ } catch (KeyManagementException e) {
+ throw new AssertionError(e);
+ }
+ return new SSLSocketFactory(sslContext.engineGetSocketFactory());
+ }
+
+ /**
+ * Create a new HttpClient with reasonable defaults (which you can update).
+ * @param userAgent to report in your HTTP requests.
+ * @return AndroidHttpClient for you to use for all your requests.
+ */
+ public static AndroidHttpClient newInstance(String userAgent) {
+ return newInstance(userAgent, null /* session cache */);
+ }
+
private final HttpClient delegate;
private RuntimeException mLeakedException = new IllegalStateException(
@@ -347,6 +388,15 @@ public final class AndroidHttpClient implements HttpClient {
}
/**
+ * Returns true if auth logging is turned on for this configuration. Can only be set on
+ * insecure devices.
+ */
+ private boolean isAuthLoggable() {
+ String secure = SystemProperties.get("ro.secure");
+ return "0".equals(secure) && Log.isLoggable(tag + "-auth", level);
+ }
+
+ /**
* Prints a message using this configuration.
*/
private void println(String message) {
@@ -392,7 +442,8 @@ public final class AndroidHttpClient implements HttpClient {
if (configuration != null
&& configuration.isLoggable()
&& request instanceof HttpUriRequest) {
- configuration.println(toCurl((HttpUriRequest) request));
+ configuration.println(toCurl((HttpUriRequest) request,
+ configuration.isAuthLoggable()));
}
}
}
@@ -400,12 +451,17 @@ public final class AndroidHttpClient implements HttpClient {
/**
* Generates a cURL command equivalent to the given request.
*/
- private static String toCurl(HttpUriRequest request) throws IOException {
+ private static String toCurl(HttpUriRequest request, boolean logAuthToken) throws IOException {
StringBuilder builder = new StringBuilder();
builder.append("curl ");
for (Header header: request.getAllHeaders()) {
+ if (!logAuthToken
+ && (header.getName().equals("Authorization") ||
+ header.getName().equals("Cookie"))) {
+ continue;
+ }
builder.append("--header \"");
builder.append(header.toString().trim());
builder.append("\" ");
diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java
index b7f7368..0edbe5b 100644
--- a/core/java/android/net/http/CertificateChainValidator.java
+++ b/core/java/android/net/http/CertificateChainValidator.java
@@ -16,8 +16,6 @@
package android.net.http;
-import android.os.SystemClock;
-
import java.io.IOException;
import java.security.cert.Certificate;
@@ -28,23 +26,13 @@ import java.security.cert.X509Certificate;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.Enumeration;
-
-import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
-import org.apache.http.HttpHost;
-
-import org.bouncycastle.asn1.x509.X509Name;
-
/**
* Class responsible for all server certificate validation functionality
*
@@ -52,9 +40,6 @@ import org.bouncycastle.asn1.x509.X509Name;
*/
class CertificateChainValidator {
- private static long sTotal = 0;
- private static long sTotalReused = 0;
-
/**
* The singleton instance of the certificate chain validator
*/
@@ -110,91 +95,42 @@ class CertificateChainValidator {
* @return An SSL error object if there is an error and null otherwise
*/
public SslError doHandshakeAndValidateServerCertificates(
- HttpsConnection connection, SSLSocket sslSocket, String domain)
- throws SSLHandshakeException, IOException {
-
- ++sTotal;
-
- SSLContext sslContext = HttpsConnection.getContext();
- if (sslContext == null) {
- closeSocketThrowException(sslSocket, "SSL context is null");
- }
-
+ HttpsConnection connection, SSLSocket sslSocket, String domain)
+ throws IOException {
X509Certificate[] serverCertificates = null;
- long sessionBeforeHandshakeLastAccessedTime = 0;
- byte[] sessionBeforeHandshakeId = null;
-
- SSLSession sessionAfterHandshake = null;
-
- synchronized(sslContext) {
- // get SSL session before the handshake
- SSLSession sessionBeforeHandshake =
- getSSLSession(sslContext, connection.getHost());
- if (sessionBeforeHandshake != null) {
- sessionBeforeHandshakeLastAccessedTime =
- sessionBeforeHandshake.getLastAccessedTime();
+ // start handshake, close the socket if we fail
+ try {
+ sslSocket.setUseClientMode(true);
+ sslSocket.startHandshake();
+ } catch (IOException e) {
+ closeSocketThrowException(
+ sslSocket, e.getMessage(),
+ "failed to perform SSL handshake");
+ }
- sessionBeforeHandshakeId =
- sessionBeforeHandshake.getId();
- }
+ // retrieve the chain of the server peer certificates
+ Certificate[] peerCertificates =
+ sslSocket.getSession().getPeerCertificates();
- // start handshake, close the socket if we fail
- try {
- sslSocket.setUseClientMode(true);
- sslSocket.startHandshake();
- } catch (IOException e) {
- closeSocketThrowException(
- sslSocket, e.getMessage(),
- "failed to perform SSL handshake");
+ if (peerCertificates == null || peerCertificates.length <= 0) {
+ closeSocketThrowException(
+ sslSocket, "failed to retrieve peer certificates");
+ } else {
+ serverCertificates =
+ new X509Certificate[peerCertificates.length];
+ for (int i = 0; i < peerCertificates.length; ++i) {
+ serverCertificates[i] =
+ (X509Certificate)(peerCertificates[i]);
}
- // retrieve the chain of the server peer certificates
- Certificate[] peerCertificates =
- sslSocket.getSession().getPeerCertificates();
-
- if (peerCertificates == null || peerCertificates.length <= 0) {
- closeSocketThrowException(
- sslSocket, "failed to retrieve peer certificates");
- } else {
- serverCertificates =
- new X509Certificate[peerCertificates.length];
- for (int i = 0; i < peerCertificates.length; ++i) {
- serverCertificates[i] =
- (X509Certificate)(peerCertificates[i]);
- }
-
- // update the SSL certificate associated with the connection
- if (connection != null) {
- if (serverCertificates[0] != null) {
- connection.setCertificate(
- new SslCertificate(serverCertificates[0]));
- }
+ // update the SSL certificate associated with the connection
+ if (connection != null) {
+ if (serverCertificates[0] != null) {
+ connection.setCertificate(
+ new SslCertificate(serverCertificates[0]));
}
}
-
- // get SSL session after the handshake
- sessionAfterHandshake =
- getSSLSession(sslContext, connection.getHost());
- }
-
- if (sessionBeforeHandshakeLastAccessedTime != 0 &&
- sessionAfterHandshake != null &&
- Arrays.equals(
- sessionBeforeHandshakeId, sessionAfterHandshake.getId()) &&
- sessionBeforeHandshakeLastAccessedTime <
- sessionAfterHandshake.getLastAccessedTime()) {
-
- if (HttpLog.LOGV) {
- HttpLog.v("SSL session was reused: total reused: "
- + sTotalReused
- + " out of total of: " + sTotal);
-
- ++sTotalReused;
- }
-
- // no errors!!!
- return null;
}
// check if the first certificate in the chain is for this site
@@ -216,7 +152,6 @@ class CertificateChainValidator {
}
}
- //
// first, we validate the chain using the standard validation
// solution; if we do not find any errors, we are done; if we
// fail the standard validation, we re-validate again below,
@@ -393,14 +328,14 @@ class CertificateChainValidator {
}
private void closeSocketThrowException(
- SSLSocket socket, String errorMessage, String defaultErrorMessage)
- throws SSLHandshakeException, IOException {
+ SSLSocket socket, String errorMessage, String defaultErrorMessage)
+ throws IOException {
closeSocketThrowException(
socket, errorMessage != null ? errorMessage : defaultErrorMessage);
}
- private void closeSocketThrowException(SSLSocket socket, String errorMessage)
- throws SSLHandshakeException, IOException {
+ private void closeSocketThrowException(SSLSocket socket,
+ String errorMessage) throws IOException {
if (HttpLog.LOGV) {
HttpLog.v("validation error: " + errorMessage);
}
@@ -416,29 +351,4 @@ class CertificateChainValidator {
throw new SSLHandshakeException(errorMessage);
}
-
- /**
- * @param sslContext The SSL context shared accross all the SSL sessions
- * @param host The host associated with the session
- * @return A suitable SSL session from the SSL context
- */
- private SSLSession getSSLSession(SSLContext sslContext, HttpHost host) {
- if (sslContext != null && host != null) {
- Enumeration en = sslContext.getClientSessionContext().getIds();
- while (en.hasMoreElements()) {
- byte[] id = (byte[]) en.nextElement();
- if (id != null) {
- SSLSession session =
- sslContext.getClientSessionContext().getSession(id);
- if (session.isValid() &&
- host.getHostName().equals(session.getPeerHost()) &&
- host.getPort() == session.getPeerPort()) {
- return session;
- }
- }
- }
- }
-
- return null;
- }
}
diff --git a/core/java/android/net/http/RequestHandle.java b/core/java/android/net/http/RequestHandle.java
index 65e6117..c4ee5b0 100644
--- a/core/java/android/net/http/RequestHandle.java
+++ b/core/java/android/net/http/RequestHandle.java
@@ -55,7 +55,7 @@ public class RequestHandle {
private final static String AUTHORIZATION_HEADER = "Authorization";
private final static String PROXY_AUTHORIZATION_HEADER = "Proxy-Authorization";
- private final static int MAX_REDIRECT_COUNT = 16;
+ public final static int MAX_REDIRECT_COUNT = 16;
/**
* Creates a new request session.
@@ -106,6 +106,14 @@ public class RequestHandle {
return mRedirectCount >= MAX_REDIRECT_COUNT;
}
+ public int getRedirectCount() {
+ return mRedirectCount;
+ }
+
+ public void setRedirectCount(int count) {
+ mRedirectCount = count;
+ }
+
/**
* Create and queue a redirect request.
*