diff --git a/mockwebserver/src/main/java/okhttp3/mockwebserver/Dispatcher.kt b/mockwebserver/src/main/java/okhttp3/mockwebserver/Dispatcher.kt index 5d2028344..d50d6c4c5 100644 --- a/mockwebserver/src/main/java/okhttp3/mockwebserver/Dispatcher.kt +++ b/mockwebserver/src/main/java/okhttp3/mockwebserver/Dispatcher.kt @@ -31,7 +31,8 @@ abstract class Dispatcher { * request bodies. */ open fun peek(): MockResponse { - return MockResponse().setSocketPolicy(SocketPolicy.KEEP_OPEN) + val mockResponse = MockResponse() + return mockResponse.apply { mockResponse.socketPolicy = SocketPolicy.KEEP_OPEN } } /** diff --git a/mockwebserver/src/main/java/okhttp3/mockwebserver/MockResponse.kt b/mockwebserver/src/main/java/okhttp3/mockwebserver/MockResponse.kt index c9b1657c7..ae8e3f63a 100644 --- a/mockwebserver/src/main/java/okhttp3/mockwebserver/MockResponse.kt +++ b/mockwebserver/src/main/java/okhttp3/mockwebserver/MockResponse.kt @@ -25,7 +25,10 @@ import java.util.concurrent.TimeUnit /** A scripted response to be replayed by the mock web server. */ class MockResponse : Cloneable { - private var status: String = "" + /** Returns the HTTP response line, such as "HTTP/1.1 200 OK". */ + @set:JvmName("status") + var status: String = "" + private var headers = Headers.Builder() private var trailers = Headers.Builder() @@ -36,8 +39,16 @@ class MockResponse : Cloneable { private var throttlePeriodAmount = 1L private var throttlePeriodUnit = TimeUnit.SECONDS - private var socketPolicy = SocketPolicy.KEEP_OPEN - private var http2ErrorCode = -1 + @set:JvmName("socketPolicy") + var socketPolicy = SocketPolicy.KEEP_OPEN + + /** + * Sets the [HTTP/2 error code](https://tools.ietf.org/html/rfc7540#section-7) to be + * returned when resetting the stream. + * This is only valid with [SocketPolicy.RESET_STREAM_AT_START]. + */ + @set:JvmName("http2ErrorCode") + var http2ErrorCode = -1 private var bodyDelayAmount = 0L private var bodyDelayUnit = TimeUnit.MILLISECONDS @@ -72,9 +83,21 @@ class MockResponse : Cloneable { return result } - /** Returns the HTTP response line, such as "HTTP/1.1 200 OK". */ + @JvmName("-deprecated_getStatus") + @Deprecated( + message = "moved to var", + replaceWith = ReplaceWith(expression = "status"), + level = DeprecationLevel.WARNING) fun getStatus(): String = status + @Deprecated( + message = "moved to var. Replace setStatus(...) with status(...) to fix Java", + replaceWith = ReplaceWith(expression = "apply { this.status = status }"), + level = DeprecationLevel.WARNING) + fun setStatus(status: String) = apply { + this.status = status + } + fun setResponseCode(code: Int): MockResponse { val reason = when (code) { in 100..199 -> "Informational" @@ -84,11 +107,7 @@ class MockResponse : Cloneable { in 500..599 -> "Server Error" else -> "Mock Response" } - return setStatus("HTTP/1.1 $code $reason") - } - - fun setStatus(status: String) = apply { - this.status = status + return apply { status = "HTTP/1.1 $code $reason" } } /** Returns the HTTP headers, such as "Content-Length: 0". */ @@ -193,19 +212,32 @@ class MockResponse : Cloneable { fun setChunkedBody(body: String, maxChunkSize: Int): MockResponse = setChunkedBody(Buffer().writeUtf8(body), maxChunkSize) + @JvmName("-deprecated_getSocketPolicy") + @Deprecated( + message = "moved to var", + replaceWith = ReplaceWith(expression = "socketPolicy"), + level = DeprecationLevel.WARNING) fun getSocketPolicy() = socketPolicy + @Deprecated( + message = "moved to var. Replace setSocketPolicy(...) with socketPolicy(...) to fix Java", + replaceWith = ReplaceWith(expression = "apply { this.socketPolicy = socketPolicy }"), + level = DeprecationLevel.WARNING) fun setSocketPolicy(socketPolicy: SocketPolicy) = apply { this.socketPolicy = socketPolicy } + @JvmName("-deprecated_getHttp2ErrorCode") + @Deprecated( + message = "moved to var", + replaceWith = ReplaceWith(expression = "http2ErrorCode"), + level = DeprecationLevel.WARNING) fun getHttp2ErrorCode() = http2ErrorCode - /** - * Sets the [HTTP/2 error code](https://tools.ietf.org/html/rfc7540#section-7) to be - * returned when resetting the stream. - * This is only valid with [SocketPolicy.RESET_STREAM_AT_START]. - */ + @Deprecated( + message = "moved to var. Replace setHttp2ErrorCode(...) with http2ErrorCode(...) to fix Java", + replaceWith = ReplaceWith(expression = "apply { this.http2ErrorCode = http2ErrorCode }"), + level = DeprecationLevel.WARNING) fun setHttp2ErrorCode(http2ErrorCode: Int) = apply { this.http2ErrorCode = http2ErrorCode } @@ -264,7 +296,7 @@ class MockResponse : Cloneable { * This will overwrite any previously set status or body. */ fun withWebSocketUpgrade(listener: WebSocketListener) = apply { - setStatus("HTTP/1.1 101 Switching Protocols") + status = "HTTP/1.1 101 Switching Protocols" setHeader("Connection", "Upgrade") setHeader("Upgrade", "websocket") body = null diff --git a/mockwebserver/src/main/java/okhttp3/mockwebserver/MockWebServer.kt b/mockwebserver/src/main/java/okhttp3/mockwebserver/MockWebServer.kt index f9b24152c..29a5a3f2d 100644 --- a/mockwebserver/src/main/java/okhttp3/mockwebserver/MockWebServer.kt +++ b/mockwebserver/src/main/java/okhttp3/mockwebserver/MockWebServer.kt @@ -370,7 +370,7 @@ class MockWebServer : ExternalResource(), Closeable { return } - val socketPolicy = dispatcher.peek().getSocketPolicy() + val socketPolicy = dispatcher.peek().socketPolicy if (socketPolicy === DISCONNECT_AT_START) { dispatchBookkeepingRequest(0, socket) socket.close() @@ -426,7 +426,7 @@ class MockWebServer : ExternalResource(), Closeable { @Throws(Exception::class) fun handle() { - val socketPolicy = dispatcher.peek().getSocketPolicy() + val socketPolicy = dispatcher.peek().socketPolicy var protocol = Protocol.HTTP_1_1 val socket: Socket when { @@ -513,7 +513,7 @@ class MockWebServer : ExternalResource(), Closeable { val source = raw.source().buffer() val sink = raw.sink().buffer() while (true) { - val socketPolicy = dispatcher.peek().getSocketPolicy() + val socketPolicy = dispatcher.peek().socketPolicy check(processOneRequest(raw, source, sink)) { "Tunnel without any CONNECT!" } if (socketPolicy === UPGRADE_TO_SSL_AT_END) return } @@ -535,11 +535,11 @@ class MockWebServer : ExternalResource(), Closeable { requestQueue.add(request) val response = dispatcher.dispatch(request) - if (response.getSocketPolicy() === DISCONNECT_AFTER_REQUEST) { + if (response.socketPolicy === DISCONNECT_AFTER_REQUEST) { socket.close() return false } - if (response.getSocketPolicy() === NO_RESPONSE) { + if (response.socketPolicy === NO_RESPONSE) { // This read should block until the socket is closed. (Because nobody is writing.) if (source.exhausted()) return false throw ProtocolException("unexpected data") @@ -563,7 +563,7 @@ class MockWebServer : ExternalResource(), Closeable { } // See warnings associated with these socket policies in SocketPolicy. - when (response.getSocketPolicy()) { + when (response.socketPolicy) { DISCONNECT_AT_END -> { socket.close() return false @@ -644,7 +644,7 @@ class MockWebServer : ExternalResource(), Closeable { } } - val socketPolicy = dispatcher.peek().getSocketPolicy() + val socketPolicy = dispatcher.peek().socketPolicy if (expectContinue && socketPolicy === EXPECT_CONTINUE || socketPolicy === CONTINUE_ALWAYS) { sink.writeUtf8("HTTP/1.1 100 Continue\r\n") sink.writeUtf8("Content-Length: 0\r\n") @@ -703,7 +703,7 @@ class MockWebServer : ExternalResource(), Closeable { .url("$scheme://$authority/") .headers(request.headers) .build() - val statusParts = response.getStatus().split(' ', limit = 3) + val statusParts = response.status.split(' ', limit = 3) val fancyResponse = Response.Builder() .code(Integer.parseInt(statusParts[1])) .message(statusParts[2]) @@ -735,7 +735,7 @@ class MockWebServer : ExternalResource(), Closeable { @Throws(IOException::class) private fun writeHttpResponse(socket: Socket, sink: BufferedSink, response: MockResponse) { sleepIfDelayed(response.getHeadersDelay(TimeUnit.MILLISECONDS)) - sink.writeUtf8(response.getStatus()) + sink.writeUtf8(response.status) sink.writeUtf8("\r\n") writeHeaders(sink, response.getHeaders()) @@ -789,9 +789,9 @@ class MockWebServer : ExternalResource(), Closeable { val halfByteCount = byteCountNum / 2 val disconnectHalfway = if (isRequest) { - policy.getSocketPolicy() === DISCONNECT_DURING_REQUEST_BODY + policy.socketPolicy === DISCONNECT_DURING_REQUEST_BODY } else { - policy.getSocketPolicy() === DISCONNECT_DURING_RESPONSE_BODY + policy.socketPolicy === DISCONNECT_DURING_RESPONSE_BODY } while (!socket.isClosed) { @@ -879,9 +879,9 @@ class MockWebServer : ExternalResource(), Closeable { @Throws(IOException::class) override fun onStream(stream: Http2Stream) { val peekedResponse = dispatcher.peek() - if (peekedResponse.getSocketPolicy() === RESET_STREAM_AT_START) { + if (peekedResponse.socketPolicy === RESET_STREAM_AT_START) { dispatchBookkeepingRequest(sequenceNumber.getAndIncrement(), socket) - stream.close(ErrorCode.fromHttp2(peekedResponse.getHttp2ErrorCode())!!, null) + stream.close(ErrorCode.fromHttp2(peekedResponse.http2ErrorCode)!!, null) return } @@ -891,7 +891,7 @@ class MockWebServer : ExternalResource(), Closeable { val response: MockResponse = dispatcher.dispatch(request) - if (response.getSocketPolicy() === DISCONNECT_AFTER_REQUEST) { + if (response.socketPolicy === DISCONNECT_AFTER_REQUEST) { socket.close() return } @@ -902,7 +902,7 @@ class MockWebServer : ExternalResource(), Closeable { "and responded: $response protocol is $protocol") } - if (response.getSocketPolicy() === DISCONNECT_AT_END) { + if (response.socketPolicy === DISCONNECT_AT_END) { val connection = stream.connection connection.shutdown(ErrorCode.NO_ERROR) } @@ -933,7 +933,7 @@ class MockWebServer : ExternalResource(), Closeable { val headers = httpHeaders.build() val peek = dispatcher.peek() - if (!readBody && peek.getSocketPolicy() === EXPECT_CONTINUE) { + if (!readBody && peek.socketPolicy === EXPECT_CONTINUE) { val continueHeaders = listOf(Header(Header.RESPONSE_STATUS, "100 Continue".encodeUtf8())) stream.writeHeaders(continueHeaders, outFinished = false, flushHeaders = true) @@ -964,13 +964,14 @@ class MockWebServer : ExternalResource(), Closeable { val settings = response.settings stream.connection.setSettings(settings) - if (response.getSocketPolicy() === NO_RESPONSE) { + if (response.socketPolicy === NO_RESPONSE) { return } val http2Headers = mutableListOf
() - val statusParts = response.getStatus().split(' ', limit = 3) + val statusParts = response.status.split(' ', limit = 3) + if (statusParts.size < 2) { - throw AssertionError("Unexpected status: ${response.getStatus()}") + throw AssertionError("Unexpected status: ${response.status}") } // TODO: constants for well-known header names. http2Headers.add(Header(Header.RESPONSE_STATUS, statusParts[1])) diff --git a/mockwebserver/src/main/java/okhttp3/mockwebserver/QueueDispatcher.kt b/mockwebserver/src/main/java/okhttp3/mockwebserver/QueueDispatcher.kt index 3c38496c5..0a2e2436b 100644 --- a/mockwebserver/src/main/java/okhttp3/mockwebserver/QueueDispatcher.kt +++ b/mockwebserver/src/main/java/okhttp3/mockwebserver/QueueDispatcher.kt @@ -81,8 +81,10 @@ open class QueueDispatcher : Dispatcher() { * Enqueued on shutdown to release threads waiting on [dispatch]. Note that this response * isn't transmitted because the connection is closed before this response is returned. */ - private val DEAD_LETTER = MockResponse() - .setStatus("HTTP/1.1 $HTTP_UNAVAILABLE shutting down") + private val DEAD_LETTER = run { + val mockResponse = MockResponse() + mockResponse.apply { mockResponse.status = "HTTP/1.1 $HTTP_UNAVAILABLE shutting down" } + } private val logger = Logger.getLogger(QueueDispatcher::class.java.name) } diff --git a/okhttp/src/test/java/okhttp3/KotlinSourceModernTest.kt b/okhttp/src/test/java/okhttp3/KotlinSourceModernTest.kt index 5de59f600..3ab35067a 100644 --- a/okhttp/src/test/java/okhttp3/KotlinSourceModernTest.kt +++ b/okhttp/src/test/java/okhttp3/KotlinSourceModernTest.kt @@ -682,10 +682,10 @@ class KotlinSourceModernTest { @Test @Ignore fun mockResponse() { var mockResponse: MockResponse = MockResponse() - var status: String = mockResponse.getStatus() - status = mockResponse.getStatus() - mockResponse = mockResponse.setStatus("") - mockResponse.setStatus("") + var status: String = mockResponse.status + status = mockResponse.status + mockResponse = mockResponse.apply { mockResponse.status = "" } + mockResponse.status = "" mockResponse = mockResponse.setResponseCode(0) var headers: Headers = mockResponse.getHeaders() headers = mockResponse.getHeaders() @@ -705,13 +705,14 @@ class KotlinSourceModernTest { mockResponse.setBody(Buffer()) mockResponse = mockResponse.setChunkedBody(Buffer(), 0) mockResponse = mockResponse.setChunkedBody("", 0) - var socketPolicy: SocketPolicy = mockResponse.getSocketPolicy() - socketPolicy = mockResponse.getSocketPolicy() - mockResponse = mockResponse.setSocketPolicy(SocketPolicy.KEEP_OPEN) - var http2ErrorCode: Int = mockResponse.getHttp2ErrorCode() - http2ErrorCode = mockResponse.getHttp2ErrorCode() - mockResponse = mockResponse.setHttp2ErrorCode(0) - mockResponse.setHttp2ErrorCode(0) + var socketPolicy: SocketPolicy = mockResponse.socketPolicy + socketPolicy = mockResponse.socketPolicy + mockResponse = mockResponse.apply { mockResponse.socketPolicy = SocketPolicy.KEEP_OPEN } + mockResponse.socketPolicy = SocketPolicy.KEEP_OPEN + var http2ErrorCode: Int = mockResponse.http2ErrorCode + http2ErrorCode = mockResponse.http2ErrorCode + mockResponse = mockResponse.apply { mockResponse.http2ErrorCode = 0 } + mockResponse.http2ErrorCode = 0 mockResponse = mockResponse.throttleBody(0L, 0L, TimeUnit.SECONDS) var throttleBytesPerPeriod: Long = mockResponse.throttleBytesPerPeriod throttleBytesPerPeriod = mockResponse.throttleBytesPerPeriod