@Override public void setRequestMethod(String method) throws ProtocolException { if (!METHODS.contains(method)) { throw new ProtocolException("Expected one of " + METHODS + " but was " + method); } this.method = method; }
static String extractStatusLine(Map<String, List<String>> javaResponseHeaders) throws ProtocolException { List<String> values = javaResponseHeaders.get(null); if (values == null || values.size() == 0) { // The status line is missing. This suggests a badly behaving cache. throw new ProtocolException( "CacheResponse is missing a \'null\' header containing the status line. Headers=" + javaResponseHeaders); } return values.get(0); }
@Override public void setRequestMethod(String method) throws ProtocolException { if (!METHODS.contains(method)) { throw new ProtocolException("Expected one of " + METHODS + " but was " + method); } this.method = method; }
@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; } }
@Override public InputStream getInputStream() throws IOException { if (!doInput) { throw new ProtocolException("This protocol does not support input"); } Response response = getResponse(false); if (response.code() >= HTTP_BAD_REQUEST) { throw new FileNotFoundException(url.toString()); } return response.body().byteStream(); }
@Override public void close() throws IOException { closed = true; if (expectedContentLength != -1L && bytesReceived < expectedContentLength) { throw new ProtocolException("expected " + expectedContentLength + " bytes but received " + bytesReceived); } sink.close(); } };
@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; } }
@Override public void write(byte[] source, int offset, int byteCount) throws IOException { if (closed) throw new IOException("closed"); // Not IllegalStateException! if (expectedContentLength != -1L && bytesReceived + byteCount > expectedContentLength) { throw new ProtocolException("expected " + expectedContentLength + " bytes but received " + bytesReceived + byteCount); } bytesReceived += byteCount; try { sink.write(source, offset, byteCount); } catch (InterruptedIOException e) { throw new SocketTimeoutException(e.getMessage()); } }
@Override public void close() throws IOException { closed = true; if (expectedContentLength != -1L && bytesReceived < expectedContentLength) { throw new ProtocolException("expected " + expectedContentLength + " bytes but received " + bytesReceived); } sink.close(); } };
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 + "'"); } }
@Override public long read(Buffer sink, long byteCount) throws IOException { if (byteCount < 0) throw new IllegalArgumentException("byteCount < 0: " + byteCount); if (closed) throw new IllegalStateException("closed"); if (bytesRemaining == 0) return -1; long read = super.read(sink, Math.min(bytesRemaining, byteCount)); if (read == -1) { ProtocolException e = new ProtocolException("unexpected end of stream"); endOfInput(false, e); // The server didn't supply the promised content length. throw e; } bytesRemaining -= read; if (bytesRemaining == 0) { endOfInput(true, null); } return read; }
@Override public void write(Buffer source, long byteCount) throws IOException { if (closed) throw new IllegalStateException("closed"); checkOffsetAndCount(source.size(), 0, byteCount); if (byteCount > bytesRemaining) { throw new ProtocolException("expected " + bytesRemaining + " bytes but received " + byteCount); } sink.write(source, byteCount); bytesRemaining -= byteCount; }
@Override public long read(Buffer sink, long byteCount) throws IOException { if (byteCount < 0) throw new IllegalArgumentException("byteCount < 0: " + byteCount); if (closed) throw new IllegalStateException("closed"); if (!hasMoreChunks) return -1; if (bytesRemainingInChunk == 0 || bytesRemainingInChunk == NO_CHUNK_YET) { readChunkSize(); if (!hasMoreChunks) return -1; } long read = super.read(sink, Math.min(byteCount, bytesRemainingInChunk)); if (read == -1) { ProtocolException e = new ProtocolException("unexpected end of stream"); endOfInput(false, e); // The server didn't supply the promised chunk length. throw e; } bytesRemainingInChunk -= read; return read; }
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; trailers = readHeaders(); HttpHeaders.receiveHeaders(client.cookieJar(), url, trailers); endOfInput(true, null); } }
@Override public void write(Buffer source, long byteCount) throws IOException { if (closed) throw new IllegalStateException("closed"); checkOffsetAndCount(source.size(), 0, byteCount); if (byteCount > bytesRemaining) { throw new ProtocolException("expected " + bytesRemaining + " bytes but received " + byteCount); } sink.write(source, byteCount); bytesRemaining -= byteCount; }
@Override public InputStream getInputStream() throws IOException { if (!doInput) { throw new ProtocolException("This protocol does not support input"); } Response response = getResponse(false); if (response.code() >= HTTP_BAD_REQUEST) { throw new FileNotFoundException(url.toString()); } return response.body().byteStream(); }
private void readMessageFrame() throws IOException { int opcode = this.opcode; if (opcode != OPCODE_TEXT && opcode != OPCODE_BINARY) { throw new ProtocolException("Unknown opcode: " + toHexString(opcode)); } readMessage(); if (opcode == OPCODE_TEXT) { frameCallback.onReadMessage(messageFrameBuffer.readUtf8()); } else { frameCallback.onReadMessage(messageFrameBuffer.readByteString()); } }
@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(); }
/** * 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() throws IOException { while (true) { if (closed) throw new IOException("closed"); if (frameLength > 0) { source.readFully(messageFrameBuffer, frameLength); if (!isClient) { messageFrameBuffer.readAndWriteUnsafe(maskCursor); maskCursor.seek(messageFrameBuffer.size() - frameLength); toggleMask(maskCursor, maskKey); maskCursor.close(); } } if (isFinalFrame) break; // We are exhausted and have no continuations. readUntilNonControlFrame(); if (opcode != OPCODE_CONTINUATION) { throw new ProtocolException("Expected continuation opcode. Got: " + toHexString(opcode)); } } } }
/** Returns headers for a name value block containing an HTTP/2 response. */ public static Response.Builder readHttp2HeadersList(Headers headerBlock, Protocol protocol) throws IOException { StatusLine statusLine = null; Headers.Builder headersBuilder = new Headers.Builder(); for (int i = 0, size = headerBlock.size(); i < size; i++) { String name = headerBlock.name(i); String value = headerBlock.value(i); if (name.equals(RESPONSE_STATUS_UTF8)) { statusLine = StatusLine.parse("HTTP/1.1 " + value); } else if (!HTTP_2_SKIPPED_RESPONSE_HEADERS.contains(name)) { Internal.instance.addLenient(headersBuilder, name, value); } } if (statusLine == null) throw new ProtocolException("Expected ':status' header not present"); return new Response.Builder() .protocol(protocol) .code(statusLine.code) .message(statusLine.message) .headers(headersBuilder.build()); }