1
0
mirror of https://github.com/square/okhttp.git synced 2025-08-07 12:42:57 +03:00

Cover more of the OkHttp API for source compatibility

This commit is contained in:
Jesse Wilson
2019-04-06 13:20:41 -04:00
parent 631d6457b4
commit 2e947a2202
4 changed files with 273 additions and 110 deletions

View File

@@ -44,7 +44,7 @@ class HttpLoggingInterceptor @JvmOverloads constructor(
@Volatile private var headersToRedact = emptySet<String>() @Volatile private var headersToRedact = emptySet<String>()
@Volatile private var level = Level.NONE @Volatile @set:JvmName("-deprecated_setLevel") var level = Level.NONE
enum class Level { enum class Level {
/** No logs. */ /** No logs. */
@@ -109,6 +109,14 @@ class HttpLoggingInterceptor @JvmOverloads constructor(
fun log(message: String) fun log(message: String)
companion object { 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. */ /** A [Logger] defaults output appropriate for the current platform. */
@JvmField @JvmField
val DEFAULT: Logger = object : Logger { val DEFAULT: Logger = object : Logger {
@@ -126,11 +134,11 @@ class HttpLoggingInterceptor @JvmOverloads constructor(
headersToRedact = newHeadersToRedact headersToRedact = newHeadersToRedact
} }
/** Change the level at which this interceptor logs. */
fun setLevel(level: Level) = apply { fun setLevel(level: Level) = apply {
this.level = level this.level = level
} }
@JvmName("-deprecated_getLevel")
fun getLevel(): Level = level fun getLevel(): Level = level
@Throws(IOException::class) @Throws(IOException::class)
@@ -193,7 +201,7 @@ class HttpLoggingInterceptor @JvmOverloads constructor(
val charset: Charset = contentType?.charset(UTF8) ?: UTF8 val charset: Charset = contentType?.charset(UTF8) ?: UTF8
logger.log("") logger.log("")
if (isPlaintext(buffer)) { if (buffer.isUtf8()) {
logger.log(buffer.readString(charset)) logger.log(buffer.readString(charset))
logger.log("--> END ${request.method()} (${requestBody.contentLength()}-byte body)") logger.log("--> END ${request.method()} (${requestBody.contentLength()}-byte body)")
} else { } else {
@@ -247,7 +255,7 @@ class HttpLoggingInterceptor @JvmOverloads constructor(
val contentType = responseBody.contentType() val contentType = responseBody.contentType()
val charset: Charset = contentType?.charset(UTF8) ?: UTF8 val charset: Charset = contentType?.charset(UTF8) ?: UTF8
if (!isPlaintext(buffer)) { if (!buffer.isUtf8()) {
logger.log("") logger.log("")
logger.log("<-- END HTTP (binary ${buffer.size}-byte body omitted)") logger.log("<-- END HTTP (binary ${buffer.size}-byte body omitted)")
return response return response
@@ -278,16 +286,16 @@ class HttpLoggingInterceptor @JvmOverloads constructor(
private val UTF8 = StandardCharsets.UTF_8 private val UTF8 = StandardCharsets.UTF_8
/** /**
* Returns true if the body in question probably contains human readable text. Uses a small sample * Returns true if the body in question probably contains human readable text. Uses a small
* of code points to detect unicode control characters commonly used in binary file signatures. * sample of code points to detect unicode control characters commonly used in binary file
* signatures.
*/ */
@JvmStatic internal fun Buffer.isUtf8(): Boolean {
fun isPlaintext(buffer: Buffer): Boolean {
try { try {
val prefix = Buffer() val prefix = Buffer()
val byteCount = if (buffer.size < 64) buffer.size else 64 val byteCount = if (size < 64) size else 64
buffer.copyTo(prefix, 0, byteCount) copyTo(prefix, 0, byteCount)
for (i in 0..15) { for (i in 0 until 16) {
if (prefix.exhausted()) { if (prefix.exhausted()) {
break break
} }

View File

@@ -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()
}
}

View File

@@ -644,16 +644,6 @@ public final class HttpLoggingInterceptorTest {
.assertNoMoreLogs(); .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 { @Test public void responseBodyIsBinary() throws IOException {
setLevel(Level.BODY); setLevel(Level.BODY);
Buffer buffer = new Buffer(); Buffer buffer = new Buffer();

View File

@@ -17,6 +17,9 @@ package okhttp3
import okhttp3.internal.proxy.NullProxySelector import okhttp3.internal.proxy.NullProxySelector
import okhttp3.internal.tls.OkHostnameVerifier import okhttp3.internal.tls.OkHostnameVerifier
import okhttp3.logging.HttpLoggingInterceptor
import okhttp3.logging.LoggingEventListener
import okhttp3.tls.HandshakeCertificates
import okhttp3.tls.HeldCertificate import okhttp3.tls.HeldCertificate
import okhttp3.tls.internal.TlsUtil.localhost import okhttp3.tls.internal.TlsUtil.localhost
import okio.Buffer import okio.Buffer
@@ -28,6 +31,8 @@ import org.junit.Ignore
import org.junit.Test import org.junit.Test
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
import java.math.BigInteger
import java.net.CookieHandler
import java.net.InetAddress import java.net.InetAddress
import java.net.InetSocketAddress import java.net.InetSocketAddress
import java.net.Proxy import java.net.Proxy
@@ -36,6 +41,8 @@ import java.net.Socket
import java.net.URI import java.net.URI
import java.net.URL import java.net.URL
import java.nio.charset.Charset import java.nio.charset.Charset
import java.security.KeyPair
import java.security.KeyPairGenerator
import java.security.Principal import java.security.Principal
import java.security.cert.Certificate import java.security.cert.Certificate
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
@@ -47,8 +54,11 @@ import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.net.SocketFactory import javax.net.SocketFactory
import javax.net.ssl.HostnameVerifier import javax.net.ssl.HostnameVerifier
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocket import javax.net.ssl.SSLSocket
import javax.net.ssl.SSLSocketFactory 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 * 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 { class KotlinSourceCompatibilityTest {
@Test @Ignore @Test @Ignore
fun address() { fun address() {
val address: Address = Address( val address: Address = newAddress()
"",
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 url: HttpUrl = address.url() val url: HttpUrl = address.url()
val dns: Dns = address.dns() val dns: Dns = address.dns()
val socketFactory: SocketFactory = address.socketFactory() val socketFactory: SocketFactory = address.socketFactory()
@@ -158,16 +155,7 @@ class KotlinSourceCompatibilityTest {
@Test @Ignore @Test @Ignore
fun call() { fun call() {
val call = object : Call { val call: Call = newCall()
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()
}
} }
@Test @Ignore @Test @Ignore
@@ -470,40 +458,32 @@ class KotlinSourceCompatibilityTest {
} }
@Test @Ignore @Test @Ignore
fun okHttpClient() { fun httpLoggingInterceptor() {
val client: OkHttpClient = OkHttpClient() var interceptor: HttpLoggingInterceptor = HttpLoggingInterceptor()
val dispatcher: Dispatcher = client.dispatcher() interceptor = HttpLoggingInterceptor(HttpLoggingInterceptor.Logger.DEFAULT)
val proxy: Proxy? = client.proxy() interceptor.redactHeader("")
val protocols: List<Protocol> = client.protocols() interceptor.level = HttpLoggingInterceptor.Level.BASIC
val connectionSpecs: List<ConnectionSpec> = client.connectionSpecs() interceptor.setLevel(HttpLoggingInterceptor.Level.BASIC)
val interceptors: List<Interceptor> = client.interceptors() var level: HttpLoggingInterceptor.Level = interceptor.level
val networkInterceptors: List<Interceptor> = client.networkInterceptors() level = interceptor.getLevel()
val eventListenerFactory: EventListener.Factory = client.eventListenerFactory() interceptor.intercept(newInterceptorChain())
val proxySelector: ProxySelector = client.proxySelector() }
val cookieJar: CookieJar = client.cookieJar()
val cache: Cache? = client.cache() @Test @Ignore
val socketFactory: SocketFactory = client.socketFactory() fun httpLoggingInterceptorLevel() {
val sslSocketFactory: SSLSocketFactory = client.sslSocketFactory() val none: HttpLoggingInterceptor.Level = HttpLoggingInterceptor.Level.NONE
val hostnameVerifier: HostnameVerifier = client.hostnameVerifier() val basic: HttpLoggingInterceptor.Level = HttpLoggingInterceptor.Level.BASIC
val certificatePinner: CertificatePinner = client.certificatePinner() val headers: HttpLoggingInterceptor.Level = HttpLoggingInterceptor.Level.HEADERS
val proxyAuthenticator: Authenticator = client.proxyAuthenticator() val body: HttpLoggingInterceptor.Level = HttpLoggingInterceptor.Level.BODY
val authenticator: Authenticator = client.authenticator() }
val connectionPool: ConnectionPool = client.connectionPool()
val dns: Dns = client.dns() @Test @Ignore
val followSslRedirects: Boolean = client.followSslRedirects() fun httpLoggingInterceptorLogger() {
val followRedirects: Boolean = client.followRedirects() var logger: HttpLoggingInterceptor.Logger = object : HttpLoggingInterceptor.Logger {
val retryOnConnectionFailure: Boolean = client.retryOnConnectionFailure() override fun log(message: String) = TODO()
val callTimeoutMillis: Int = client.callTimeoutMillis() }
val connectTimeoutMillis: Int = client.connectTimeoutMillis() logger = HttpLoggingInterceptor.Logger { TODO() }
val readTimeoutMillis: Int = client.readTimeoutMillis() val default: HttpLoggingInterceptor.Logger = HttpLoggingInterceptor.Logger.DEFAULT
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 @Test @Ignore
@@ -585,18 +565,86 @@ class KotlinSourceCompatibilityTest {
@Test @Ignore @Test @Ignore
fun interceptorChain() { fun interceptorChain() {
val chain = object : Interceptor.Chain { val chain: Interceptor.Chain = newInterceptorChain()
override fun request(): Request = TODO() }
override fun proceed(request: Request): Response = TODO()
override fun connection(): Connection? = TODO() @Test @Ignore
override fun call(): Call = TODO() fun handshakeCertificates() {
override fun connectTimeoutMillis(): Int = TODO() val handshakeCertificates = HandshakeCertificates.Builder().build()
override fun withConnectTimeout(timeout: Int, unit: TimeUnit): Interceptor.Chain = TODO() val keyManager: X509KeyManager = handshakeCertificates.keyManager()
override fun readTimeoutMillis(): Int = TODO() val trustManager: X509TrustManager = handshakeCertificates.trustManager()
override fun withReadTimeout(timeout: Int, unit: TimeUnit): Interceptor.Chain = TODO() val sslSocketFactory: SSLSocketFactory = handshakeCertificates.sslSocketFactory()
override fun writeTimeoutMillis(): Int = TODO() val sslContext: SSLContext = handshakeCertificates.sslContext()
override fun withWriteTimeout(timeout: Int, unit: TimeUnit): Interceptor.Chain = TODO() }
@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<Cookie> = 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 @Test @Ignore
@@ -656,6 +704,43 @@ class KotlinSourceCompatibilityTest {
val multipartBody: MultipartBody = builder.build() 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<Protocol> = client.protocols()
val connectionSpecs: List<ConnectionSpec> = client.connectionSpecs()
val interceptors: List<Interceptor> = client.interceptors()
val networkInterceptors: List<Interceptor> = 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 @Test @Ignore
fun okHttpClientBuilder() { fun okHttpClientBuilder() {
var builder: OkHttpClient.Builder = OkHttpClient.Builder() var builder: OkHttpClient.Builder = OkHttpClient.Builder()
@@ -859,26 +944,10 @@ class KotlinSourceCompatibilityTest {
@Test @Ignore @Test @Ignore
fun route() { fun route() {
var proxy: Proxy = Proxy.NO_PROXY val route: Route = newRoute()
var address: Address = Address( val address: Address = route.address()
"", val proxy: Proxy = route.proxy()
0, val inetSocketAddress: InetSocketAddress = route.socketAddress()
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 requiresTunnel: Boolean = route.requiresTunnel() val requiresTunnel: Boolean = route.requiresTunnel()
} }
@@ -912,4 +981,67 @@ class KotlinSourceCompatibilityTest {
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) = TODO() 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<String, MutableList<String>>?
) = TODO()
override fun get(
uri: URI?,
requestHeaders: MutableMap<String, MutableList<String>>?
): MutableMap<String, MutableList<String>> = 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))
}
} }