| Index: net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java
|
| diff --git a/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java b/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java
|
| index 9023991843d3266afbc4fbb199936d95edecfdda..5ca9b52aa893d7ae57ae61d718e1664d2babfaa5 100644
|
| --- a/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java
|
| +++ b/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java
|
| @@ -9,6 +9,7 @@ import android.util.Base64;
|
| import android.util.Log;
|
| import android.util.Pair;
|
|
|
| +import org.apache.http.Header;
|
| import org.apache.http.HttpException;
|
| import org.apache.http.HttpRequest;
|
| import org.apache.http.HttpResponse;
|
| @@ -33,8 +34,10 @@ import java.net.Socket;
|
| import java.net.URI;
|
| import java.net.URL;
|
| import java.net.URLConnection;
|
| +import java.nio.charset.Charset;
|
| import java.security.KeyManagementException;
|
| import java.security.KeyStore;
|
| +import java.security.MessageDigest;
|
| import java.security.NoSuchAlgorithmException;
|
| import java.security.cert.X509Certificate;
|
| import java.util.ArrayList;
|
| @@ -80,13 +83,15 @@ public class TestWebServer {
|
| final Runnable mResponseAction;
|
| final boolean mIsNotFound;
|
| final boolean mIsNoContent;
|
| + final boolean mForWebSocket;
|
|
|
| Response(byte[] responseData, List<Pair<String, String>> responseHeaders,
|
| - boolean isRedirect, boolean isNotFound, boolean isNoContent,
|
| + boolean isRedirect, boolean isNotFound, boolean isNoContent, boolean forWebSocket,
|
| Runnable responseAction) {
|
| mIsRedirect = isRedirect;
|
| mIsNotFound = isNotFound;
|
| mIsNoContent = isNoContent;
|
| + mForWebSocket = forWebSocket;
|
| mResponseData = responseData;
|
| mResponseHeaders = responseHeaders == null
|
| ? new ArrayList<Pair<String, String>>() : responseHeaders;
|
| @@ -195,6 +200,7 @@ public class TestWebServer {
|
| private static final int RESPONSE_STATUS_MOVED_TEMPORARILY = 1;
|
| private static final int RESPONSE_STATUS_NOT_FOUND = 2;
|
| private static final int RESPONSE_STATUS_NO_CONTENT = 3;
|
| + private static final int RESPONSE_STATUS_FOR_WEBSOCKET = 4;
|
|
|
| private String setResponseInternal(
|
| String requestPath, byte[] responseData,
|
| @@ -203,11 +209,12 @@ public class TestWebServer {
|
| final boolean isRedirect = (status == RESPONSE_STATUS_MOVED_TEMPORARILY);
|
| final boolean isNotFound = (status == RESPONSE_STATUS_NOT_FOUND);
|
| final boolean isNoContent = (status == RESPONSE_STATUS_NO_CONTENT);
|
| + final boolean forWebSocket = (status == RESPONSE_STATUS_FOR_WEBSOCKET);
|
|
|
| synchronized (mLock) {
|
| - mResponseMap.put(requestPath, new Response(
|
| - responseData, responseHeaders, isRedirect, isNotFound, isNoContent,
|
| - responseAction));
|
| + mResponseMap.put(
|
| + requestPath, new Response(responseData, responseHeaders, isRedirect, isNotFound,
|
| + isNoContent, forWebSocket, responseAction));
|
| mResponseCountMap.put(requestPath, Integer.valueOf(0));
|
| mLastRequestMap.put(requestPath, null);
|
| }
|
| @@ -344,6 +351,28 @@ public class TestWebServer {
|
| }
|
|
|
| /**
|
| + * Sets a response to a WebSocket handshake request.
|
| + *
|
| + * @param requestPath The path to respond to.
|
| + * @param responseHeaders Any additional headers that should be returned along with the
|
| + * response (null is acceptable).
|
| + * @return The full URL including the path that should be requested to get the expected
|
| + * response.
|
| + */
|
| + public String setResponseForWebSocket(
|
| + String requestPath, List<Pair<String, String>> responseHeaders) {
|
| + if (responseHeaders == null) {
|
| + responseHeaders = new ArrayList<Pair<String, String>>();
|
| + } else {
|
| + responseHeaders = new ArrayList<Pair<String, String>>(responseHeaders);
|
| + }
|
| + responseHeaders.add(Pair.create("Connection", "Upgrade"));
|
| + responseHeaders.add(Pair.create("Upgrade", "websocket"));
|
| + return setResponseInternal(
|
| + requestPath, "".getBytes(), responseHeaders, null, RESPONSE_STATUS_FOR_WEBSOCKET);
|
| + }
|
| +
|
| + /**
|
| * Get the number of requests was made at this path since it was last set.
|
| */
|
| public int getRequestCount(String requestPath) {
|
| @@ -481,6 +510,23 @@ public class TestWebServer {
|
| httpResponse.addHeader(header.first, header.second);
|
| }
|
| servedResponseFor(path, request);
|
| + } else if (response.mForWebSocket) {
|
| + Header[] keys = request.getHeaders("Sec-WebSocket-Key");
|
| + try {
|
| + if (keys.length == 1) {
|
| + final String key = keys[0].getValue();
|
| + httpResponse = createResponse(HttpStatus.SC_SWITCHING_PROTOCOLS);
|
| + for (Pair<String, String> header : response.mResponseHeaders) {
|
| + httpResponse.addHeader(header.first, header.second);
|
| + }
|
| + httpResponse.addHeader("Sec-WebSocket-Accept", computeWebSocketAccept(key));
|
| + } else {
|
| + httpResponse = createResponse(HttpStatus.SC_NOT_FOUND);
|
| + }
|
| + } catch (NoSuchAlgorithmException e) {
|
| + httpResponse = createResponse(HttpStatus.SC_NOT_FOUND);
|
| + }
|
| + servedResponseFor(path, request);
|
| } else {
|
| if (response.mResponseAction != null) response.mResponseAction.run();
|
|
|
| @@ -552,6 +598,20 @@ public class TestWebServer {
|
| return entity;
|
| }
|
|
|
| + /**
|
| + * Return a response for WebSocket handshake challenge.
|
| + */
|
| + private static String computeWebSocketAccept(String keyString) throws NoSuchAlgorithmException {
|
| + byte[] key = keyString.getBytes(Charset.forName("US-ASCII"));
|
| + byte[] guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11".getBytes(Charset.forName("US-ASCII"));
|
| +
|
| + MessageDigest md = MessageDigest.getInstance("SHA");
|
| + md.update(key);
|
| + md.update(guid);
|
| + byte[] output = md.digest();
|
| + return Base64.encodeToString(output, Base64.DEFAULT);
|
| + }
|
| +
|
| private static class ServerThread extends Thread {
|
| private TestWebServer mServer;
|
| private ServerSocket mSocket;
|
|
|