diff --git a/okhttp-logging-interceptor/src/main/java/okhttp3/logging/HttpLoggingInterceptor.kt b/okhttp-logging-interceptor/src/main/java/okhttp3/logging/HttpLoggingInterceptor.kt index e4f39a379..2bc3364f0 100644 --- a/okhttp-logging-interceptor/src/main/java/okhttp3/logging/HttpLoggingInterceptor.kt +++ b/okhttp-logging-interceptor/src/main/java/okhttp3/logging/HttpLoggingInterceptor.kt @@ -44,7 +44,7 @@ class HttpLoggingInterceptor @JvmOverloads constructor( @Volatile private var headersToRedact = emptySet() - @Volatile private var level = Level.NONE + @Volatile @set:JvmName("-deprecated_setLevel") var level = Level.NONE enum class Level { /** No logs. */ @@ -109,6 +109,14 @@ class HttpLoggingInterceptor @JvmOverloads constructor( fun log(message: String) companion object { + // This lambda conversion is for Kotlin callers expecting a Java SAM (single-abstract-method). + @JvmName("-deprecated_Logger") + inline operator fun invoke( + crossinline block: (message: String) -> Unit + ): Logger = object : Logger { + override fun log(message: String) = block(message) + } + /** A [Logger] defaults output appropriate for the current platform. */ @JvmField val DEFAULT: Logger = object : Logger { @@ -126,11 +134,11 @@ class HttpLoggingInterceptor @JvmOverloads constructor( headersToRedact = newHeadersToRedact } - /** Change the level at which this interceptor logs. */ fun setLevel(level: Level) = apply { this.level = level } + @JvmName("-deprecated_getLevel") fun getLevel(): Level = level @Throws(IOException::class) @@ -193,7 +201,7 @@ class HttpLoggingInterceptor @JvmOverloads constructor( val charset: Charset = contentType?.charset(UTF8) ?: UTF8 logger.log("") - if (isPlaintext(buffer)) { + if (buffer.isUtf8()) { logger.log(buffer.readString(charset)) logger.log("--> END ${request.method()} (${requestBody.contentLength()}-byte body)") } else { @@ -247,7 +255,7 @@ class HttpLoggingInterceptor @JvmOverloads constructor( val contentType = responseBody.contentType() val charset: Charset = contentType?.charset(UTF8) ?: UTF8 - if (!isPlaintext(buffer)) { + if (!buffer.isUtf8()) { logger.log("") logger.log("<-- END HTTP (binary ${buffer.size}-byte body omitted)") return response @@ -278,16 +286,16 @@ class HttpLoggingInterceptor @JvmOverloads constructor( private val UTF8 = StandardCharsets.UTF_8 /** - * Returns true if the body in question probably contains human readable text. Uses a small sample - * of code points to detect unicode control characters commonly used in binary file signatures. + * Returns true if the body in question probably contains human readable text. Uses a small + * sample of code points to detect unicode control characters commonly used in binary file + * signatures. */ - @JvmStatic - fun isPlaintext(buffer: Buffer): Boolean { + internal fun Buffer.isUtf8(): Boolean { try { val prefix = Buffer() - val byteCount = if (buffer.size < 64) buffer.size else 64 - buffer.copyTo(prefix, 0, byteCount) - for (i in 0..15) { + val byteCount = if (size < 64) size else 64 + copyTo(prefix, 0, byteCount) + for (i in 0 until 16) { if (prefix.exhausted()) { break } diff --git a/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorKotlinTest.kt b/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorKotlinTest.kt new file mode 100644 index 000000000..05d63c968 --- /dev/null +++ b/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorKotlinTest.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package okhttp3.logging + +import okhttp3.logging.HttpLoggingInterceptor.Companion.isUtf8 +import okio.Buffer +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test + +class HttpLoggingInterceptorKotlinTest { + @Test fun isPlaintext() { + assertThat(Buffer().isUtf8()).isTrue() + assertThat(Buffer().writeUtf8("abc").isUtf8()).isTrue() + assertThat(Buffer().writeUtf8("new\r\nlines").isUtf8()).isTrue() + assertThat(Buffer().writeUtf8("white\t space").isUtf8()).isTrue() + assertThat(Buffer().writeByte(0x80).isUtf8()).isTrue() + assertThat(Buffer().writeByte(0x00).isUtf8()).isFalse() + assertThat(Buffer().writeByte(0xc0).isUtf8()).isFalse() + } +} diff --git a/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.java b/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.java index 67384c29d..1ca1d488a 100644 --- a/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.java +++ b/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.java @@ -644,16 +644,6 @@ public final class HttpLoggingInterceptorTest { .assertNoMoreLogs(); } - @Test public void isPlaintext() { - assertThat(HttpLoggingInterceptor.isPlaintext(new Buffer())).isTrue(); - assertThat(HttpLoggingInterceptor.isPlaintext(new Buffer().writeUtf8("abc"))).isTrue(); - assertThat(HttpLoggingInterceptor.isPlaintext(new Buffer().writeUtf8("new\r\nlines"))).isTrue(); - assertThat(HttpLoggingInterceptor.isPlaintext(new Buffer().writeUtf8("white\t space"))).isTrue(); - assertThat(HttpLoggingInterceptor.isPlaintext(new Buffer().writeByte(0x80))).isTrue(); - assertThat(HttpLoggingInterceptor.isPlaintext(new Buffer().writeByte(0x00))).isFalse(); - assertThat(HttpLoggingInterceptor.isPlaintext(new Buffer().writeByte(0xc0))).isFalse(); - } - @Test public void responseBodyIsBinary() throws IOException { setLevel(Level.BODY); Buffer buffer = new Buffer(); diff --git a/okhttp/src/test/java/okhttp3/KotlinSourceCompatibilityTest.kt b/okhttp/src/test/java/okhttp3/KotlinSourceCompatibilityTest.kt index 70a2bd5a1..08ee9d93f 100644 --- a/okhttp/src/test/java/okhttp3/KotlinSourceCompatibilityTest.kt +++ b/okhttp/src/test/java/okhttp3/KotlinSourceCompatibilityTest.kt @@ -17,6 +17,9 @@ package okhttp3 import okhttp3.internal.proxy.NullProxySelector import okhttp3.internal.tls.OkHostnameVerifier +import okhttp3.logging.HttpLoggingInterceptor +import okhttp3.logging.LoggingEventListener +import okhttp3.tls.HandshakeCertificates import okhttp3.tls.HeldCertificate import okhttp3.tls.internal.TlsUtil.localhost import okio.Buffer @@ -28,6 +31,8 @@ import org.junit.Ignore import org.junit.Test import java.io.File import java.io.IOException +import java.math.BigInteger +import java.net.CookieHandler import java.net.InetAddress import java.net.InetSocketAddress import java.net.Proxy @@ -36,6 +41,8 @@ import java.net.Socket import java.net.URI import java.net.URL import java.nio.charset.Charset +import java.security.KeyPair +import java.security.KeyPairGenerator import java.security.Principal import java.security.cert.Certificate import java.security.cert.X509Certificate @@ -47,8 +54,11 @@ import java.util.concurrent.Executors import java.util.concurrent.TimeUnit import javax.net.SocketFactory import javax.net.ssl.HostnameVerifier +import javax.net.ssl.SSLContext import javax.net.ssl.SSLSocket import javax.net.ssl.SSLSocketFactory +import javax.net.ssl.X509KeyManager +import javax.net.ssl.X509TrustManager /** * Access every type, function, and property from Kotlin to defend against unexpected regressions in @@ -71,20 +81,7 @@ import javax.net.ssl.SSLSocketFactory class KotlinSourceCompatibilityTest { @Test @Ignore fun address() { - val address: Address = Address( - "", - 0, - Dns.SYSTEM, - SocketFactory.getDefault(), - localhost().sslSocketFactory(), - OkHostnameVerifier.INSTANCE, - CertificatePinner.DEFAULT, - Authenticator.NONE, - Proxy.NO_PROXY, - listOf(Protocol.HTTP_1_1), - listOf(ConnectionSpec.MODERN_TLS), - NullProxySelector() - ) + val address: Address = newAddress() val url: HttpUrl = address.url() val dns: Dns = address.dns() val socketFactory: SocketFactory = address.socketFactory() @@ -158,16 +155,7 @@ class KotlinSourceCompatibilityTest { @Test @Ignore fun call() { - val call = object : Call { - override fun request(): Request = TODO() - override fun execute(): Response = TODO() - override fun enqueue(responseCallback: Callback) = TODO() - override fun cancel() = TODO() - override fun isExecuted(): Boolean = TODO() - override fun isCanceled(): Boolean = TODO() - override fun timeout(): Timeout = TODO() - override fun clone(): Call = TODO() - } + val call: Call = newCall() } @Test @Ignore @@ -470,40 +458,32 @@ class KotlinSourceCompatibilityTest { } @Test @Ignore - fun okHttpClient() { - val client: OkHttpClient = OkHttpClient() - val dispatcher: Dispatcher = client.dispatcher() - val proxy: Proxy? = client.proxy() - val protocols: List = client.protocols() - val connectionSpecs: List = client.connectionSpecs() - val interceptors: List = client.interceptors() - val networkInterceptors: List = client.networkInterceptors() - val eventListenerFactory: EventListener.Factory = client.eventListenerFactory() - val proxySelector: ProxySelector = client.proxySelector() - val cookieJar: CookieJar = client.cookieJar() - val cache: Cache? = client.cache() - val socketFactory: SocketFactory = client.socketFactory() - val sslSocketFactory: SSLSocketFactory = client.sslSocketFactory() - val hostnameVerifier: HostnameVerifier = client.hostnameVerifier() - val certificatePinner: CertificatePinner = client.certificatePinner() - val proxyAuthenticator: Authenticator = client.proxyAuthenticator() - val authenticator: Authenticator = client.authenticator() - val connectionPool: ConnectionPool = client.connectionPool() - val dns: Dns = client.dns() - val followSslRedirects: Boolean = client.followSslRedirects() - val followRedirects: Boolean = client.followRedirects() - val retryOnConnectionFailure: Boolean = client.retryOnConnectionFailure() - val callTimeoutMillis: Int = client.callTimeoutMillis() - val connectTimeoutMillis: Int = client.connectTimeoutMillis() - val readTimeoutMillis: Int = client.readTimeoutMillis() - val writeTimeoutMillis: Int = client.writeTimeoutMillis() - val pingIntervalMillis: Int = client.pingIntervalMillis() - val call: Call = client.newCall(Request.Builder().build()) - val webSocket: WebSocket = client.newWebSocket( - Request.Builder().build(), - object : WebSocketListener() { - }) - val newBuilder: OkHttpClient.Builder = client.newBuilder() + fun httpLoggingInterceptor() { + var interceptor: HttpLoggingInterceptor = HttpLoggingInterceptor() + interceptor = HttpLoggingInterceptor(HttpLoggingInterceptor.Logger.DEFAULT) + interceptor.redactHeader("") + interceptor.level = HttpLoggingInterceptor.Level.BASIC + interceptor.setLevel(HttpLoggingInterceptor.Level.BASIC) + var level: HttpLoggingInterceptor.Level = interceptor.level + level = interceptor.getLevel() + interceptor.intercept(newInterceptorChain()) + } + + @Test @Ignore + fun httpLoggingInterceptorLevel() { + val none: HttpLoggingInterceptor.Level = HttpLoggingInterceptor.Level.NONE + val basic: HttpLoggingInterceptor.Level = HttpLoggingInterceptor.Level.BASIC + val headers: HttpLoggingInterceptor.Level = HttpLoggingInterceptor.Level.HEADERS + val body: HttpLoggingInterceptor.Level = HttpLoggingInterceptor.Level.BODY + } + + @Test @Ignore + fun httpLoggingInterceptorLogger() { + var logger: HttpLoggingInterceptor.Logger = object : HttpLoggingInterceptor.Logger { + override fun log(message: String) = TODO() + } + logger = HttpLoggingInterceptor.Logger { TODO() } + val default: HttpLoggingInterceptor.Logger = HttpLoggingInterceptor.Logger.DEFAULT } @Test @Ignore @@ -585,18 +565,86 @@ class KotlinSourceCompatibilityTest { @Test @Ignore fun interceptorChain() { - val chain = object : Interceptor.Chain { - override fun request(): Request = TODO() - override fun proceed(request: Request): Response = TODO() - override fun connection(): Connection? = TODO() - override fun call(): Call = TODO() - override fun connectTimeoutMillis(): Int = TODO() - override fun withConnectTimeout(timeout: Int, unit: TimeUnit): Interceptor.Chain = TODO() - override fun readTimeoutMillis(): Int = TODO() - override fun withReadTimeout(timeout: Int, unit: TimeUnit): Interceptor.Chain = TODO() - override fun writeTimeoutMillis(): Int = TODO() - override fun withWriteTimeout(timeout: Int, unit: TimeUnit): Interceptor.Chain = TODO() + val chain: Interceptor.Chain = newInterceptorChain() + } + + @Test @Ignore + fun handshakeCertificates() { + val handshakeCertificates = HandshakeCertificates.Builder().build() + val keyManager: X509KeyManager = handshakeCertificates.keyManager() + val trustManager: X509TrustManager = handshakeCertificates.trustManager() + val sslSocketFactory: SSLSocketFactory = handshakeCertificates.sslSocketFactory() + val sslContext: SSLContext = handshakeCertificates.sslContext() + } + + @Test @Ignore + fun handshakeCertificatesBuilder() { + var builder: HandshakeCertificates.Builder = HandshakeCertificates.Builder() + val heldCertificate = HeldCertificate.Builder().build() + builder = builder.heldCertificate(heldCertificate, heldCertificate.certificate()) + builder = builder.addTrustedCertificate(heldCertificate.certificate()) + builder = builder.addPlatformTrustedCertificates() + val handshakeCertificates: HandshakeCertificates = builder.build() + } + + @Test @Ignore + fun heldCertificate() { + val heldCertificate: HeldCertificate = HeldCertificate.Builder().build() + val certificate: X509Certificate = heldCertificate.certificate() + val keyPair: KeyPair = heldCertificate.keyPair() + val certificatePem: String = heldCertificate.certificatePem() + val privateKeyPkcs8Pem: String = heldCertificate.privateKeyPkcs8Pem() + val privateKeyPkcs1Pem: String = heldCertificate.privateKeyPkcs1Pem() + } + + @Test @Ignore + fun heldCertificateBuilder() { + val keyPair: KeyPair = KeyPairGenerator.getInstance("").genKeyPair() + var builder: HeldCertificate.Builder = HeldCertificate.Builder() + builder = builder.validityInterval(0L, 0L) + builder = builder.duration(0L, TimeUnit.SECONDS) + builder = builder.addSubjectAlternativeName("") + builder = builder.commonName("") + builder = builder.organizationalUnit("") + builder = builder.serialNumber(BigInteger.ZERO) + builder = builder.serialNumber(0L) + builder = builder.keyPair(keyPair) + builder = builder.keyPair(keyPair.public, keyPair.private) + builder = builder.signedBy(HeldCertificate.Builder().build()) + builder = builder.certificateAuthority(0) + builder = builder.ecdsa256() + builder = builder.rsa2048() + val heldCertificate: HeldCertificate = builder.build() + } + + @Test @Ignore + fun javaNetAuthenticator() { + val authenticator = JavaNetAuthenticator() + val response = Response.Builder().build() + val request: Request? = authenticator.authenticate(newRoute(), response) + } + + @Test @Ignore + fun javaNetCookieJar() { + val cookieJar: JavaNetCookieJar = JavaNetCookieJar(newCookieHandler()) + val httpUrl = HttpUrl.get("") + val loadForRequest: List = cookieJar.loadForRequest(httpUrl) + cookieJar.saveFromResponse(httpUrl, listOf(Cookie.Builder().build())) + } + + @Test @Ignore + fun loggingEventListener() { + var loggingEventListener: EventListener = LoggingEventListener.Factory().create(newCall()) + } + + @Test @Ignore + fun loggingEventListenerFactory() { + var factory: LoggingEventListener.Factory = LoggingEventListener.Factory() + factory = LoggingEventListener.Factory(HttpLoggingInterceptor.Logger.DEFAULT) + factory = object : LoggingEventListener.Factory() { + override fun create(call: Call): EventListener = TODO() } + val eventListener: EventListener = factory.create(newCall()) } @Test @Ignore @@ -656,6 +704,43 @@ class KotlinSourceCompatibilityTest { val multipartBody: MultipartBody = builder.build() } + @Test @Ignore + fun okHttpClient() { + val client: OkHttpClient = OkHttpClient() + val dispatcher: Dispatcher = client.dispatcher() + val proxy: Proxy? = client.proxy() + val protocols: List = client.protocols() + val connectionSpecs: List = client.connectionSpecs() + val interceptors: List = client.interceptors() + val networkInterceptors: List = client.networkInterceptors() + val eventListenerFactory: EventListener.Factory = client.eventListenerFactory() + val proxySelector: ProxySelector = client.proxySelector() + val cookieJar: CookieJar = client.cookieJar() + val cache: Cache? = client.cache() + val socketFactory: SocketFactory = client.socketFactory() + val sslSocketFactory: SSLSocketFactory = client.sslSocketFactory() + val hostnameVerifier: HostnameVerifier = client.hostnameVerifier() + val certificatePinner: CertificatePinner = client.certificatePinner() + val proxyAuthenticator: Authenticator = client.proxyAuthenticator() + val authenticator: Authenticator = client.authenticator() + val connectionPool: ConnectionPool = client.connectionPool() + val dns: Dns = client.dns() + val followSslRedirects: Boolean = client.followSslRedirects() + val followRedirects: Boolean = client.followRedirects() + val retryOnConnectionFailure: Boolean = client.retryOnConnectionFailure() + val callTimeoutMillis: Int = client.callTimeoutMillis() + val connectTimeoutMillis: Int = client.connectTimeoutMillis() + val readTimeoutMillis: Int = client.readTimeoutMillis() + val writeTimeoutMillis: Int = client.writeTimeoutMillis() + val pingIntervalMillis: Int = client.pingIntervalMillis() + val call: Call = client.newCall(Request.Builder().build()) + val webSocket: WebSocket = client.newWebSocket( + Request.Builder().build(), + object : WebSocketListener() { + }) + val newBuilder: OkHttpClient.Builder = client.newBuilder() + } + @Test @Ignore fun okHttpClientBuilder() { var builder: OkHttpClient.Builder = OkHttpClient.Builder() @@ -859,26 +944,10 @@ class KotlinSourceCompatibilityTest { @Test @Ignore fun route() { - var proxy: Proxy = Proxy.NO_PROXY - var address: Address = Address( - "", - 0, - Dns.SYSTEM, - SocketFactory.getDefault(), - localhost().sslSocketFactory(), - OkHostnameVerifier.INSTANCE, - CertificatePinner.DEFAULT, - Authenticator.NONE, - proxy, - listOf(Protocol.HTTP_1_1), - listOf(ConnectionSpec.MODERN_TLS), - NullProxySelector() - ) - var inetSocketAddress: InetSocketAddress = InetSocketAddress.createUnresolved("", 0) - val route: Route = Route(address, proxy, inetSocketAddress) - address = route.address() - proxy = route.proxy() - inetSocketAddress = route.socketAddress() + val route: Route = newRoute() + val address: Address = route.address() + val proxy: Proxy = route.proxy() + val inetSocketAddress: InetSocketAddress = route.socketAddress() val requiresTunnel: Boolean = route.requiresTunnel() } @@ -912,4 +981,67 @@ class KotlinSourceCompatibilityTest { override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) = TODO() } } + + private fun newAddress(): Address { + return Address( + "", + 0, + Dns.SYSTEM, + SocketFactory.getDefault(), + localhost().sslSocketFactory(), + OkHostnameVerifier.INSTANCE, + CertificatePinner.DEFAULT, + Authenticator.NONE, + Proxy.NO_PROXY, + listOf(Protocol.HTTP_1_1), + listOf(ConnectionSpec.MODERN_TLS), + NullProxySelector() + ) + } + + private fun newCall(): Call { + return object : Call { + override fun request(): Request = TODO() + override fun execute(): Response = TODO() + override fun enqueue(responseCallback: Callback) = TODO() + override fun cancel() = TODO() + override fun isExecuted(): Boolean = TODO() + override fun isCanceled(): Boolean = TODO() + override fun timeout(): Timeout = TODO() + override fun clone(): Call = TODO() + } + } + + private fun newCookieHandler(): CookieHandler { + return object : CookieHandler() { + override fun put( + uri: URI?, + responseHeaders: MutableMap>? + ) = TODO() + + override fun get( + uri: URI?, + requestHeaders: MutableMap>? + ): MutableMap> = TODO() + } + } + + private fun newInterceptorChain(): Interceptor.Chain { + return object : Interceptor.Chain { + override fun request(): Request = TODO() + override fun proceed(request: Request): Response = TODO() + override fun connection(): Connection? = TODO() + override fun call(): Call = TODO() + override fun connectTimeoutMillis(): Int = TODO() + override fun withConnectTimeout(timeout: Int, unit: TimeUnit): Interceptor.Chain = TODO() + override fun readTimeoutMillis(): Int = TODO() + override fun withReadTimeout(timeout: Int, unit: TimeUnit): Interceptor.Chain = TODO() + override fun writeTimeoutMillis(): Int = TODO() + override fun withWriteTimeout(timeout: Int, unit: TimeUnit): Interceptor.Chain = TODO() + } + } + + private fun newRoute(): Route { + return Route(newAddress(), Proxy.NO_PROXY, InetSocketAddress.createUnresolved("", 0)) + } } \ No newline at end of file