Chromium Code Reviews| 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..4d84dd1ef4b096d89bb048789acc3a3564d44974 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; |
|
mef
2016/10/14 16:52:26
According to https://bugs.chromium.org/p/chromium/
jbudorick
2016/10/18 17:27:30
Agreed. We're still working to replace existing us
|
| 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,26 @@ 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>>(); |
| + } |
| + 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 +508,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)); |
| + servedResponseFor(path, request); |
| + } else { |
| + httpResponse = createResponse(HttpStatus.SC_NOT_FOUND); |
| + } |
| + } catch (NoSuchAlgorithmException e) { |
| + httpResponse = createResponse(HttpStatus.SC_NOT_FOUND); |
| + } |
| } else { |
| if (response.mResponseAction != null) response.mResponseAction.run(); |
| @@ -552,6 +596,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; |