summaryrefslogtreecommitdiffstats
path: root/support
diff options
context:
space:
mode:
Diffstat (limited to 'support')
-rw-r--r--support/src/test/java/libcore/net/http/HttpResponseCache.java300
-rw-r--r--support/src/test/java/tests/http/MockWebServer.java20
-rw-r--r--support/src/test/java/tests/http/SocketPolicy.java6
-rw-r--r--support/src/test/java/tests/io/MockOs.java120
-rw-r--r--support/src/test/java/tests/net/StuckServer.java18
-rw-r--r--support/src/test/java/tests/support/Support_Configuration.java51
6 files changed, 162 insertions, 353 deletions
diff --git a/support/src/test/java/libcore/net/http/HttpResponseCache.java b/support/src/test/java/libcore/net/http/HttpResponseCache.java
deleted file mode 100644
index a551e27..0000000
--- a/support/src/test/java/libcore/net/http/HttpResponseCache.java
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package libcore.net.http;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.CacheRequest;
-import java.net.CacheResponse;
-import java.net.HttpURLConnection;
-import java.net.ResponseCache;
-import java.net.SecureCacheResponse;
-import java.net.URI;
-import java.net.URLConnection;
-import java.security.Principal;
-import java.security.cert.Certificate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLPeerUnverifiedException;
-
-/**
- * Cache all responses in memory by URI.
- *
- * TODO: disk storage, tuning knobs, LRU
- * TODO: move this class to android.util
- */
-public final class HttpResponseCache extends ResponseCache {
- private final Map<URI, Entry> entries = new HashMap<URI, Entry>();
- private int abortCount;
- private int successCount;
- private int hitCount;
- private int missCount;
-
- @Override public synchronized CacheResponse get(URI uri, String requestMethod,
- Map<String, List<String>> requestHeaders) throws IOException {
- Entry entry = entries.get(uri);
- if (entry == null) {
- missCount++;
- return null;
- }
-
- if (!requestMethod.equals(entry.requestMethod)) {
- return null;
- }
-
- // RawHeaders headers = RawHeaders.fromMultimap(entry.responseHeaders);
-
- hitCount++;
- return entry.asResponse();
- }
-
- @Override public CacheRequest put(URI uri, URLConnection urlConnection)
- throws IOException {
- if (!(urlConnection instanceof HttpURLConnection)) {
- return null;
- }
-
- HttpURLConnection httpConnection = (HttpURLConnection) urlConnection;
- String requestMethod = httpConnection.getRequestMethod();
-
- // Invalidate the cache on POST, PUT and DELETE.
- if (requestMethod.equals("POST") || requestMethod.equals("PUT")
- || requestMethod.equals("DELETE")) {
- entries.remove(uri);
- }
-
- /*
- * Don't cache non-GET responses. We're technically allowed to cache
- * HEAD requests and some POST requests, but the complexity of doing so
- * is high and the benefit is low.
- */
- if (!requestMethod.equals("GET")) {
- return null;
- }
-
- // For implementation simplicity, don't cache responses that have a Vary field.
- if (httpConnection.getHeaderField("Vary") != null) {
- return null;
- }
-
- return new Entry(uri, httpConnection).asRequest();
- }
-
- public synchronized Map<URI, Entry> getContents() {
- return new HashMap<URI, Entry>(entries);
- }
-
- /**
- * Returns the number of requests that were aborted before they were closed.
- */
- public synchronized int getAbortCount() {
- return abortCount;
- }
-
- /**
- * Returns the number of requests that were closed successfully.
- */
- public synchronized int getSuccessCount() {
- return successCount;
- }
-
- /**
- * Returns the number of responses served by the cache.
- */
- public synchronized int getHitCount() {
- return hitCount;
- }
-
- /**
- * Returns the number of responses that couldn't be served by the cache.
- */
- public synchronized int getMissCount() {
- return missCount;
- }
-
- public final class Entry {
- private final ByteArrayOutputStream body = new ByteArrayOutputStream() {
- private boolean closed;
- @Override public void close() throws IOException {
- synchronized (HttpResponseCache.this) {
- if (closed) {
- return;
- }
-
- super.close();
- entries.put(uri, Entry.this);
- successCount++;
- closed = true;
- }
- }
- };
-
- private final String requestMethod;
- private final Map<String, List<String>> responseHeaders;
- private final URI uri;
- private final CacheResponse cacheResponse;
-
- private Entry(URI uri, HttpURLConnection connection) {
- this.uri = uri;
- this.requestMethod = connection.getRequestMethod();
- this.responseHeaders = deepCopy(connection.getHeaderFields());
- this.cacheResponse = connection instanceof HttpsURLConnection
- ? new SecureCacheResponseImpl(responseHeaders, body,
- (HttpsURLConnection) connection)
- : new CacheResponseImpl(responseHeaders, body);
- }
-
- public CacheRequest asRequest() {
- return new CacheRequest() {
- private boolean aborted;
- @Override public void abort() {
- synchronized (HttpResponseCache.this) {
- if (aborted) {
- return;
- }
-
- abortCount++;
- aborted = true;
- }
- }
- @Override public OutputStream getBody() throws IOException {
- return body;
- }
- };
- }
-
- public CacheResponse asResponse() {
- return cacheResponse;
- }
-
- public byte[] getBytes() {
- return body.toByteArray();
- }
- }
-
- private final class CacheResponseImpl extends CacheResponse {
- private final Map<String, List<String>> headers;
- private final ByteArrayOutputStream bytesOut;
-
- public CacheResponseImpl(Map<String, List<String>> headers,
- ByteArrayOutputStream bytesOut) {
- this.headers = headers;
- this.bytesOut = bytesOut;
- }
-
- @Override public Map<String, List<String>> getHeaders() {
- return deepCopy(headers);
- }
-
- @Override public InputStream getBody() {
- return new ByteArrayInputStream(bytesOut.toByteArray());
- }
- }
-
- private final class SecureCacheResponseImpl extends SecureCacheResponse {
- private final Map<String, List<String>> headers;
- private final ByteArrayOutputStream bytesOut;
- private final String cipherSuite;
- private final Certificate[] localCertificates;
- private final List<Certificate> serverCertificates;
- private final Principal peerPrincipal;
- private final Principal localPrincipal;
-
- public SecureCacheResponseImpl(Map<String, List<String>> headers,
- ByteArrayOutputStream bytesOut,
- HttpsURLConnection httpsConnection) {
- this.headers = headers;
- this.bytesOut = bytesOut;
-
- /*
- * Retrieve the fields eagerly to avoid needing a strong
- * reference to the connection. We do acrobatics for the two
- * methods that can throw so that the cache response also
- * throws.
- */
- List<Certificate> serverCertificatesNonFinal = null;
- try {
- serverCertificatesNonFinal = Arrays.asList(
- httpsConnection.getServerCertificates());
- } catch (SSLPeerUnverifiedException ignored) {
- }
- Principal peerPrincipalNonFinal = null;
- try {
- peerPrincipalNonFinal = httpsConnection.getPeerPrincipal();
- } catch (SSLPeerUnverifiedException ignored) {
- }
- this.cipherSuite = httpsConnection.getCipherSuite();
- this.localCertificates = httpsConnection.getLocalCertificates();
- this.serverCertificates = serverCertificatesNonFinal;
- this.peerPrincipal = peerPrincipalNonFinal;
- this.localPrincipal = httpsConnection.getLocalPrincipal();
- }
-
- @Override public Map<String, List<String>> getHeaders() {
- return deepCopy(headers);
- }
-
- @Override public InputStream getBody() {
- return new ByteArrayInputStream(bytesOut.toByteArray());
- }
-
- @Override public String getCipherSuite() {
- return cipherSuite;
- }
-
- @Override public List<Certificate> getLocalCertificateChain() {
- return localCertificates != null
- ? Arrays.asList(localCertificates.clone())
- : null;
- }
-
- @Override public List<Certificate> getServerCertificateChain()
- throws SSLPeerUnverifiedException {
- if (serverCertificates == null) {
- throw new SSLPeerUnverifiedException(null);
- }
- return new ArrayList<Certificate>(serverCertificates);
- }
-
- @Override public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
- if (peerPrincipal == null) {
- throw new SSLPeerUnverifiedException(null);
- }
- return peerPrincipal;
- }
-
- @Override public Principal getLocalPrincipal() {
- return localPrincipal;
- }
- }
-
- private static Map<String, List<String>> deepCopy(Map<String, List<String>> input) {
- Map<String, List<String>> result = new LinkedHashMap<String, List<String>>(input);
- for (Map.Entry<String, List<String>> entry : result.entrySet()) {
- entry.setValue(new ArrayList<String>(entry.getValue()));
- }
- return result;
- }
-}
diff --git a/support/src/test/java/tests/http/MockWebServer.java b/support/src/test/java/tests/http/MockWebServer.java
index 2d8215c..a130dde 100644
--- a/support/src/test/java/tests/http/MockWebServer.java
+++ b/support/src/test/java/tests/http/MockWebServer.java
@@ -251,9 +251,7 @@ public final class MockWebServer {
Socket socket;
if (sslSocketFactory != null) {
if (tunnelProxy) {
- if (!processOneRequest(raw.getInputStream(), raw.getOutputStream(), raw)) {
- throw new IllegalStateException("Tunnel without any CONNECT!");
- }
+ createTunnel();
}
socket = sslSocketFactory.createSocket(
raw, raw.getInetAddress().getHostAddress(), raw.getPort(), true);
@@ -283,6 +281,22 @@ public final class MockWebServer {
}
/**
+ * Respond to CONNECT requests until a SWITCH_TO_SSL_AT_END response
+ * is dispatched.
+ */
+ private void createTunnel() throws IOException, InterruptedException {
+ while (true) {
+ MockResponse connect = responseQueue.peek();
+ if (!processOneRequest(raw.getInputStream(), raw.getOutputStream(), raw)) {
+ throw new IllegalStateException("Tunnel without any CONNECT!");
+ }
+ if (connect.getSocketPolicy() == SocketPolicy.UPGRADE_TO_SSL_AT_END) {
+ return;
+ }
+ }
+ }
+
+ /**
* Reads a request and writes its response. Returns true if a request
* was processed.
*/
diff --git a/support/src/test/java/tests/http/SocketPolicy.java b/support/src/test/java/tests/http/SocketPolicy.java
index 549c65d..820b400 100644
--- a/support/src/test/java/tests/http/SocketPolicy.java
+++ b/support/src/test/java/tests/http/SocketPolicy.java
@@ -34,6 +34,12 @@ public enum SocketPolicy {
DISCONNECT_AT_END,
/**
+ * Wrap the socket with SSL at the completion of this request/response
+ * pair. Used for CONNECT messages to tunnel SSL over an HTTP proxy.
+ */
+ UPGRADE_TO_SSL_AT_END,
+
+ /**
* Request immediate close of connection without even reading the
* request.
*
diff --git a/support/src/test/java/tests/io/MockOs.java b/support/src/test/java/tests/io/MockOs.java
new file mode 100644
index 0000000..0cfe836
--- /dev/null
+++ b/support/src/test/java/tests/io/MockOs.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.io;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Map;
+import libcore.io.ErrnoException;
+import libcore.io.Libcore;
+import libcore.io.Os;
+import libcore.io.OsConstants;
+
+/**
+ * A mocking interceptor that wraps another {@link Os} to add faults. This can
+ * be useful to test otherwise hard-to-test scenarios such as a full disk.
+ */
+public final class MockOs {
+ private final InheritableThreadLocal<Map<String, Deque<InvocationHandler>>> handlers
+ = new InheritableThreadLocal<Map<String, Deque<InvocationHandler>>>() {
+ @Override protected Map<String, Deque<InvocationHandler>> initialValue() {
+ return new HashMap<String, Deque<InvocationHandler>>();
+ }
+ };
+
+ private Os delegate;
+ private final InvocationHandler delegateHandler = new InvocationHandler() {
+ @Override public Object invoke(Object o, Method method, Object[] args) throws Throwable {
+ try {
+ return method.invoke(delegate, args);
+ } catch (InvocationTargetException e) {
+ throw e.getCause();
+ }
+ }
+ };
+
+ private final InvocationHandler invocationHandler = new InvocationHandler() {
+ @Override public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable {
+ InvocationHandler handler = getHandlers(method.getName()).poll();
+ if (handler == null) {
+ handler = delegateHandler;
+ }
+ return handler.invoke(proxy, method, args);
+ }
+ };
+
+ private final Os mockOs = (Os) Proxy.newProxyInstance(MockOs.class.getClassLoader(),
+ new Class[] { Os.class }, invocationHandler);
+
+ public void install() {
+ if (delegate != null) {
+ throw new IllegalStateException("MockOs already installed!");
+ }
+ delegate = Libcore.os;
+ Libcore.os = mockOs;
+ }
+
+ public void uninstall() {
+ if (delegate == null) {
+ throw new IllegalStateException("MockOs not installed!");
+ }
+ Libcore.os = delegate;
+ }
+
+ /**
+ * Returns the invocation handlers to handle upcoming invocations of
+ * {@code methodName}. If empty, calls will be handled by the delegate.
+ */
+ public Deque<InvocationHandler> getHandlers(String methodName) {
+ Map<String, Deque<InvocationHandler>> threadFaults = handlers.get();
+ Deque<InvocationHandler> result = threadFaults.get(methodName);
+ if (result == null) {
+ result = new ArrayDeque<InvocationHandler>();
+ threadFaults.put(methodName, result);
+ }
+ return result;
+ }
+
+ /**
+ * Enqueues the specified number of normal operations. Useful to delay
+ * faults.
+ */
+ public void enqueueNormal(String methodName, int count) {
+ Deque<InvocationHandler> handlers = getHandlers(methodName);
+ for (int i = 0; i < count; i++) {
+ handlers.add(delegateHandler);
+ }
+ }
+
+ public void enqueueFault(String methodName) {
+ enqueueFault(methodName, OsConstants.EIO);
+ }
+
+ public void enqueueFault(String methodName, final int errno) {
+ getHandlers(methodName).add(new InvocationHandler() {
+ @Override public Object invoke(Object proxy, Method method, Object[] args) {
+ throw new ErrnoException(method.getName(), errno);
+ }
+ });
+ }
+}
diff --git a/support/src/test/java/tests/net/StuckServer.java b/support/src/test/java/tests/net/StuckServer.java
index 4230f17..eababce 100644
--- a/support/src/test/java/tests/net/StuckServer.java
+++ b/support/src/test/java/tests/net/StuckServer.java
@@ -40,6 +40,24 @@ public final class StuckServer {
}
}
+ public void unblockAfterMs(final int ms) {
+ Thread t = new Thread(new Runnable() {
+ @Override public void run() {
+ try {
+ Thread.sleep(ms);
+ for (Socket client : clients) {
+ client.close();
+ }
+ clients.clear();
+ clients.add(serverSocket.accept());
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ });
+ t.start();
+ }
+
public InetSocketAddress getLocalSocketAddress() {
return (InetSocketAddress) serverSocket.getLocalSocketAddress();
}
diff --git a/support/src/test/java/tests/support/Support_Configuration.java b/support/src/test/java/tests/support/Support_Configuration.java
index fb5b468..fed0bc8 100644
--- a/support/src/test/java/tests/support/Support_Configuration.java
+++ b/support/src/test/java/tests/support/Support_Configuration.java
@@ -46,8 +46,6 @@ public class Support_Configuration {
public static String HomeAddressSoftware = "Jetty(6.0.x)";
- public static String ProxyServerTestHost = "jcltest.apache.org";
-
public static String SocksServerTestHost = "jcltest.apache.org";
public static int SocksServerTestPort = 1080;
@@ -75,15 +73,7 @@ public class Support_Configuration {
public static byte[] InetTestCaddr = { 9, 26, -56, -111 };
- public static final String HomeAddress6 = "jcltest6.apache.org";
-
- public static String IPv6GlobalAddressJcl4 = "FE80:0000:0000:0000:020D:60FF:FE0F:A776%4"; // this
-
- public static String ProxyServerTestHostIPv6 = "jcltest6.apache.org";
-
- public static String InetTestIP6 = "fe80::20d:60ff:fe24:7410";
-
- public static String InetTestIP6LO = "::1";
+ public static String IPv6GlobalAddressJcl4 = "2001:4860:8004::67"; // ipv6.google.com
// ip address that resolves to a host that is not present on the local
// network
@@ -131,12 +121,6 @@ public class Support_Configuration {
public static long URLConnectionDate = 929106872000L;
- public static boolean RunCommTests = false;
-
- public static String Port1 = "COM1";
-
- public static String Port2 = "COM2";
-
static Hashtable<String, String> props = null;
static {
loadProperties();
@@ -149,9 +133,6 @@ public class Support_Configuration {
Hashtable<String, String> props = new Hashtable<String, String>();
String iniName = System.getProperty("test.ini.file", "JCLAuto.ini");
- if (System.getProperty("test.comm") != null) {
- RunCommTests = true;
- }
try {
in = new FileInputStream(iniName);
@@ -204,11 +185,6 @@ public class Support_Configuration {
HomeAddressSoftware = value;
}
- value = props.get("ProxyServerTestHost");
- if (value != null) {
- ProxyServerTestHost = value;
- }
-
value = props.get("SocksServerTestHost");
if (value != null) {
SocksServerTestHost = value;
@@ -313,31 +289,6 @@ public class Support_Configuration {
URLConnectionDate = Long.parseLong(value);
}
- value = props.get("Port1");
- if (value != null) {
- Port1 = value;
- }
-
- value = props.get("Port2");
- if (value != null) {
- Port2 = value;
- }
-
- value = props.get("InetTestIP6");
- if (value != null) {
- InetTestIP6 = value;
- }
-
- value = props.get("InetTestIP6LO");
- if (value != null) {
- InetTestIP6LO = value;
- }
-
- value = props.get("ProxyServerTestHostIPv6");
- if (value != null) {
- ProxyServerTestHostIPv6 = value;
- }
-
value = props.get("ResolvedNotExistingHost");
if (value != null) {
ResolvedNotExistingHost = value;