aboutsummaryrefslogtreecommitdiff
path: root/mockwebserver
diff options
context:
space:
mode:
authorNeil Fuller <nfuller@google.com>2015-04-13 13:06:22 +0100
committerNeil Fuller <nfuller@google.com>2015-04-16 11:44:31 +0100
commita2cab72aa5ff730ba2ae987b45398faafffeb505 (patch)
tree283de306182e8f1faff93d4e6515298539d8c21d /mockwebserver
parent9fa0698523b8a573b8862c0e62c533be8bd53bda (diff)
downloadokhttp-a2cab72aa5ff730ba2ae987b45398faafffeb505.tar.gz
Roll-up of upstream OkHttp and Okio changes
OkHttp: From b609edd07864d7191dcda8ba1f6c833c9fe170ad to b40f99a950cb407eff52537a97420bd253a64f63 Okio: From 654ddf5e8f6311fda77e429c22d5e0e15f713b8d to b5811711b141b230e4e58f577c79cfbf4c2d4028 Both "to" are head as of 20150413. Patches applied cleanly without conflicts. This submission will break some CTS tests due to https://github.com/square/okhttp/issues/1552 Solutions will be made upstream and patched in. The CTS tests broken are related to SPDY/HTTP2 which are not used by Android's embedded OkHttp. Change-Id: I84d55b6f5c8dbc05148e86bd9421a2c393b563d4
Diffstat (limited to 'mockwebserver')
-rw-r--r--mockwebserver/README.md20
-rw-r--r--mockwebserver/pom.xml7
-rw-r--r--mockwebserver/src/main/java/com/squareup/okhttp/internal/SslContextBuilder.java2
-rw-r--r--mockwebserver/src/main/java/com/squareup/okhttp/internal/spdy/SpdyServer.java110
-rw-r--r--mockwebserver/src/main/java/com/squareup/okhttp/mockwebserver/MockResponse.java4
-rw-r--r--mockwebserver/src/main/java/com/squareup/okhttp/mockwebserver/MockWebServer.java35
-rw-r--r--mockwebserver/src/test/java/com/squareup/okhttp/mockwebserver/MockWebServerTest.java15
7 files changed, 133 insertions, 60 deletions
diff --git a/mockwebserver/README.md b/mockwebserver/README.md
index c729668..eb698c3 100644
--- a/mockwebserver/README.md
+++ b/mockwebserver/README.md
@@ -116,6 +116,26 @@ assertEquals("{}", request.getUtf8Body());
By default MockWebServer uses a queue to specify a series of responses. Use a
Dispatcher to handle requests using another policy. One natural policy is to
dispatch on the request path.
+You can, for example, filter the request instead of using `server.enqueue()`.
+
+```java
+final Dispatcher dispatcher = new Dispatcher() {
+
+ @Override
+ public MockResponse dispatch(RecordedRequest request) throws InterruptedException {
+
+ if (request.getPath().equals("/v1/login/auth/")){
+ return new MockResponse().setResponseCode(200));
+ } else if (request.getPath().equals("v1/check/version/")){
+ return new MockResponse().setResponseCode(200).setBody("version=9");
+ } else if (request.getPath().equals("/v1/profile/info")) {
+ return new MockResponse().setResponseCode(200).setBody("{\\\"info\\\":{\\\"name\":\"Lucas Albuquerque\",\"age\":\"21\",\"gender\":\"male\"}}");
+ }
+ return new MockResponse().setResponseCode(404);
+ }
+};
+server.setDispatcher(dispatcher);
+```
### Download
diff --git a/mockwebserver/pom.xml b/mockwebserver/pom.xml
index ae3abb5..86d2503 100644
--- a/mockwebserver/pom.xml
+++ b/mockwebserver/pom.xml
@@ -6,7 +6,7 @@
<parent>
<groupId>com.squareup.okhttp</groupId>
<artifactId>parent</artifactId>
- <version>2.3.0-SNAPSHOT</version>
+ <version>2.4.0-SNAPSHOT</version>
</parent>
<artifactId>mockwebserver</artifactId>
@@ -19,6 +19,11 @@
<version>${project.version}</version>
</dependency>
<dependency>
+ <groupId>com.squareup.okhttp</groupId>
+ <artifactId>okhttp-ws</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
diff --git a/mockwebserver/src/main/java/com/squareup/okhttp/internal/SslContextBuilder.java b/mockwebserver/src/main/java/com/squareup/okhttp/internal/SslContextBuilder.java
index 3d61d73..546d660 100644
--- a/mockwebserver/src/main/java/com/squareup/okhttp/internal/SslContextBuilder.java
+++ b/mockwebserver/src/main/java/com/squareup/okhttp/internal/SslContextBuilder.java
@@ -68,7 +68,7 @@ public final class SslContextBuilder {
public static synchronized SSLContext localhost() {
if (localhost == null) {
try {
- localhost = new SslContextBuilder(InetAddress.getByName(null).getHostName()).build();
+ localhost = new SslContextBuilder(InetAddress.getByName("localhost").getHostName()).build();
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
} catch (UnknownHostException e) {
diff --git a/mockwebserver/src/main/java/com/squareup/okhttp/internal/spdy/SpdyServer.java b/mockwebserver/src/main/java/com/squareup/okhttp/internal/spdy/SpdyServer.java
index fb21a08..8e93b47 100644
--- a/mockwebserver/src/main/java/com/squareup/okhttp/internal/spdy/SpdyServer.java
+++ b/mockwebserver/src/main/java/com/squareup/okhttp/internal/spdy/SpdyServer.java
@@ -22,10 +22,13 @@ import com.squareup.okhttp.internal.SslContextBuilder;
import com.squareup.okhttp.internal.Util;
import java.io.File;
import java.io.IOException;
+import java.net.ProtocolException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import okio.BufferedSink;
@@ -34,17 +37,15 @@ import okio.Source;
/** A basic SPDY/HTTP_2 server that serves the contents of a local directory. */
public final class SpdyServer implements IncomingStreamHandler {
+ static final Logger logger = Logger.getLogger(SpdyServer.class.getName());
+
private final List<Protocol> spdyProtocols = Util.immutableList(Protocol.HTTP_2, Protocol.SPDY_3);
private final File baseDirectory;
- private SSLSocketFactory sslSocketFactory;
- private Protocol protocol;
+ private final SSLSocketFactory sslSocketFactory;
- public SpdyServer(File baseDirectory) {
+ public SpdyServer(File baseDirectory, SSLSocketFactory sslSocketFactory) {
this.baseDirectory = baseDirectory;
- }
-
- public void useHttps(SSLSocketFactory sslSocketFactory) {
this.sslSocketFactory = sslSocketFactory;
}
@@ -53,52 +54,67 @@ public final class SpdyServer implements IncomingStreamHandler {
serverSocket.setReuseAddress(true);
while (true) {
- Socket socket = serverSocket.accept();
- if (sslSocketFactory != null) {
- socket = doSsl(socket);
+ Socket socket = null;
+ try {
+ socket = serverSocket.accept();
+
+ SSLSocket sslSocket = doSsl(socket);
+ String protocolString = Platform.get().getSelectedProtocol(sslSocket);
+ Protocol protocol = protocolString != null ? Protocol.get(protocolString) : null;
+ if (protocol == null || !spdyProtocols.contains(protocol)) {
+ throw new ProtocolException("Protocol " + protocol + " unsupported");
+ }
+ SpdyConnection spdyConnection = new SpdyConnection.Builder(false, sslSocket)
+ .protocol(protocol)
+ .handler(this)
+ .build();
+ spdyConnection.sendConnectionPreface();
+ } catch (IOException e) {
+ logger.log(Level.INFO, "SpdyServer connection failure: " + e);
+ Util.closeQuietly(socket);
+ } catch (Exception e) {
+ logger.log(Level.WARNING, "SpdyServer unexpected failure", e);
+ Util.closeQuietly(socket);
}
- new SpdyConnection.Builder(false, socket).protocol(protocol).handler(this).build();
}
}
- private Socket doSsl(Socket socket) throws IOException {
- SSLSocket sslSocket =
- (SSLSocket) sslSocketFactory.createSocket(socket, socket.getInetAddress().getHostAddress(),
- socket.getPort(), true);
+ private SSLSocket doSsl(Socket socket) throws IOException {
+ SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(
+ socket, socket.getInetAddress().getHostAddress(), socket.getPort(), true);
sslSocket.setUseClientMode(false);
Platform.get().configureTlsExtensions(sslSocket, null, spdyProtocols);
sslSocket.startHandshake();
- String protocolString = Platform.get().getSelectedProtocol(sslSocket);
- protocol = protocolString != null ? Protocol.get(protocolString) : null;
- if (protocol == null || !spdyProtocols.contains(protocol)) {
- throw new IllegalStateException("Protocol " + protocol + " unsupported");
- }
return sslSocket;
}
@Override public void receive(final SpdyStream stream) throws IOException {
- List<Header> requestHeaders = stream.getRequestHeaders();
- String path = null;
- for (int i = 0, size = requestHeaders.size(); i < size; i++) {
- if (requestHeaders.get(i).name.equals(Header.TARGET_PATH)) {
- path = requestHeaders.get(i).value.utf8();
- break;
+ try {
+ List<Header> requestHeaders = stream.getRequestHeaders();
+ String path = null;
+ for (int i = 0, size = requestHeaders.size(); i < size; i++) {
+ if (requestHeaders.get(i).name.equals(Header.TARGET_PATH)) {
+ path = requestHeaders.get(i).value.utf8();
+ break;
+ }
}
- }
- if (path == null) {
- // TODO: send bad request error
- throw new AssertionError();
- }
+ if (path == null) {
+ // TODO: send bad request error
+ throw new AssertionError();
+ }
- File file = new File(baseDirectory + path);
+ File file = new File(baseDirectory + path);
- if (file.isDirectory()) {
- serveDirectory(stream, file.list());
- } else if (file.exists()) {
- serveFile(stream, file);
- } else {
- send404(stream, path);
+ if (file.isDirectory()) {
+ serveDirectory(stream, file.listFiles());
+ } else if (file.exists()) {
+ serveFile(stream, file);
+ } else {
+ send404(stream, path);
+ }
+ } catch (IOException e) {
+ System.out.println(e.getMessage());
}
}
@@ -114,7 +130,7 @@ public final class SpdyServer implements IncomingStreamHandler {
out.close();
}
- private void serveDirectory(SpdyStream stream, String[] files) throws IOException {
+ private void serveDirectory(SpdyStream stream, File[] files) throws IOException {
List<Header> responseHeaders = Arrays.asList(
new Header(":status", "200"),
new Header(":version", "HTTP/1.1"),
@@ -122,8 +138,9 @@ public final class SpdyServer implements IncomingStreamHandler {
);
stream.reply(responseHeaders, true);
BufferedSink out = Okio.buffer(stream.getSink());
- for (String file : files) {
- out.writeUtf8("<a href='" + file + "'>" + file + "</a><br>");
+ for (File file : files) {
+ String target = file.isDirectory() ? (file.getName() + "/") : file.getName();
+ out.writeUtf8("<a href='" + target + "'>" + target + "</a><br>");
}
out.close();
}
@@ -146,7 +163,14 @@ public final class SpdyServer implements IncomingStreamHandler {
}
private String contentType(File file) {
- return file.getName().endsWith(".html") ? "text/html" : "text/plain";
+ if (file.getName().endsWith(".css")) return "text/css";
+ if (file.getName().endsWith(".gif")) return "image/gif";
+ if (file.getName().endsWith(".html")) return "text/html";
+ if (file.getName().endsWith(".jpeg")) return "image/jpeg";
+ if (file.getName().endsWith(".jpg")) return "image/jpeg";
+ if (file.getName().endsWith(".js")) return "application/javascript";
+ if (file.getName().endsWith(".png")) return "image/png";
+ return "text/plain";
}
public static void main(String... args) throws Exception {
@@ -155,8 +179,8 @@ public final class SpdyServer implements IncomingStreamHandler {
return;
}
- SpdyServer server = new SpdyServer(new File(args[0]));
- server.useHttps(SslContextBuilder.localhost().getSocketFactory());
+ SpdyServer server = new SpdyServer(new File(args[0]),
+ SslContextBuilder.localhost().getSocketFactory());
server.run();
}
}
diff --git a/mockwebserver/src/main/java/com/squareup/okhttp/mockwebserver/MockResponse.java b/mockwebserver/src/main/java/com/squareup/okhttp/mockwebserver/MockResponse.java
index 8f0ee2c..09dda56 100644
--- a/mockwebserver/src/main/java/com/squareup/okhttp/mockwebserver/MockResponse.java
+++ b/mockwebserver/src/main/java/com/squareup/okhttp/mockwebserver/MockResponse.java
@@ -16,7 +16,7 @@
package com.squareup.okhttp.mockwebserver;
import com.squareup.okhttp.Headers;
-import com.squareup.okhttp.internal.ws.WebSocketListener;
+import com.squareup.okhttp.ws.WebSocketListener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -153,7 +153,7 @@ public final class MockResponse implements Cloneable {
Buffer bytesOut = new Buffer();
while (!body.exhausted()) {
long chunkSize = Math.min(body.size(), maxChunkSize);
- bytesOut.writeUtf8(Long.toHexString(chunkSize));
+ bytesOut.writeHexadecimalUnsignedLong(chunkSize);
bytesOut.writeUtf8("\r\n");
bytesOut.write(body, chunkSize);
bytesOut.writeUtf8("\r\n");
diff --git a/mockwebserver/src/main/java/com/squareup/okhttp/mockwebserver/MockWebServer.java b/mockwebserver/src/main/java/com/squareup/okhttp/mockwebserver/MockWebServer.java
index 39fbf6f..259cf3e 100644
--- a/mockwebserver/src/main/java/com/squareup/okhttp/mockwebserver/MockWebServer.java
+++ b/mockwebserver/src/main/java/com/squareup/okhttp/mockwebserver/MockWebServer.java
@@ -30,8 +30,8 @@ import com.squareup.okhttp.internal.spdy.IncomingStreamHandler;
import com.squareup.okhttp.internal.spdy.SpdyConnection;
import com.squareup.okhttp.internal.spdy.SpdyStream;
import com.squareup.okhttp.internal.ws.RealWebSocket;
-import com.squareup.okhttp.internal.ws.WebSocketListener;
import com.squareup.okhttp.internal.ws.WebSocketProtocol;
+import com.squareup.okhttp.ws.WebSocketListener;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@@ -56,7 +56,9 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
@@ -77,6 +79,7 @@ import okio.Timeout;
import static com.squareup.okhttp.mockwebserver.SocketPolicy.DISCONNECT_AT_START;
import static com.squareup.okhttp.mockwebserver.SocketPolicy.FAIL_HANDSHAKE;
+import static java.util.concurrent.TimeUnit.SECONDS;
/**
* A scriptable web server. Callers supply canned responses and the server
@@ -362,6 +365,8 @@ public final class MockWebServer {
}
public void shutdown() throws IOException {
+ if (serverSocket == null) throw new IllegalStateException("shutdown() before start()");
+
// Cause acceptConnections() to break out.
serverSocket.close();
@@ -472,8 +477,8 @@ public final class MockWebServer {
}
/**
- * Reads a request and writes its response. Returns true if a request was
- * processed.
+ * Reads a request and writes its response. Returns true if further calls should be attempted
+ * on the socket.
*/
private boolean processOneRequest(Socket socket, BufferedSource source, BufferedSink sink)
throws IOException, InterruptedException {
@@ -503,21 +508,19 @@ public final class MockWebServer {
writeHttpResponse(socket, sink, response);
}
+ if (logger.isLoggable(Level.INFO)) {
+ logger.info(MockWebServer.this + " received request: " + request
+ + " and responded: " + response);
+ }
+
if (response.getSocketPolicy() == SocketPolicy.DISCONNECT_AT_END) {
- source.close();
- sink.close();
- // Workaround for bug on Android: closing the input/output streams should close an
- // SSLSocket but does not. https://code.google.com/p/android/issues/detail?id=97564
socket.close();
+ return false;
} else if (response.getSocketPolicy() == SocketPolicy.SHUTDOWN_INPUT_AT_END) {
socket.shutdownInput();
} else if (response.getSocketPolicy() == SocketPolicy.SHUTDOWN_OUTPUT_AT_END) {
socket.shutdownOutput();
}
- if (logger.isLoggable(Level.INFO)) {
- logger.info(
- MockWebServer.this + " received request: " + request + " and responded: " + response);
- }
sequenceNumber++;
return true;
@@ -636,9 +639,15 @@ public final class MockWebServer {
final WebSocketListener listener = response.getWebSocketListener();
final CountDownLatch connectionClose = new CountDownLatch(1);
+
+ ThreadPoolExecutor replyExecutor =
+ new ThreadPoolExecutor(1, 1, 1, SECONDS, new LinkedBlockingDeque<Runnable>(),
+ Util.threadFactory(String.format("MockWebServer %s WebSocket", request.getPath()),
+ true));
+ replyExecutor.allowCoreThreadTimeOut(true);
final RealWebSocket webSocket =
- new RealWebSocket(false, source, sink, new SecureRandom(), listener,
- request.getPath()) {
+ new RealWebSocket(false /* is server */, source, sink, new SecureRandom(), replyExecutor,
+ listener, request.getPath()) {
@Override protected void closeConnection() throws IOException {
connectionClose.countDown();
}
diff --git a/mockwebserver/src/test/java/com/squareup/okhttp/mockwebserver/MockWebServerTest.java b/mockwebserver/src/test/java/com/squareup/okhttp/mockwebserver/MockWebServerTest.java
index 388dbf6..a3816d2 100644
--- a/mockwebserver/src/test/java/com/squareup/okhttp/mockwebserver/MockWebServerTest.java
+++ b/mockwebserver/src/test/java/com/squareup/okhttp/mockwebserver/MockWebServerTest.java
@@ -264,4 +264,19 @@ public final class MockWebServerTest {
}
return headerList;
}
+
+ @Test public void shutdownWithoutStart() throws IOException {
+ MockWebServer server = new MockWebServer();
+ try {
+ server.shutdown();
+ fail();
+ } catch (IllegalStateException expected) {
+ }
+ }
+
+ @Test public void shutdownWithoutEnqueue() throws IOException {
+ MockWebServer server = new MockWebServer();
+ server.start();
+ server.shutdown();
+ }
}