@Override public void read(DataInputStream in) throws IOException { final int version = in.readInt(); switch (version) { case VERSION_INIT: throw new ProtocolException("Ignored upgrade"); case VERSION_SPLIT_URI: authority = DurableUtils.readNullableString(in); documentId = DurableUtils.readNullableString(in); mimeType = DurableUtils.readNullableString(in); displayName = DurableUtils.readNullableString(in); lastModified = in.readLong(); flags = in.readInt(); summary = DurableUtils.readNullableString(in); size = in.readLong(); icon = in.readInt(); path = DurableUtils.readNullableString(in); deriveFields(); break; default: throw new ProtocolException("Unknown version " + version); } }
void a(byte[] bArr) throws IOException { if (bArr != null) { ByteBuffer wrap = ByteBuffer.wrap(bArr); int length = ApkExternalInfoTool.b.getBytes().length; byte[] bArr2 = new byte[length]; wrap.get(bArr2); if (!ApkExternalInfoTool.b.equals(new ZipShort(bArr2))) { throw new ProtocolException("unknow protocl [" + Arrays.toString(bArr) + "]"); } else if (bArr.length - length > 2) { bArr2 = new byte[2]; wrap.get(bArr2); int value = new ZipShort(bArr2).getValue(); if ((bArr.length - length) - 2 >= value) { byte[] bArr3 = new byte[value]; wrap.get(bArr3); this.a.load(new ByteArrayInputStream(bArr3)); length = ((bArr.length - length) - value) - 2; if (length > 0) { this.b = new byte[length]; wrap.get(this.b); } } } } }
@Override public void read(DataInputStream in) throws IOException { final int version = in.readInt(); switch (version) { case VERSION_DROP_TYPE: authority = DurableUtils.readNullableString(in); rootId = DurableUtils.readNullableString(in); flags = in.readInt(); icon = in.readInt(); title = DurableUtils.readNullableString(in); summary = DurableUtils.readNullableString(in); documentId = DurableUtils.readNullableString(in); availableBytes = in.readLong(); totalBytes = in.readLong(); mimeTypes = DurableUtils.readNullableString(in); path = DurableUtils.readNullableString(in); deriveFields(); break; default: throw new ProtocolException("Unknown version " + version); } }
private void readChunkSize() throws IOException { // Read the suffix of the previous chunk. if (bytesRemainingInChunk != NO_CHUNK_YET) { source.readUtf8LineStrict(); } try { bytesRemainingInChunk = source.readHexadecimalUnsignedLong(); String extensions = source.readUtf8LineStrict().trim(); if (bytesRemainingInChunk < 0 || (!extensions.isEmpty() && !extensions.startsWith(";"))) { throw new ProtocolException("expected chunk size and optional extensions but was \"" + bytesRemainingInChunk + extensions + "\""); } } catch (NumberFormatException e) { throw new ProtocolException(e.getMessage()); } if (bytesRemainingInChunk == 0L) { hasMoreChunks = false; HttpHeaders.receiveHeaders(client.cookieJar(), url, readHeaders()); endOfInput(true); } }
void checkResponse(Response response) throws ProtocolException { if (response.code() != 101) { throw new ProtocolException("Expected HTTP 101 response but was '" + response.code() + " " + response.message() + "'"); } String headerConnection = response.header("Connection"); if (!"Upgrade".equalsIgnoreCase(headerConnection)) { throw new ProtocolException("Expected 'Connection' header value 'Upgrade' but was '" + headerConnection + "'"); } String headerUpgrade = response.header("Upgrade"); if (!"websocket".equalsIgnoreCase(headerUpgrade)) { throw new ProtocolException( "Expected 'Upgrade' header value 'websocket' but was '" + headerUpgrade + "'"); } String headerAccept = response.header("Sec-WebSocket-Accept"); String acceptExpected = ByteString.encodeUtf8(key + WebSocketProtocol.ACCEPT_MAGIC) .sha1().base64(); if (!acceptExpected.equals(headerAccept)) { throw new ProtocolException("Expected 'Sec-WebSocket-Accept' header value '" + acceptExpected + "' but was '" + headerAccept + "'"); } }
@SmallTest @Feature({"Cronet"}) @CompareDefaultWithCronet public void testWriteLessThanContentLength() throws Exception { URL url = new URL(NativeTestServer.getEchoBodyURL()); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoOutput(true); connection.setRequestMethod("POST"); // Set a content length that's 1 byte more. connection.setRequestProperty( "Content-Length", Integer.toString(TestUtil.UPLOAD_DATA.length + 1)); OutputStream out = connection.getOutputStream(); out.write(TestUtil.UPLOAD_DATA); try { connection.getResponseCode(); fail(); } catch (ProtocolException e) { // Expected. } connection.disconnect(); }
/** * Does all the work to build an HTTPS connection over a proxy tunnel. The catch here is that a * proxy server can issue an auth challenge and then close the connection. */ private void connectTunnel(int connectTimeout, int readTimeout, int writeTimeout) throws IOException { Request tunnelRequest = createTunnelRequest(); HttpUrl url = tunnelRequest.url(); int attemptedConnections = 0; int maxAttempts = 21; while (true) { if (++attemptedConnections > maxAttempts) { throw new ProtocolException("Too many tunnel connections attempted: " + maxAttempts); } connectSocket(connectTimeout, readTimeout); tunnelRequest = createTunnel(readTimeout, writeTimeout, tunnelRequest, url); if (tunnelRequest == null) break; // Tunnel successfully created. // The proxy decided to close the connection after an auth challenge. We need to create a new // connection, but this time with the auth credentials. closeQuietly(rawSocket); rawSocket = null; sink = null; source = null; } }
@Test public void tooManyProxyAuthFailuresWithConnectionClose() throws IOException { server.useHttps(sslClient.socketFactory, true); server.setProtocols(Collections.singletonList(Protocol.HTTP_1_1)); for (int i = 0; i < 21; i++) { server.enqueue(new MockResponse() .setResponseCode(407) .addHeader("Proxy-Authenticate: Basic realm=\"localhost\"") .addHeader("Connection: close")); } client = client.newBuilder() .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .proxy(server.toProxyAddress()) .proxyAuthenticator(new RecordingOkAuthenticator("password")) .hostnameVerifier(new RecordingHostnameVerifier()) .build(); Request request = new Request.Builder() .url("https://android.com/foo") .build(); try { client.newCall(request).execute(); fail(); } catch (ProtocolException expected) { } }
@Test public void closeReservedSetThrows() throws IOException { data.write(ByteString.decodeHex("880203ec")); // Close with code 1004 data.write(ByteString.decodeHex("880203ed")); // Close with code 1005 data.write(ByteString.decodeHex("880203ee")); // Close with code 1006 for (int i = 1012; i <= 2999; i++) { data.write(ByteString.decodeHex("8802" + Util.format("%04X", i))); // Close with code 'i' } int count = 0; for (; !data.exhausted(); count++) { try { clientReader.processNextFrame(); fail(); } catch (ProtocolException e) { String message = e.getMessage(); assertTrue(message, Pattern.matches("Code \\d+ is reserved and may not be used.", message)); } } assertEquals(1991, count); }
public void testOnPingIncorrect(boolean fin, boolean rsv1, boolean rsv2, boolean rsv3, ByteBuffer data) { if (fin && !rsv1 && !rsv2 && !rsv3 && data.remaining() <= 125) { throw new SkipException("Correct frame"); } CompletableFuture<WebSocket> webSocket = new CompletableFuture<>(); MockChannel channel = new MockChannel.Builder() .provideFrame(fin, rsv1, rsv2, rsv3, Opcode.PING, data) .expectClose((code, reason) -> Integer.valueOf(1002).equals(code) && "".equals(reason)) .build(); MockListener listener = new MockListener.Builder() .expectOnOpen((ws) -> true) .expectOnError((ws, error) -> error instanceof ProtocolException) .build(); webSocket.complete(newWebSocket(channel, listener)); checkExpectations(500, TimeUnit.MILLISECONDS, channel, listener); }
@Override public OutputStream getOutputStream() throws IOException { OutputStreamRequestBody requestBody = (OutputStreamRequestBody) buildCall().request().body(); if (requestBody == null) { throw new ProtocolException("method does not support a request body: " + method); } // If this request needs to stream bytes to the server, build a physical connection immediately // and start streaming those bytes over that connection. if (requestBody instanceof StreamedRequestBody) { connect(); networkInterceptor.proceed(); } if (requestBody.isClosed()) { throw new ProtocolException("cannot write request body after response has been read"); } return requestBody.outputStream(); }
@Test public void contentDisagreesWithChunkedHeaderBodyTooShort() throws IOException { MockResponse mockResponse = new MockResponse(); mockResponse.setChunkedBody("abcde", 5); Buffer truncatedBody = new Buffer(); Buffer fullBody = mockResponse.getBody(); truncatedBody.write(fullBody, fullBody.indexOf((byte) 'e')); mockResponse.setBody(truncatedBody); mockResponse.clearHeaders(); mockResponse.addHeader("Transfer-encoding: chunked"); mockResponse.setSocketPolicy(DISCONNECT_AT_END); server.enqueue(mockResponse); try { readAscii(urlFactory.open(server.url("/").url()).getInputStream(), 5); fail(); } catch (ProtocolException expected) { } }
@Test public void doesNotFollow21Redirects() throws Exception { for (int i = 0; i < 21; i++) { server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP) .addHeader("Location: /" + (i + 1)) .setBody("Redirecting to /" + (i + 1))); } connection = urlFactory.open(server.url("/0").url()); try { connection.getInputStream(); fail(); } catch (ProtocolException expected) { assertEquals(HttpURLConnection.HTTP_MOVED_TEMP, connection.getResponseCode()); assertEquals("Too many follow-up requests: 21", expected.getMessage()); assertEquals(server.url("/20").url(), connection.getURL()); } }
@Test public void doesNotAttemptAuthorization21Times() throws Exception { for (int i = 0; i < 21; i++) { server.enqueue(new MockResponse().setResponseCode(401)); } String credential = Credentials.basic("jesse", "peanutbutter"); urlFactory.setClient(urlFactory.client().newBuilder() .authenticator(new RecordingOkAuthenticator(credential)) .build()); connection = urlFactory.open(server.url("/").url()); try { connection.getInputStream(); fail(); } catch (ProtocolException expected) { assertEquals(401, connection.getResponseCode()); assertEquals("Too many follow-up requests: 21", expected.getMessage()); } }
@Override public void read(DataInputStream in) throws IOException { final int version = in.readInt(); switch (version) { case VERSION_INIT: throw new ProtocolException("Ignored upgrade"); case VERSION_ADD_ROOT: if (in.readBoolean()) { root = new RootInfo(); root.read(in); } final int size = in.readInt(); for (int i = 0; i < size; i++) { final DocumentInfo doc = new DocumentInfo(); doc.read(in); add(doc); } break; default: throw new ProtocolException("Unknown version " + version); } }
@Test public void disconnectResponseHalfway() throws IOException { server.enqueue(new MockResponse() .setBody("ab") .setSocketPolicy(SocketPolicy.DISCONNECT_DURING_RESPONSE_BODY)); URLConnection connection = server.url("/").url().openConnection(); assertEquals(2, connection.getContentLength()); InputStream in = connection.getInputStream(); assertEquals('a', in.read()); try { int byteRead = in.read(); // OpenJDK behavior: end of stream. assertEquals(-1, byteRead); } catch (ProtocolException e) { // On Android, HttpURLConnection is implemented by OkHttp v2. OkHttp // treats an incomplete response body as a ProtocolException. } }
/** * Ensures that {@code count} bytes can be written to the internal buffer. */ private void ensureCanWrite(int count) throws IOException { if (mInitialContentLength != -1 && mBuffer.position() + count > mInitialContentLength) { // Error message is to match that of the default implementation. throw new ProtocolException("exceeded content-length limit of " + mInitialContentLength + " bytes"); } if (mConnected) { throw new IllegalStateException("Cannot write after being connected."); } if (mInitialContentLength != -1) { // If mInitialContentLength is known, the buffer should not grow. return; } if (mBuffer.limit() - mBuffer.position() > count) { // If there is enough capacity, the buffer should not grow. return; } int afterSize = Math.max(mBuffer.capacity() * 2, mBuffer.capacity() + count); ByteBuffer newByteBuffer = ByteBuffer.allocate(afterSize); mBuffer.flip(); newByteBuffer.put(mBuffer); mBuffer = newByteBuffer; }
/** * Handles a redirect. * * @param originalUrl The original URL. * @param location The Location header in the response. * @return The next URL. * @throws IOException If redirection isn't possible. */ private static URL handleRedirect(URL originalUrl, String location) throws IOException { if (location == null) { throw new ProtocolException("Null location redirect"); } // Form the new url. URL url = new URL(originalUrl, location); // Check that the protocol of the new url is supported. String protocol = url.getProtocol(); if (!"https".equals(protocol) && !"http".equals(protocol)) { throw new ProtocolException("Unsupported protocol redirect: " + protocol); } // Currently this method is only called if allowCrossProtocolRedirects is true, and so the code // below isn't required. If we ever decide to handle redirects ourselves when cross-protocol // redirects are disabled, we'll need to uncomment this block of code. // if (!allowCrossProtocolRedirects && !protocol.equals(originalUrl.getProtocol())) { // throw new ProtocolException("Disallowed cross-protocol redirect (" // + originalUrl.getProtocol() + " to " + protocol + ")"); // } return url; }
@Test public void interceptConnect_redirect_processEachTime() throws IOException { final String mockLocation = "mock location"; when(mockConnected.getResponseCode()).thenReturn(HttpURLConnection.HTTP_MOVED_PERM); when(mockConnected.getResponseHeaderField("Location")).thenReturn(mockLocation); try { interceptor.interceptConnect(mockChain); } catch (ProtocolException e) { // ignore } verify(mockChain, times(MAX_REDIRECT_TIMES)).processConnect(); verify(mockChain, times(MAX_REDIRECT_TIMES - 1)) .setRedirectLocation(mockLocation); verify(mockChain, times(MAX_REDIRECT_TIMES - 1)) .setConnection(any(DownloadConnection.class)); }
private void readChunkSize() throws IOException { // read the suffix of the previous chunk if (bytesRemainingInChunk != NO_CHUNK_YET) { Util.readAsciiLine(in); } String chunkSizeString = Util.readAsciiLine(in); int index = chunkSizeString.indexOf(";"); if (index != -1) { chunkSizeString = chunkSizeString.substring(0, index); } try { bytesRemainingInChunk = Integer.parseInt(chunkSizeString.trim(), 16); } catch (NumberFormatException e) { throw new ProtocolException("Expected a hex chunk size but was " + chunkSizeString); } if (bytesRemainingInChunk == 0) { hasMoreChunks = false; RawHeaders rawResponseHeaders = httpEngine.responseHeaders.getHeaders(); RawHeaders.readHeaders(transport.socketIn, rawResponseHeaders); httpEngine.receiveHeaders(rawResponseHeaders); endOfInput(); } }
private void initHttpEngine() throws IOException { if (httpEngineFailure != null) { throw httpEngineFailure; } else if (httpEngine != null) { return; } connected = true; try { if (doOutput) { if (method.equals("GET")) { // they are requesting a stream to write to. This implies a POST method method = "POST"; } else if (!method.equals("POST") && !method.equals("PUT") && !method.equals("PATCH")) { // If the request method is neither POST nor PUT nor PATCH, then you're not writing throw new ProtocolException(method + " does not support writing"); } } httpEngine = newHttpEngine(method, rawRequestHeaders, null, null); } catch (IOException e) { httpEngineFailure = e; throw e; } }
private void initHttpEngine() throws IOException { if (this.httpEngineFailure != null) { throw this.httpEngineFailure; } else if (this.httpEngine == null) { this.connected = true; try { if (this.doOutput) { if (this.method.equals("GET")) { this.method = Constants.HTTP_POST; } else if (!HttpMethod.permitsRequestBody(this.method)) { throw new ProtocolException(this.method + " does not support writing"); } } this.httpEngine = newHttpEngine(this.method, null, null, null); } catch (IOException e) { this.httpEngineFailure = e; throw e; } } }
@Test public void protocolErrorInCloseResponseClosesConnection() throws IOException { client.webSocket.close(1000, "Hello"); server.processNextFrame(); assertFalse(client.closed); // Not closed until close reply is received. // Manually write an invalid masked close frame. server.sink.write(ByteString.decodeHex("888760b420bb635c68de0cd84f")).emit(); client.processNextFrame();// Detects error, disconnects immediately since close already sent. assertTrue(client.closed); client.listener.assertFailure( ProtocolException.class, "Server-sent frames must not be masked."); server.listener.assertClosing(1000, "Hello"); server.listener.assertExhausted(); // Client should not have sent second close. }
private boolean uploadIPFSDataViaPost(File f, String serverURL) throws MalformedURLException, ProtocolException, IOException { URL obj = new URL(serverURL); HttpURLConnection con = (HttpURLConnection) obj.openConnection(); con.setRequestMethod("POST"); con.setRequestProperty("User-Agent", "Mozilla/5.0"); con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); con.setDoOutput(true); DataOutputStream out = new DataOutputStream(con.getOutputStream()); out.write(Util.loadFileInMemory(f)); out.flush(); out.close(); int responseCode = con.getResponseCode(); // TODO: for now compare hashes until it is clear POST works the same way System.out.println("IPFS header fields:" + con.getHeaderFields()); return responseCode == 201; // Created }
@SmallTest @Feature({"Cronet"}) @CompareDefaultWithCronet public void testGetOutputStreamAfterConnectionMade() throws Exception { URL url = new URL(NativeTestServer.getEchoBodyURL()); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoOutput(true); connection.setRequestMethod("POST"); connection.setChunkedStreamingMode(0); assertEquals(200, connection.getResponseCode()); try { connection.getOutputStream(); fail(); } catch (ProtocolException e) { // Expected. } }
@Override public void close() throws IOException { if (closed) return; closed = true; if (bytesRemaining > 0) throw new ProtocolException("unexpected end of stream"); detachTimeout(timeout); state = STATE_READ_RESPONSE_HEADERS; }
/** * Same as {@code testWriteMoreThanContentLength()}, but it only writes one byte * at a time. */ @SmallTest @Feature({"Cronet"}) @CompareDefaultWithCronet public void testWriteMoreThanContentLengthWriteOneByte() throws Exception { URL url = new URL(NativeTestServer.getEchoBodyURL()); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoOutput(true); connection.setRequestMethod("POST"); // Use a content length that is 1 byte shorter than actual data. connection.setRequestProperty( "Content-Length", Integer.toString(TestUtil.UPLOAD_DATA.length - 1)); OutputStream out = connection.getOutputStream(); try { for (int i = 0; i < TestUtil.UPLOAD_DATA.length; i++) { out.write(TestUtil.UPLOAD_DATA[i]); } // On Lollipop, default implementation only triggers the error when reading response. connection.getInputStream(); fail(); } catch (java.net.ProtocolException e) { assertEquals("exceeded content-length limit of " + (TestUtil.UPLOAD_DATA.length - 1) + " bytes", e.getMessage()); } }
/** * Reads a message body into across one or more frames. Control frames that occur between * fragments will be processed. If the message payload is masked this will unmask as it's being * processed. */ private void readMessage(Buffer sink) throws IOException { while (true) { if (closed) throw new IOException("closed"); if (frameBytesRead == frameLength) { if (isFinalFrame) return; // We are exhausted and have no continuations. readUntilNonControlFrame(); if (opcode != OPCODE_CONTINUATION) { throw new ProtocolException("Expected continuation opcode. Got: " + toHexString(opcode)); } if (isFinalFrame && frameLength == 0) { return; // Fast-path for empty final frame. } } long toRead = frameLength - frameBytesRead; long read; if (isMasked) { toRead = Math.min(toRead, maskBuffer.length); read = source.read(maskBuffer, 0, (int) toRead); if (read == -1) throw new EOFException(); toggleMask(maskBuffer, read, maskKey, frameBytesRead); sink.write(maskBuffer, 0, (int) read); } else { read = source.read(sink, toRead); if (read == -1) throw new EOFException(); } frameBytesRead += read; } }
@SmallTest @Feature({"Cronet"}) @CompareDefaultWithCronet public void testWriteMoreThanContentLengthWriteOneByte() throws Exception { URL url = new URL(NativeTestServer.getEchoBodyURL()); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoOutput(true); connection.setRequestMethod("POST"); // Set a content length that's 1 byte short. connection.setFixedLengthStreamingMode(TestUtil.UPLOAD_DATA.length - 1); OutputStream out = connection.getOutputStream(); for (int i = 0; i < TestUtil.UPLOAD_DATA.length - 1; i++) { out.write(TestUtil.UPLOAD_DATA[i]); } try { // Try upload an extra byte. out.write(TestUtil.UPLOAD_DATA[TestUtil.UPLOAD_DATA.length - 1]); // On Lollipop, default implementation only triggers the error when reading response. connection.getInputStream(); fail(); } catch (ProtocolException e) { // Expected. String expectedVariant = "expected 0 bytes but received 1"; String expectedVariantOnLollipop = "expected " + (TestUtil.UPLOAD_DATA.length - 1) + " bytes but received " + TestUtil.UPLOAD_DATA.length; assertTrue(expectedVariant.equals(e.getMessage()) || expectedVariantOnLollipop.equals(e.getMessage())); } connection.disconnect(); }
public static int readIntAttribute(XmlPullParser in, String name) throws IOException { final String value = in.getAttributeValue(null, name); try { return Integer.parseInt(value); } catch (NumberFormatException e) { throw new ProtocolException("problem parsing " + name + "=" + value + " as int"); } }
private static void sendOtherError(Throwable error, boolean here) { if (error instanceof SocketTimeoutException) { if (here) Crashlytics.logException(new Exception(HERE + error.toString() + "\n\n" + Arrays.toString(error.getStackTrace()).replaceAll(", ", "\n"))); else Crashlytics.logException(new Exception(OVERPASS + error.toString() + "\n\n" + Arrays.toString(error.getStackTrace()).replaceAll(", ", "\n"))); } else if (error instanceof java.net.SocketException) { if (here) Crashlytics.logException(new Exception(HERE + error.toString() + "\n\n" + Arrays.toString(error.getStackTrace()).replaceAll(", ", "\n"))); else Crashlytics.logException(new Exception(OVERPASS + error.toString() + "\n\n" + Arrays.toString(error.getStackTrace()).replaceAll(", ", "\n"))); } else if (error instanceof MalformedJsonException) { if (here) Crashlytics.logException(new Exception(HERE + error.toString() + "\n\n" + Arrays.toString(error.getStackTrace()).replaceAll(", ", "\n"))); else Crashlytics.logException(new Exception(OVERPASS + error.toString() + "\n\n" + Arrays.toString(error.getStackTrace()).replaceAll(", ", "\n"))); } else if (error instanceof UnknownHostException) { if (here) Crashlytics.logException(new Exception(HERE + error.toString() + "\n\n" + Arrays.toString(error.getStackTrace()).replaceAll(", ", "\n"))); else Crashlytics.logException(new Exception(OVERPASS + error.toString() + "\n\n" + Arrays.toString(error.getStackTrace()).replaceAll(", ", "\n"))); } else if (error instanceof ProtocolException) { if (here) Crashlytics.logException(new Exception(HERE + error.toString() + "\n\n" + Arrays.toString(error.getStackTrace()).replaceAll(", ", "\n"))); else Crashlytics.logException(new Exception(OVERPASS + error.toString() + "\n\n" + Arrays.toString(error.getStackTrace()).replaceAll(", ", "\n"))); } else if (error instanceof IllegalStateException) { if (here) Crashlytics.logException(new Exception(HERE + error.toString() + "\n\n" + Arrays.toString(error.getStackTrace()).replaceAll(", ", "\n"))); else Crashlytics.logException(new Exception(OVERPASS + error.toString() + "\n\n" + Arrays.toString(error.getStackTrace()).replaceAll(", ", "\n"))); } else if (error instanceof java.io.IOException) { if (here) Crashlytics.logException(new Exception(HERE + error.toString() + "\n\n" + Arrays.toString(error.getStackTrace()).replaceAll(", ", "\n"))); else Crashlytics.logException(new Exception(OVERPASS + error.toString() + "\n\n" + Arrays.toString(error.getStackTrace()).replaceAll(", ", "\n"))); } else { //some other exception if (here) Crashlytics.logException(new Exception(HERE, error)); else Crashlytics.logException(new Exception(OVERPASS, error)); } }
private void hello(BufferedSource fromSource, BufferedSink fromSink) throws IOException { int version = fromSource.readByte() & 0xff; int methodCount = fromSource.readByte() & 0xff; int selectedMethod = METHOD_NONE; if (version != VERSION_5) { throw new ProtocolException("unsupported version: " + version); } for (int i = 0; i < methodCount; i++) { int candidateMethod = fromSource.readByte() & 0xff; if (candidateMethod == METHOD_NO_AUTHENTICATION_REQUIRED) { selectedMethod = candidateMethod; } } switch (selectedMethod) { case METHOD_NO_AUTHENTICATION_REQUIRED: fromSink.writeByte(VERSION_5); fromSink.writeByte(selectedMethod); fromSink.emit(); break; default: throw new ProtocolException("unsupported method: " + selectedMethod); } }
@Override public void write(byte[] buffer, int offset, int count) throws IOException { checkNotClosed(); checkOffsetAndCount(buffer.length, offset, count); if (count > bytesRemaining) { throw new ProtocolException("expected " + bytesRemaining + " bytes but received " + count); } socketOut.write(buffer, offset, count); bytesRemaining -= count; }
@Test public void non101RetainsBody() throws IOException { webServer.enqueue(new MockResponse().setResponseCode(200).setBody("Body")); newWebSocket(); clientListener.assertFailure(200, "Body", ProtocolException.class, "Expected HTTP 101 response but was '200 OK'"); }
@Test public void wrongConnectionHeader() throws IOException { webServer.enqueue(new MockResponse() .setResponseCode(101) .setHeader("Upgrade", "websocket") .setHeader("Connection", "Downgrade") .setHeader("Sec-WebSocket-Accept", "ujmZX4KXZqjwy6vi1aQFH5p4Ygk=")); newWebSocket(); clientListener.assertFailure(101, null, ProtocolException.class, "Expected 'Connection' header value 'Upgrade' but was 'Downgrade'"); }