mirror of
https://github.com/square/okhttp.git
synced 2026-01-12 10:23:16 +03:00
Allow OkHttpClient overrides in Interceptor (#9108)
Allow OkHttpClient overrides in Interceptor, generally anything settable on OkHttpClient.Builder can be overridden in application interceptor. Tests that the effect of overrides takes effect and can be reversed.
This commit is contained in:
@@ -170,9 +170,6 @@ class TestValueFactory : Closeable {
|
||||
index = 0,
|
||||
exchange = null,
|
||||
request = call.request(),
|
||||
connectTimeoutMillis = 10_000,
|
||||
readTimeoutMillis = 10_000,
|
||||
writeTimeoutMillis = 10_000,
|
||||
)
|
||||
|
||||
fun newRoutePlanner(
|
||||
|
||||
@@ -749,12 +749,42 @@ public abstract interface class okhttp3/Interceptor$Chain {
|
||||
public abstract fun call ()Lokhttp3/Call;
|
||||
public abstract fun connectTimeoutMillis ()I
|
||||
public abstract fun connection ()Lokhttp3/Connection;
|
||||
public abstract fun getAuthenticator ()Lokhttp3/Authenticator;
|
||||
public abstract fun getCache ()Lokhttp3/Cache;
|
||||
public abstract fun getCertificatePinner ()Lokhttp3/CertificatePinner;
|
||||
public abstract fun getConnectionPool ()Lokhttp3/ConnectionPool;
|
||||
public abstract fun getCookieJar ()Lokhttp3/CookieJar;
|
||||
public abstract fun getDns ()Lokhttp3/Dns;
|
||||
public abstract fun getEventListener ()Lokhttp3/EventListener;
|
||||
public abstract fun getFollowRedirects ()Z
|
||||
public abstract fun getFollowSslRedirects ()Z
|
||||
public abstract fun getHostnameVerifier ()Ljavax/net/ssl/HostnameVerifier;
|
||||
public abstract fun getProxy ()Ljava/net/Proxy;
|
||||
public abstract fun getProxyAuthenticator ()Lokhttp3/Authenticator;
|
||||
public abstract fun getProxySelector ()Ljava/net/ProxySelector;
|
||||
public abstract fun getRetryOnConnectionFailure ()Z
|
||||
public abstract fun getSocketFactory ()Ljavax/net/SocketFactory;
|
||||
public abstract fun getSslSocketFactoryOrNull ()Ljavax/net/ssl/SSLSocketFactory;
|
||||
public abstract fun getX509TrustManagerOrNull ()Ljavax/net/ssl/X509TrustManager;
|
||||
public abstract fun proceed (Lokhttp3/Request;)Lokhttp3/Response;
|
||||
public abstract fun readTimeoutMillis ()I
|
||||
public abstract fun request ()Lokhttp3/Request;
|
||||
public abstract fun withConnectTimeout (ILjava/util/concurrent/TimeUnit;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withReadTimeout (ILjava/util/concurrent/TimeUnit;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withWriteTimeout (ILjava/util/concurrent/TimeUnit;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withAuthenticator (Lokhttp3/Authenticator;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withCache (Lokhttp3/Cache;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withCertificatePinner (Lokhttp3/CertificatePinner;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withConnectTimeout (JLjava/util/concurrent/TimeUnit;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withConnectionPool (Lokhttp3/ConnectionPool;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withCookieJar (Lokhttp3/CookieJar;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withDns (Lokhttp3/Dns;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withHostnameVerifier (Ljavax/net/ssl/HostnameVerifier;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withProxy (Ljava/net/Proxy;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withProxyAuthenticator (Lokhttp3/Authenticator;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withProxySelector (Ljava/net/ProxySelector;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withReadTimeout (JLjava/util/concurrent/TimeUnit;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withRetryOnConnectionFailure (Z)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withSocketFactory (Ljavax/net/SocketFactory;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withSslSocketFactory (Ljavax/net/ssl/SSLSocketFactory;Ljavax/net/ssl/X509TrustManager;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withWriteTimeout (JLjava/util/concurrent/TimeUnit;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun writeTimeoutMillis ()I
|
||||
}
|
||||
|
||||
|
||||
@@ -749,12 +749,42 @@ public abstract interface class okhttp3/Interceptor$Chain {
|
||||
public abstract fun call ()Lokhttp3/Call;
|
||||
public abstract fun connectTimeoutMillis ()I
|
||||
public abstract fun connection ()Lokhttp3/Connection;
|
||||
public abstract fun getAuthenticator ()Lokhttp3/Authenticator;
|
||||
public abstract fun getCache ()Lokhttp3/Cache;
|
||||
public abstract fun getCertificatePinner ()Lokhttp3/CertificatePinner;
|
||||
public abstract fun getConnectionPool ()Lokhttp3/ConnectionPool;
|
||||
public abstract fun getCookieJar ()Lokhttp3/CookieJar;
|
||||
public abstract fun getDns ()Lokhttp3/Dns;
|
||||
public abstract fun getEventListener ()Lokhttp3/EventListener;
|
||||
public abstract fun getFollowRedirects ()Z
|
||||
public abstract fun getFollowSslRedirects ()Z
|
||||
public abstract fun getHostnameVerifier ()Ljavax/net/ssl/HostnameVerifier;
|
||||
public abstract fun getProxy ()Ljava/net/Proxy;
|
||||
public abstract fun getProxyAuthenticator ()Lokhttp3/Authenticator;
|
||||
public abstract fun getProxySelector ()Ljava/net/ProxySelector;
|
||||
public abstract fun getRetryOnConnectionFailure ()Z
|
||||
public abstract fun getSocketFactory ()Ljavax/net/SocketFactory;
|
||||
public abstract fun getSslSocketFactoryOrNull ()Ljavax/net/ssl/SSLSocketFactory;
|
||||
public abstract fun getX509TrustManagerOrNull ()Ljavax/net/ssl/X509TrustManager;
|
||||
public abstract fun proceed (Lokhttp3/Request;)Lokhttp3/Response;
|
||||
public abstract fun readTimeoutMillis ()I
|
||||
public abstract fun request ()Lokhttp3/Request;
|
||||
public abstract fun withConnectTimeout (ILjava/util/concurrent/TimeUnit;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withReadTimeout (ILjava/util/concurrent/TimeUnit;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withWriteTimeout (ILjava/util/concurrent/TimeUnit;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withAuthenticator (Lokhttp3/Authenticator;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withCache (Lokhttp3/Cache;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withCertificatePinner (Lokhttp3/CertificatePinner;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withConnectTimeout (JLjava/util/concurrent/TimeUnit;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withConnectionPool (Lokhttp3/ConnectionPool;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withCookieJar (Lokhttp3/CookieJar;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withDns (Lokhttp3/Dns;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withHostnameVerifier (Ljavax/net/ssl/HostnameVerifier;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withProxy (Ljava/net/Proxy;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withProxyAuthenticator (Lokhttp3/Authenticator;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withProxySelector (Ljava/net/ProxySelector;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withReadTimeout (JLjava/util/concurrent/TimeUnit;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withRetryOnConnectionFailure (Z)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withSocketFactory (Ljavax/net/SocketFactory;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withSslSocketFactory (Ljavax/net/ssl/SSLSocketFactory;Ljavax/net/ssl/X509TrustManager;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun withWriteTimeout (JLjava/util/concurrent/TimeUnit;)Lokhttp3/Interceptor$Chain;
|
||||
public abstract fun writeTimeoutMillis ()I
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,14 @@
|
||||
package okhttp3
|
||||
|
||||
import java.io.IOException
|
||||
import java.net.Proxy
|
||||
import java.net.ProxySelector
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.net.SocketFactory
|
||||
import javax.net.ssl.HostnameVerifier
|
||||
import javax.net.ssl.SSLSocketFactory
|
||||
import javax.net.ssl.X509TrustManager
|
||||
import okhttp3.internal.tls.CertificateChainCleaner
|
||||
|
||||
/**
|
||||
* Observes, modifies, and potentially short-circuits requests going out and the corresponding
|
||||
@@ -82,31 +89,210 @@ fun interface Interceptor {
|
||||
|
||||
/**
|
||||
* Returns the connection the request will be executed on. This is only available in the chains
|
||||
* of network interceptors; for application interceptors this is always null.
|
||||
* of network interceptors. For application interceptors this is always null.
|
||||
*/
|
||||
fun connection(): Connection?
|
||||
|
||||
/**
|
||||
* Returns the `Call` to which this chain belongs.
|
||||
*/
|
||||
fun call(): Call
|
||||
|
||||
/**
|
||||
* Returns the connect timeout in milliseconds.
|
||||
*/
|
||||
fun connectTimeoutMillis(): Int
|
||||
|
||||
/**
|
||||
* Returns a new chain with the specified connect timeout.
|
||||
*/
|
||||
fun withConnectTimeout(
|
||||
timeout: Int,
|
||||
timeout: Long,
|
||||
unit: TimeUnit,
|
||||
): Chain
|
||||
|
||||
/**
|
||||
* Returns the read timeout in milliseconds.
|
||||
*/
|
||||
fun readTimeoutMillis(): Int
|
||||
|
||||
/**
|
||||
* Returns a new chain with the specified read timeout.
|
||||
*/
|
||||
fun withReadTimeout(
|
||||
timeout: Int,
|
||||
timeout: Long,
|
||||
unit: TimeUnit,
|
||||
): Chain
|
||||
|
||||
/**
|
||||
* Returns the write timeout in milliseconds.
|
||||
*/
|
||||
fun writeTimeoutMillis(): Int
|
||||
|
||||
/**
|
||||
* Returns a new chain with the specified write timeout.
|
||||
*/
|
||||
fun withWriteTimeout(
|
||||
timeout: Int,
|
||||
timeout: Long,
|
||||
unit: TimeUnit,
|
||||
): Chain
|
||||
|
||||
val followSslRedirects: Boolean
|
||||
|
||||
val followRedirects: Boolean
|
||||
|
||||
/**
|
||||
* Get the [DNS] instance for the OkHttpClient, or an override from the Call.Chain.
|
||||
*/
|
||||
val dns: Dns
|
||||
|
||||
/**
|
||||
* Override the [DNS] for the Call.Chain.
|
||||
*
|
||||
* @throws IllegalStateException if this is a Network Interceptor, since the override is too late.
|
||||
*/
|
||||
fun withDns(dns: Dns): Chain
|
||||
|
||||
/**
|
||||
* Returns the [SocketFactory] for the OkHttpClient, or an override from the Call.Chain.
|
||||
*/
|
||||
val socketFactory: SocketFactory
|
||||
|
||||
/**
|
||||
* Override the [SocketFactory] for the Call.Chain.
|
||||
*
|
||||
* @throws IllegalStateException if this is a Network Interceptor, since the override is too late.
|
||||
*/
|
||||
fun withSocketFactory(socketFactory: SocketFactory): Chain
|
||||
|
||||
/**
|
||||
* Returns true if the call should retry on connection failures.
|
||||
*/
|
||||
val retryOnConnectionFailure: Boolean
|
||||
|
||||
/**
|
||||
* Returns a new chain with the specified retry on connection failure setting.
|
||||
*/
|
||||
fun withRetryOnConnectionFailure(retryOnConnectionFailure: Boolean): Chain
|
||||
|
||||
/**
|
||||
* Returns the [Authenticator] for the OkHttpClient, or an override from the Call.Chain.
|
||||
*/
|
||||
val authenticator: Authenticator
|
||||
|
||||
/**
|
||||
* Override the [Authenticator] for the Call.Chain.
|
||||
*
|
||||
* @throws IllegalStateException if this is a Network Interceptor, since the override is too late.
|
||||
*/
|
||||
fun withAuthenticator(authenticator: Authenticator): Chain
|
||||
|
||||
/**
|
||||
* Returns the [CookieJar] for the OkHttpClient, or an override from the Call.Chain.
|
||||
*/
|
||||
val cookieJar: CookieJar
|
||||
|
||||
/**
|
||||
* Returns a new chain with the specified [CookieJar].
|
||||
*/
|
||||
fun withCookieJar(cookieJar: CookieJar): Chain
|
||||
|
||||
/**
|
||||
* Returns the [Cache] for the OkHttpClient, or an override from the Call.Chain.
|
||||
*/
|
||||
val cache: Cache?
|
||||
|
||||
/**
|
||||
* Override the [Cache] for the Call.Chain.
|
||||
*
|
||||
* @throws IllegalStateException if this is a Network Interceptor, since the override is too late.
|
||||
*/
|
||||
fun withCache(cache: Cache?): Chain
|
||||
|
||||
/**
|
||||
* Returns the [Proxy] for the OkHttpClient, or an override from the Call.Chain.
|
||||
*/
|
||||
val proxy: Proxy?
|
||||
|
||||
/**
|
||||
* Returns a new chain with the specified [Proxy].
|
||||
*/
|
||||
fun withProxy(proxy: Proxy?): Chain
|
||||
|
||||
/**
|
||||
* Returns the [ProxySelector] for the OkHttpClient, or an override from the Call.Chain.
|
||||
*/
|
||||
val proxySelector: ProxySelector
|
||||
|
||||
/**
|
||||
* Override the [ProxySelector] for the Call.Chain.
|
||||
*
|
||||
* @throws IllegalStateException if this is a Network Interceptor, since the override is too late.
|
||||
*/
|
||||
fun withProxySelector(proxySelector: ProxySelector): Chain
|
||||
|
||||
/**
|
||||
* Returns the proxy [Authenticator] for the OkHttpClient, or an override from the Call.Chain.
|
||||
*/
|
||||
val proxyAuthenticator: Authenticator
|
||||
|
||||
/**
|
||||
* Returns a new chain with the specified proxy [Authenticator].
|
||||
*/
|
||||
fun withProxyAuthenticator(proxyAuthenticator: Authenticator): Chain
|
||||
|
||||
/**
|
||||
* Returns the [SSLSocketFactory] for the OkHttpClient, or an override from the Call.Chain.
|
||||
*/
|
||||
val sslSocketFactoryOrNull: SSLSocketFactory?
|
||||
|
||||
/**
|
||||
* Returns a new chain with the specified [SSLSocketFactory].
|
||||
*
|
||||
* @throws IllegalStateException if this is a Network Interceptor, since the override is too late.
|
||||
*/
|
||||
fun withSslSocketFactory(
|
||||
sslSocketFactory: SSLSocketFactory?,
|
||||
x509TrustManager: X509TrustManager?,
|
||||
): Chain
|
||||
|
||||
/**
|
||||
* Returns the [X509TrustManager] for the OkHttpClient, or an override from the Call.Chain.
|
||||
*/
|
||||
val x509TrustManagerOrNull: X509TrustManager?
|
||||
|
||||
/**
|
||||
* Returns the [HostnameVerifier] for the OkHttpClient, or an override from the Call.Chain.
|
||||
*/
|
||||
val hostnameVerifier: HostnameVerifier
|
||||
|
||||
/**
|
||||
* Override the [HostnameVerifier] for the Call.Chain.
|
||||
*
|
||||
* @throws IllegalStateException if this is a Network Interceptor, since the override is too late.
|
||||
*/
|
||||
fun withHostnameVerifier(hostnameVerifier: HostnameVerifier): Chain
|
||||
|
||||
/**
|
||||
* Returns the [CertificatePinner] for the OkHttpClient, or an override from the Call.Chain.
|
||||
*/
|
||||
val certificatePinner: CertificatePinner
|
||||
|
||||
/**
|
||||
* Returns a new chain with the specified [CertificatePinner].
|
||||
*/
|
||||
fun withCertificatePinner(certificatePinner: CertificatePinner): Chain
|
||||
|
||||
/**
|
||||
* Returns the [ConnectionPool] for the OkHttpClient, or an override from the Call.Chain.
|
||||
*/
|
||||
val connectionPool: ConnectionPool
|
||||
|
||||
/**
|
||||
* Returns a new chain with the specified [ConnectionPool].
|
||||
*/
|
||||
fun withConnectionPool(connectionPool: ConnectionPool): Chain
|
||||
|
||||
val eventListener: EventListener
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ open class OkHttpClient internal constructor(
|
||||
@get:JvmName("socketFactory")
|
||||
val socketFactory: SocketFactory = builder.socketFactory
|
||||
|
||||
private val sslSocketFactoryOrNull: SSLSocketFactory?
|
||||
internal val sslSocketFactoryOrNull: SSLSocketFactory?
|
||||
|
||||
@get:JvmName("sslSocketFactory")
|
||||
val sslSocketFactory: SSLSocketFactory
|
||||
|
||||
@@ -40,12 +40,11 @@ import okio.Timeout
|
||||
import okio.buffer
|
||||
|
||||
/** Serves requests from the cache and writes responses to the cache. */
|
||||
class CacheInterceptor(
|
||||
internal val call: RealCall,
|
||||
internal val cache: Cache?,
|
||||
) : Interceptor {
|
||||
class CacheInterceptor : Interceptor {
|
||||
@Throws(IOException::class)
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val call = chain.call()
|
||||
val cache = chain.cache
|
||||
val cacheCandidate = cache?.get(chain.request().requestForCache())
|
||||
|
||||
val now = System.currentTimeMillis()
|
||||
@@ -73,7 +72,7 @@ class CacheInterceptor(
|
||||
.receivedResponseAtMillis(System.currentTimeMillis())
|
||||
.build()
|
||||
.also {
|
||||
call.eventListener.satisfactionFailure(call, it)
|
||||
chain.eventListener.satisfactionFailure(call, it)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,14 +83,14 @@ class CacheInterceptor(
|
||||
.cacheResponse(cacheResponse.stripBody())
|
||||
.build()
|
||||
.also {
|
||||
call.eventListener.cacheHit(call, it)
|
||||
chain.eventListener.cacheHit(call, it)
|
||||
}
|
||||
}
|
||||
|
||||
if (cacheResponse != null) {
|
||||
call.eventListener.cacheConditionalHit(call, cacheResponse)
|
||||
chain.eventListener.cacheConditionalHit(call, cacheResponse)
|
||||
} else if (cache != null) {
|
||||
call.eventListener.cacheMiss(call)
|
||||
chain.eventListener.cacheMiss(call)
|
||||
}
|
||||
|
||||
var networkResponse: Response? = null
|
||||
@@ -124,7 +123,7 @@ class CacheInterceptor(
|
||||
cache!!.trackConditionalCacheHit()
|
||||
cache.update(cacheResponse, response)
|
||||
return response.also {
|
||||
call.eventListener.cacheHit(call, it)
|
||||
chain.eventListener.cacheHit(call, it)
|
||||
}
|
||||
} else {
|
||||
cacheResponse.body.closeQuietly()
|
||||
@@ -147,7 +146,7 @@ class CacheInterceptor(
|
||||
return cacheWritingResponse(cacheRequest, response).also {
|
||||
if (cacheResponse != null) {
|
||||
// This will log a conditional cache miss only.
|
||||
call.eventListener.cacheMiss(call)
|
||||
chain.eventListener.cacheMiss(call)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,9 +209,9 @@ class RealCall(
|
||||
// Build a full stack of interceptors.
|
||||
val interceptors = mutableListOf<Interceptor>()
|
||||
interceptors += client.interceptors
|
||||
interceptors += RetryAndFollowUpInterceptor(client)
|
||||
interceptors += BridgeInterceptor(client.cookieJar)
|
||||
interceptors += CacheInterceptor(this, client.cache)
|
||||
interceptors += RetryAndFollowUpInterceptor()
|
||||
interceptors += BridgeInterceptor()
|
||||
interceptors += CacheInterceptor()
|
||||
interceptors += ConnectInterceptor
|
||||
if (!forWebSocket) {
|
||||
interceptors += client.networkInterceptors
|
||||
@@ -225,9 +225,6 @@ class RealCall(
|
||||
index = 0,
|
||||
exchange = null,
|
||||
request = originalRequest,
|
||||
connectTimeoutMillis = client.connectTimeoutMillis,
|
||||
readTimeoutMillis = client.readTimeoutMillis,
|
||||
writeTimeoutMillis = client.writeTimeoutMillis,
|
||||
)
|
||||
|
||||
var calledNoMoreExchanges = false
|
||||
@@ -275,15 +272,15 @@ class RealCall(
|
||||
val routePlanner =
|
||||
RealRoutePlanner(
|
||||
taskRunner = client.taskRunner,
|
||||
connectionPool = connectionPool,
|
||||
readTimeoutMillis = client.readTimeoutMillis,
|
||||
writeTimeoutMillis = client.writeTimeoutMillis,
|
||||
connectionPool = chain.connectionPool.delegate,
|
||||
readTimeoutMillis = chain.readTimeoutMillis,
|
||||
writeTimeoutMillis = chain.writeTimeoutMillis,
|
||||
socketConnectTimeoutMillis = chain.connectTimeoutMillis,
|
||||
socketReadTimeoutMillis = chain.readTimeoutMillis,
|
||||
pingIntervalMillis = client.pingIntervalMillis,
|
||||
retryOnConnectionFailure = client.retryOnConnectionFailure,
|
||||
retryOnConnectionFailure = chain.retryOnConnectionFailure,
|
||||
fastFallback = client.fastFallback,
|
||||
address = client.address(request.url),
|
||||
address = chain.address(request.url),
|
||||
routeDatabase = client.routeDatabase,
|
||||
call = this,
|
||||
request = request,
|
||||
|
||||
@@ -31,9 +31,7 @@ import okio.buffer
|
||||
* request. Then it proceeds to call the network. Finally it builds a user response from the network
|
||||
* response.
|
||||
*/
|
||||
class BridgeInterceptor(
|
||||
private val cookieJar: CookieJar,
|
||||
) : Interceptor {
|
||||
class BridgeInterceptor : Interceptor {
|
||||
@Throws(IOException::class)
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val userRequest = chain.request()
|
||||
@@ -72,7 +70,7 @@ class BridgeInterceptor(
|
||||
requestBuilder.header("Accept-Encoding", "gzip")
|
||||
}
|
||||
|
||||
val cookies = cookieJar.loadForRequest(userRequest.url)
|
||||
val cookies = chain.cookieJar.loadForRequest(userRequest.url)
|
||||
if (cookies.isNotEmpty()) {
|
||||
requestBuilder.header("Cookie", cookieHeader(cookies))
|
||||
}
|
||||
@@ -84,7 +82,7 @@ class BridgeInterceptor(
|
||||
val networkRequest = requestBuilder.build()
|
||||
val networkResponse = chain.proceed(networkRequest)
|
||||
|
||||
cookieJar.receiveHeaders(networkRequest.url, networkResponse.headers)
|
||||
chain.cookieJar.receiveHeaders(networkRequest.url, networkResponse.headers)
|
||||
|
||||
val responseBuilder =
|
||||
networkResponse
|
||||
|
||||
@@ -16,15 +16,32 @@
|
||||
package okhttp3.internal.http
|
||||
|
||||
import java.io.IOException
|
||||
import java.net.Proxy
|
||||
import java.net.ProxySelector
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.net.SocketFactory
|
||||
import javax.net.ssl.HostnameVerifier
|
||||
import javax.net.ssl.SSLSocketFactory
|
||||
import javax.net.ssl.X509TrustManager
|
||||
import okhttp3.Address
|
||||
import okhttp3.Authenticator
|
||||
import okhttp3.Cache
|
||||
import okhttp3.Call
|
||||
import okhttp3.CertificatePinner
|
||||
import okhttp3.Connection
|
||||
import okhttp3.ConnectionPool
|
||||
import okhttp3.CookieJar
|
||||
import okhttp3.Dns
|
||||
import okhttp3.EventListener
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import okhttp3.internal.checkDuration
|
||||
import okhttp3.internal.connection.Exchange
|
||||
import okhttp3.internal.connection.RealCall
|
||||
import okhttp3.internal.tls.CertificateChainCleaner
|
||||
|
||||
/**
|
||||
* A concrete interceptor chain that carries the entire interceptor chain: all application
|
||||
@@ -42,7 +59,55 @@ class RealInterceptorChain(
|
||||
internal val connectTimeoutMillis: Int,
|
||||
internal val readTimeoutMillis: Int,
|
||||
internal val writeTimeoutMillis: Int,
|
||||
override val authenticator: Authenticator,
|
||||
override val cache: Cache?,
|
||||
override val certificatePinner: CertificatePinner,
|
||||
override val connectionPool: ConnectionPool,
|
||||
override val cookieJar: CookieJar,
|
||||
override val dns: Dns,
|
||||
override val hostnameVerifier: HostnameVerifier,
|
||||
override val proxy: Proxy?,
|
||||
override val proxyAuthenticator: Authenticator,
|
||||
override val proxySelector: ProxySelector,
|
||||
override val retryOnConnectionFailure: Boolean,
|
||||
override val socketFactory: SocketFactory,
|
||||
override val sslSocketFactoryOrNull: SSLSocketFactory?,
|
||||
override val x509TrustManagerOrNull: X509TrustManager?,
|
||||
val certificateChainCleaner: CertificateChainCleaner?,
|
||||
) : Interceptor.Chain {
|
||||
internal constructor(
|
||||
call: RealCall,
|
||||
interceptors: List<Interceptor>,
|
||||
index: Int,
|
||||
exchange: Nothing?,
|
||||
request: Request,
|
||||
client: OkHttpClient = call.client,
|
||||
) : this(
|
||||
call,
|
||||
interceptors,
|
||||
index,
|
||||
exchange,
|
||||
request,
|
||||
client.connectTimeoutMillis,
|
||||
client.readTimeoutMillis,
|
||||
client.writeTimeoutMillis,
|
||||
client.authenticator,
|
||||
client.cache,
|
||||
client.certificatePinner,
|
||||
client.connectionPool,
|
||||
client.cookieJar,
|
||||
client.dns,
|
||||
client.hostnameVerifier,
|
||||
client.proxy,
|
||||
client.proxyAuthenticator,
|
||||
client.proxySelector,
|
||||
client.retryOnConnectionFailure,
|
||||
client.socketFactory,
|
||||
client.sslSocketFactoryOrNull,
|
||||
client.x509TrustManager,
|
||||
client.certificateChainCleaner,
|
||||
)
|
||||
|
||||
private var calls: Int = 0
|
||||
|
||||
internal fun copy(
|
||||
@@ -52,6 +117,21 @@ class RealInterceptorChain(
|
||||
connectTimeoutMillis: Int = this.connectTimeoutMillis,
|
||||
readTimeoutMillis: Int = this.readTimeoutMillis,
|
||||
writeTimeoutMillis: Int = this.writeTimeoutMillis,
|
||||
authenticator: Authenticator = this.authenticator,
|
||||
cache: Cache? = this.cache,
|
||||
certificatePinner: CertificatePinner = this.certificatePinner,
|
||||
connectionPool: ConnectionPool = this.connectionPool,
|
||||
cookieJar: CookieJar = this.cookieJar,
|
||||
dns: Dns = this.dns,
|
||||
hostnameVerifier: HostnameVerifier = this.hostnameVerifier,
|
||||
proxy: Proxy? = this.proxy,
|
||||
proxyAuthenticator: Authenticator = this.proxyAuthenticator,
|
||||
proxySelector: ProxySelector = this.proxySelector,
|
||||
retryOnConnectionFailure: Boolean = this.retryOnConnectionFailure,
|
||||
socketFactory: SocketFactory = this.socketFactory,
|
||||
sslSocketFactory: SSLSocketFactory? = this.sslSocketFactoryOrNull,
|
||||
x509TrustManager: X509TrustManager? = this.x509TrustManagerOrNull,
|
||||
certificateChainCleaner: CertificateChainCleaner? = this.certificateChainCleaner,
|
||||
) = RealInterceptorChain(
|
||||
call,
|
||||
interceptors,
|
||||
@@ -61,41 +141,167 @@ class RealInterceptorChain(
|
||||
connectTimeoutMillis,
|
||||
readTimeoutMillis,
|
||||
writeTimeoutMillis,
|
||||
authenticator,
|
||||
cache,
|
||||
certificatePinner,
|
||||
connectionPool,
|
||||
cookieJar,
|
||||
dns,
|
||||
hostnameVerifier,
|
||||
proxy,
|
||||
proxyAuthenticator,
|
||||
proxySelector,
|
||||
retryOnConnectionFailure,
|
||||
socketFactory,
|
||||
sslSocketFactory,
|
||||
x509TrustManager,
|
||||
certificateChainCleaner,
|
||||
)
|
||||
|
||||
override val eventListener: EventListener
|
||||
get() = call.eventListener
|
||||
|
||||
override val followSslRedirects: Boolean
|
||||
get() = call.client.followSslRedirects
|
||||
|
||||
override val followRedirects: Boolean
|
||||
get() = call.client.followRedirects
|
||||
|
||||
override fun connection(): Connection? = exchange?.connection
|
||||
|
||||
override fun connectTimeoutMillis(): Int = connectTimeoutMillis
|
||||
|
||||
override fun withConnectTimeout(
|
||||
timeout: Int,
|
||||
timeout: Long,
|
||||
unit: TimeUnit,
|
||||
): Interceptor.Chain {
|
||||
check(exchange == null) { "Timeouts can't be adjusted in a network interceptor" }
|
||||
|
||||
return copy(connectTimeoutMillis = checkDuration("connectTimeout", timeout.toLong(), unit))
|
||||
return copy(connectTimeoutMillis = checkDuration("connectTimeout", timeout, unit))
|
||||
}
|
||||
|
||||
override fun readTimeoutMillis(): Int = readTimeoutMillis
|
||||
|
||||
override fun withReadTimeout(
|
||||
timeout: Int,
|
||||
timeout: Long,
|
||||
unit: TimeUnit,
|
||||
): Interceptor.Chain {
|
||||
check(exchange == null) { "Timeouts can't be adjusted in a network interceptor" }
|
||||
|
||||
return copy(readTimeoutMillis = checkDuration("readTimeout", timeout.toLong(), unit))
|
||||
return copy(readTimeoutMillis = checkDuration("readTimeout", timeout, unit))
|
||||
}
|
||||
|
||||
override fun writeTimeoutMillis(): Int = writeTimeoutMillis
|
||||
|
||||
override fun withWriteTimeout(
|
||||
timeout: Int,
|
||||
timeout: Long,
|
||||
unit: TimeUnit,
|
||||
): Interceptor.Chain {
|
||||
check(exchange == null) { "Timeouts can't be adjusted in a network interceptor" }
|
||||
|
||||
return copy(writeTimeoutMillis = checkDuration("writeTimeout", timeout.toLong(), unit))
|
||||
return copy(writeTimeoutMillis = checkDuration("writeTimeout", timeout, unit))
|
||||
}
|
||||
|
||||
override fun withDns(dns: Dns): Interceptor.Chain {
|
||||
check(exchange == null) { "dns can't be adjusted in a network interceptor" }
|
||||
|
||||
return copy(dns = dns)
|
||||
}
|
||||
|
||||
override fun withSocketFactory(socketFactory: SocketFactory): Interceptor.Chain {
|
||||
check(exchange == null) { "socketFactory can't be adjusted in a network interceptor" }
|
||||
|
||||
return copy(socketFactory = socketFactory)
|
||||
}
|
||||
|
||||
override fun withRetryOnConnectionFailure(retryOnConnectionFailure: Boolean): Interceptor.Chain {
|
||||
check(exchange == null) { "retryOnConnectionFailure can't be adjusted in a network interceptor" }
|
||||
|
||||
return copy(retryOnConnectionFailure = retryOnConnectionFailure)
|
||||
}
|
||||
|
||||
override fun withAuthenticator(authenticator: Authenticator): Interceptor.Chain {
|
||||
check(exchange == null) { "authenticator can't be adjusted in a network interceptor" }
|
||||
|
||||
return copy(authenticator = authenticator)
|
||||
}
|
||||
|
||||
override fun withCookieJar(cookieJar: CookieJar): Interceptor.Chain {
|
||||
check(exchange == null) { "cookieJar can't be adjusted in a network interceptor" }
|
||||
|
||||
return copy(cookieJar = cookieJar)
|
||||
}
|
||||
|
||||
override fun withCache(cache: Cache?): Interceptor.Chain {
|
||||
check(exchange == null) { "cache can't be adjusted in a network interceptor" }
|
||||
|
||||
return copy(cache = cache)
|
||||
}
|
||||
|
||||
override fun withProxy(proxy: Proxy?): Interceptor.Chain {
|
||||
check(exchange == null) { "proxy can't be adjusted in a network interceptor" }
|
||||
|
||||
return copy(proxy = proxy)
|
||||
}
|
||||
|
||||
override fun withProxySelector(proxySelector: ProxySelector): Interceptor.Chain {
|
||||
check(exchange == null) { "proxySelector can't be adjusted in a network interceptor" }
|
||||
|
||||
return copy(proxySelector = proxySelector)
|
||||
}
|
||||
|
||||
override fun withProxyAuthenticator(proxyAuthenticator: Authenticator): Interceptor.Chain {
|
||||
check(exchange == null) { "proxyAuthenticator can't be adjusted in a network interceptor" }
|
||||
|
||||
return copy(proxyAuthenticator = proxyAuthenticator)
|
||||
}
|
||||
|
||||
override fun withSslSocketFactory(
|
||||
sslSocketFactory: SSLSocketFactory?,
|
||||
x509TrustManager: X509TrustManager?,
|
||||
): Interceptor.Chain {
|
||||
check(exchange == null) { "sslSocketFactory can't be adjusted in a network interceptor" }
|
||||
|
||||
if (sslSocketFactory != null && x509TrustManager != null) {
|
||||
val newCertificateChainCleaner = CertificateChainCleaner.get(x509TrustManager)
|
||||
return copy(
|
||||
sslSocketFactory = sslSocketFactory,
|
||||
x509TrustManager = x509TrustManager,
|
||||
certificateChainCleaner = newCertificateChainCleaner,
|
||||
certificatePinner = certificatePinner.withCertificateChainCleaner(newCertificateChainCleaner),
|
||||
)
|
||||
} else {
|
||||
return copy(
|
||||
sslSocketFactory = null,
|
||||
x509TrustManager = null,
|
||||
certificateChainCleaner = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun withHostnameVerifier(hostnameVerifier: HostnameVerifier): Interceptor.Chain {
|
||||
check(exchange == null) { "hostnameVerifier can't be adjusted in a network interceptor" }
|
||||
|
||||
return copy(hostnameVerifier = hostnameVerifier)
|
||||
}
|
||||
|
||||
override fun withCertificatePinner(certificatePinner: CertificatePinner): Interceptor.Chain {
|
||||
check(exchange == null) { "certificatePinner can't be adjusted in a network interceptor" }
|
||||
|
||||
val newCertificatePinner =
|
||||
if (certificateChainCleaner != null) {
|
||||
certificatePinner.withCertificateChainCleaner(certificateChainCleaner)
|
||||
} else {
|
||||
certificatePinner
|
||||
}
|
||||
|
||||
return copy(certificatePinner = newCertificatePinner)
|
||||
}
|
||||
|
||||
override fun withConnectionPool(connectionPool: ConnectionPool): Interceptor.Chain {
|
||||
check(exchange == null) { "connectionPool can't be adjusted in a network interceptor" }
|
||||
|
||||
return copy(connectionPool = connectionPool)
|
||||
}
|
||||
|
||||
override fun call(): Call = call
|
||||
@@ -135,4 +341,34 @@ class RealInterceptorChain(
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an [Address] of out of the provided [HttpUrl]
|
||||
* that uses this client’s DNS, TLS, and proxy configuration.
|
||||
*/
|
||||
fun address(url: HttpUrl): Address {
|
||||
var useSslSocketFactory: SSLSocketFactory? = null
|
||||
var useHostnameVerifier: HostnameVerifier? = null
|
||||
var useCertificatePinner: CertificatePinner? = null
|
||||
if (url.isHttps) {
|
||||
useSslSocketFactory = this.sslSocketFactoryOrNull
|
||||
useHostnameVerifier = this.hostnameVerifier
|
||||
useCertificatePinner = this.certificatePinner
|
||||
}
|
||||
|
||||
return Address(
|
||||
uriHost = url.host,
|
||||
uriPort = url.port,
|
||||
dns = dns,
|
||||
socketFactory = socketFactory,
|
||||
sslSocketFactory = useSslSocketFactory,
|
||||
hostnameVerifier = useHostnameVerifier,
|
||||
certificatePinner = useCertificatePinner,
|
||||
proxyAuthenticator = proxyAuthenticator,
|
||||
proxy = proxy,
|
||||
protocols = call.client.protocols,
|
||||
connectionSpecs = call.client.connectionSpecs,
|
||||
proxySelector = proxySelector,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,7 @@ import okhttp3.internal.withSuppressed
|
||||
* This interceptor recovers from failures and follows redirects as necessary. It may throw an
|
||||
* [IOException] if the call was canceled.
|
||||
*/
|
||||
class RetryAndFollowUpInterceptor(
|
||||
private val client: OkHttpClient,
|
||||
) : Interceptor {
|
||||
class RetryAndFollowUpInterceptor : Interceptor {
|
||||
@Throws(IOException::class)
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val realChain = chain as RealInterceptorChain
|
||||
@@ -75,7 +73,7 @@ class RetryAndFollowUpInterceptor(
|
||||
newRoutePlanner = true
|
||||
} catch (e: IOException) {
|
||||
// An attempt to communicate with a server failed. The request may have been sent.
|
||||
val isRecoverable = recover(e, call, request)
|
||||
val isRecoverable = recover(e, call, chain, request)
|
||||
call.eventListener.retryDecision(call, e, isRecoverable)
|
||||
if (!isRecoverable) throw e.withSuppressed(recoveredFailures)
|
||||
recoveredFailures += e
|
||||
@@ -92,7 +90,7 @@ class RetryAndFollowUpInterceptor(
|
||||
.build()
|
||||
|
||||
val exchange = call.interceptorScopedExchange
|
||||
val followUp = followUpRequest(response, exchange)
|
||||
val followUp = followUpRequest(response, exchange, chain)
|
||||
|
||||
if (followUp == null) {
|
||||
if (exchange != null && exchange.isDuplex) {
|
||||
@@ -135,12 +133,13 @@ class RetryAndFollowUpInterceptor(
|
||||
private fun recover(
|
||||
e: IOException,
|
||||
call: RealCall,
|
||||
chain: Interceptor.Chain,
|
||||
userRequest: Request,
|
||||
): Boolean {
|
||||
val requestSendStarted = e !is ConnectionShutdownException
|
||||
|
||||
// The application layer has forbidden retries.
|
||||
if (!client.retryOnConnectionFailure) return false
|
||||
if (!chain.retryOnConnectionFailure) return false
|
||||
|
||||
// We can't send the request body again.
|
||||
if (requestSendStarted && requestIsOneShot(e, userRequest)) return false
|
||||
@@ -207,6 +206,7 @@ class RetryAndFollowUpInterceptor(
|
||||
private fun followUpRequest(
|
||||
userResponse: Response,
|
||||
exchange: Exchange?,
|
||||
chain: Interceptor.Chain,
|
||||
): Request? {
|
||||
val route = exchange?.connection?.route()
|
||||
val responseCode = userResponse.code
|
||||
@@ -218,20 +218,20 @@ class RetryAndFollowUpInterceptor(
|
||||
if (selectedProxy.type() != Proxy.Type.HTTP) {
|
||||
throw ProtocolException("Received HTTP_PROXY_AUTH (407) code while not using proxy")
|
||||
}
|
||||
return client.proxyAuthenticator.authenticate(route, userResponse)
|
||||
return chain.proxyAuthenticator.authenticate(route, userResponse)
|
||||
}
|
||||
|
||||
HTTP_UNAUTHORIZED -> return client.authenticator.authenticate(route, userResponse)
|
||||
HTTP_UNAUTHORIZED -> return chain.authenticator.authenticate(route, userResponse)
|
||||
|
||||
HTTP_PERM_REDIRECT, HTTP_TEMP_REDIRECT, HTTP_MULT_CHOICE, HTTP_MOVED_PERM, HTTP_MOVED_TEMP, HTTP_SEE_OTHER -> {
|
||||
return buildRedirectRequest(userResponse, method)
|
||||
return buildRedirectRequest(userResponse, method, chain)
|
||||
}
|
||||
|
||||
HTTP_CLIENT_TIMEOUT -> {
|
||||
// 408's are rare in practice, but some servers like HAProxy use this response code. The
|
||||
// spec says that we may repeat the request without modifications. Modern browsers also
|
||||
// repeat the request (even non-idempotent ones.)
|
||||
if (!client.retryOnConnectionFailure) {
|
||||
if (!chain.retryOnConnectionFailure) {
|
||||
// The application layer has directed us not to retry the request.
|
||||
return null
|
||||
}
|
||||
@@ -292,9 +292,10 @@ class RetryAndFollowUpInterceptor(
|
||||
private fun buildRedirectRequest(
|
||||
userResponse: Response,
|
||||
method: String,
|
||||
chain: Interceptor.Chain,
|
||||
): Request? {
|
||||
// Does the client allow redirects?
|
||||
if (!client.followRedirects) return null
|
||||
if (!chain.followRedirects) return null
|
||||
|
||||
val location = userResponse.header("Location") ?: return null
|
||||
// Don't follow redirects to unsupported protocols.
|
||||
@@ -302,7 +303,7 @@ class RetryAndFollowUpInterceptor(
|
||||
|
||||
// If configured, don't follow redirects between SSL and non-SSL.
|
||||
val sameScheme = url.scheme == userResponse.request.url.scheme
|
||||
if (!sameScheme && !client.followSslRedirects) return null
|
||||
if (!sameScheme && !chain.followSslRedirects) return null
|
||||
|
||||
// Most redirects don't include a request body.
|
||||
val requestBuilder = userResponse.request.newBuilder()
|
||||
|
||||
858
okhttp/src/jvmTest/kotlin/okhttp3/InterceptorOverridesTest.kt
Normal file
858
okhttp/src/jvmTest/kotlin/okhttp3/InterceptorOverridesTest.kt
Normal file
@@ -0,0 +1,858 @@
|
||||
package okhttp3
|
||||
|
||||
import app.cash.burst.Burst
|
||||
import app.cash.burst.burstValues
|
||||
import assertk.assertFailure
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.hasMessage
|
||||
import assertk.assertions.isFailure
|
||||
import assertk.assertions.isFalse
|
||||
import assertk.assertions.isNotSameInstanceAs
|
||||
import assertk.assertions.isTrue
|
||||
import java.io.FilterInputStream
|
||||
import java.io.FilterOutputStream
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.Proxy
|
||||
import java.net.ProxySelector
|
||||
import java.net.Socket
|
||||
import java.net.SocketAddress
|
||||
import java.net.URI
|
||||
import java.security.cert.X509Certificate
|
||||
import java.util.Locale.getDefault
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.net.SocketFactory
|
||||
import javax.net.ssl.HostnameVerifier
|
||||
import javax.net.ssl.SSLException
|
||||
import javax.net.ssl.SSLSocket
|
||||
import javax.net.ssl.SSLSocketFactory
|
||||
import javax.net.ssl.X509TrustManager
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
import kotlin.time.Duration.Companion.nanoseconds
|
||||
import mockwebserver3.MockResponse
|
||||
import mockwebserver3.MockWebServer
|
||||
import mockwebserver3.junit5.StartStop
|
||||
import okhttp3.CertificatePinner.Companion.pin
|
||||
import okhttp3.Headers.Companion.headersOf
|
||||
import okhttp3.internal.connection.ConnectionListener
|
||||
import okhttp3.internal.platform.Platform
|
||||
import okhttp3.testing.PlatformRule
|
||||
import okio.BufferedSink
|
||||
import okio.ForwardingFileSystem
|
||||
import okio.IOException
|
||||
import okio.Path
|
||||
import okio.Path.Companion.toPath
|
||||
import okio.fakefilesystem.FakeFileSystem
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.RegisterExtension
|
||||
|
||||
@Burst
|
||||
class InterceptorOverridesTest {
|
||||
@RegisterExtension
|
||||
val platform = PlatformRule()
|
||||
|
||||
@StartStop
|
||||
private val server = MockWebServer()
|
||||
|
||||
// Can't use test instance with overrides
|
||||
private var client = OkHttpClient.Builder().build()
|
||||
|
||||
private val handshakeCertificates = platform.localhostHandshakeCertificates()
|
||||
|
||||
/**
|
||||
* Test that we can override in a Application Interceptor, purely by seeing that the chain reports
|
||||
* the override in a Network Interceptor.
|
||||
*/
|
||||
@Test
|
||||
fun testOverrideInApplicationInterceptor(
|
||||
override: OverrideParam =
|
||||
burstValues(
|
||||
OverrideParam.Authenticator,
|
||||
OverrideParam.Cache,
|
||||
OverrideParam.CertificatePinner,
|
||||
OverrideParam.ConnectTimeout,
|
||||
OverrideParam.ConnectionPool,
|
||||
OverrideParam.CookieJar,
|
||||
OverrideParam.Dns,
|
||||
OverrideParam.HostnameVerifier,
|
||||
OverrideParam.Proxy,
|
||||
OverrideParam.ProxyAuthenticator,
|
||||
OverrideParam.ProxySelector,
|
||||
OverrideParam.ReadTimeout,
|
||||
OverrideParam.RetryOnConnectionFailure,
|
||||
OverrideParam.SocketFactory,
|
||||
OverrideParam.SslSocketFactory,
|
||||
OverrideParam.WriteTimeout,
|
||||
OverrideParam.X509TrustManager,
|
||||
),
|
||||
isDefault: Boolean,
|
||||
) {
|
||||
fun <T> Override<T>.testApplicationInterceptor(chain: Interceptor.Chain): Response {
|
||||
val defaultValue = chain.value()
|
||||
assertThat(isDefaultValue(chain.value())).isTrue()
|
||||
val withOverride = chain.withOverride(nonDefaultValue)
|
||||
assertThat(chain).isNotSameInstanceAs(withOverride)
|
||||
assertThat(isDefaultValue(withOverride.value())).isFalse()
|
||||
|
||||
return if (isDefault) {
|
||||
val withDefault = withOverride.withOverride(defaultValue)
|
||||
assertThat(isDefaultValue(withDefault.value())).isTrue()
|
||||
withOverride.proceed(chain.request())
|
||||
} else {
|
||||
withOverride.proceed(chain.request())
|
||||
}
|
||||
}
|
||||
|
||||
with(override.override) {
|
||||
client =
|
||||
client
|
||||
.newBuilder()
|
||||
.addInterceptor { chain ->
|
||||
testApplicationInterceptor(chain)
|
||||
}.addNetworkInterceptor { chain ->
|
||||
assertThat(isDefaultValue(chain.value())).isFalse()
|
||||
chain.proceed(chain.request())
|
||||
}.build()
|
||||
|
||||
server.enqueue(
|
||||
MockResponse(),
|
||||
)
|
||||
val response = client.newCall(Request(server.url("/"))).execute()
|
||||
response.close()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that we can't override in a Network Interceptor, which will throw an exception.
|
||||
*/
|
||||
@Test
|
||||
fun testOverrideInNetworkInterceptor(
|
||||
override: OverrideParam =
|
||||
burstValues(
|
||||
OverrideParam.Authenticator,
|
||||
OverrideParam.Cache,
|
||||
OverrideParam.CertificatePinner,
|
||||
OverrideParam.ConnectTimeout,
|
||||
OverrideParam.ConnectionPool,
|
||||
OverrideParam.CookieJar,
|
||||
OverrideParam.Dns,
|
||||
OverrideParam.HostnameVerifier,
|
||||
OverrideParam.Proxy,
|
||||
OverrideParam.ProxyAuthenticator,
|
||||
OverrideParam.ProxySelector,
|
||||
OverrideParam.ReadTimeout,
|
||||
OverrideParam.RetryOnConnectionFailure,
|
||||
OverrideParam.SocketFactory,
|
||||
OverrideParam.SslSocketFactory,
|
||||
OverrideParam.WriteTimeout,
|
||||
OverrideParam.X509TrustManager,
|
||||
),
|
||||
) {
|
||||
with(override.override) {
|
||||
client =
|
||||
client
|
||||
.newBuilder()
|
||||
.addNetworkInterceptor { chain ->
|
||||
assertThat(isDefaultValue(chain.value())).isTrue()
|
||||
|
||||
assertFailure {
|
||||
chain.withOverride(
|
||||
nonDefaultValue,
|
||||
)
|
||||
}.hasMessage("${override.paramName} can't be adjusted in a network interceptor")
|
||||
|
||||
chain.proceed(chain.request())
|
||||
}.build()
|
||||
|
||||
server.enqueue(
|
||||
MockResponse(),
|
||||
)
|
||||
val response = client.newCall(Request(server.url("/"))).execute()
|
||||
response.close()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that if we set a bad implementation on the OkHttpClient directly, that we can avoid the failure
|
||||
* by setting a good override.
|
||||
*/
|
||||
@Test
|
||||
fun testOverrideBadImplementation(
|
||||
override: OverrideParam =
|
||||
burstValues(
|
||||
OverrideParam.Authenticator,
|
||||
OverrideParam.Cache,
|
||||
OverrideParam.CertificatePinner,
|
||||
OverrideParam.ConnectTimeout,
|
||||
OverrideParam.ConnectionPool,
|
||||
OverrideParam.CookieJar,
|
||||
OverrideParam.Dns,
|
||||
OverrideParam.HostnameVerifier,
|
||||
OverrideParam.Proxy,
|
||||
OverrideParam.ProxyAuthenticator,
|
||||
OverrideParam.ProxySelector,
|
||||
OverrideParam.ReadTimeout,
|
||||
OverrideParam.RetryOnConnectionFailure,
|
||||
OverrideParam.SocketFactory,
|
||||
OverrideParam.SslSocketFactory,
|
||||
OverrideParam.WriteTimeout,
|
||||
OverrideParam.X509TrustManager,
|
||||
),
|
||||
testItFails: Boolean = false,
|
||||
) {
|
||||
when (override) {
|
||||
OverrideParam.ProxyAuthenticator -> {
|
||||
client = client.newBuilder().proxy(server.proxyAddress).build()
|
||||
|
||||
server.enqueue(
|
||||
MockResponse
|
||||
.Builder()
|
||||
.code(407)
|
||||
.headers(headersOf("Proxy-Authenticate", "Basic realm=\"localhost\""))
|
||||
.inTunnel()
|
||||
.build(),
|
||||
)
|
||||
|
||||
overrideBadImplementation(override = override.override, testItFails = testItFails)
|
||||
}
|
||||
|
||||
OverrideParam.Authenticator -> {
|
||||
server.enqueue(
|
||||
MockResponse.Builder().code(401).build(),
|
||||
)
|
||||
|
||||
overrideBadImplementation(override = override.override, testItFails = testItFails)
|
||||
}
|
||||
|
||||
OverrideParam.RetryOnConnectionFailure -> {
|
||||
enableTls()
|
||||
var first = true
|
||||
client =
|
||||
client
|
||||
.newBuilder()
|
||||
.connectionSpecs(listOf(ConnectionSpec.RESTRICTED_TLS, ConnectionSpec.MODERN_TLS))
|
||||
.eventListener(
|
||||
object : EventListener() {
|
||||
override fun secureConnectEnd(
|
||||
call: Call,
|
||||
handshake: Handshake?,
|
||||
) {
|
||||
if (first) {
|
||||
first = false
|
||||
throw SSLException("")
|
||||
}
|
||||
}
|
||||
},
|
||||
).build()
|
||||
|
||||
overrideBadImplementation(
|
||||
override = Override.RetryOnConnectionFailureOverride,
|
||||
testItFails = testItFails,
|
||||
badValue = false,
|
||||
goodValue = true,
|
||||
)
|
||||
}
|
||||
|
||||
OverrideParam.SslSocketFactory -> {
|
||||
enableTls()
|
||||
overrideBadImplementation(
|
||||
override = Override.SslSocketFactoryOverride,
|
||||
testItFails = testItFails,
|
||||
goodValue = handshakeCertificates.sslSocketFactory(),
|
||||
)
|
||||
}
|
||||
|
||||
OverrideParam.X509TrustManager -> {
|
||||
enableTls()
|
||||
overrideBadImplementation(
|
||||
override = Override.X509TrustManagerOverride,
|
||||
testItFails = testItFails,
|
||||
goodValue = handshakeCertificates.trustManager,
|
||||
)
|
||||
}
|
||||
|
||||
OverrideParam.HostnameVerifier -> {
|
||||
enableTls()
|
||||
overrideBadImplementation(override = override.override, testItFails = testItFails)
|
||||
}
|
||||
|
||||
OverrideParam.WriteTimeout -> {
|
||||
val body =
|
||||
object : RequestBody() {
|
||||
override fun contentType(): MediaType? = null
|
||||
|
||||
override fun writeTo(sink: BufferedSink) {
|
||||
if (sink
|
||||
.timeout()
|
||||
.timeoutNanos()
|
||||
.nanoseconds.inWholeMilliseconds == 10L
|
||||
) {
|
||||
throw IOException()
|
||||
}
|
||||
}
|
||||
}
|
||||
overrideBadImplementation(override = override.override, testItFails = testItFails, body = body)
|
||||
}
|
||||
|
||||
OverrideParam.ReadTimeout -> {
|
||||
client =
|
||||
client
|
||||
.newBuilder()
|
||||
.socketFactory(
|
||||
DelayingSocketFactory(onRead = {
|
||||
Thread.sleep(100L)
|
||||
}),
|
||||
).build()
|
||||
|
||||
overrideBadImplementation(override = override.override, testItFails = testItFails)
|
||||
}
|
||||
|
||||
OverrideParam.ConnectTimeout -> {
|
||||
client =
|
||||
client
|
||||
.newBuilder()
|
||||
.socketFactory(
|
||||
DelayingSocketFactory(onConnect = { timeout ->
|
||||
if (timeout == 10) {
|
||||
throw IOException()
|
||||
}
|
||||
}),
|
||||
).build()
|
||||
|
||||
overrideBadImplementation(override = override.override, testItFails = testItFails)
|
||||
}
|
||||
|
||||
OverrideParam.CertificatePinner -> {
|
||||
enableTls()
|
||||
|
||||
val pinner =
|
||||
CertificatePinner
|
||||
.Builder()
|
||||
.add(server.hostName, pin(handshakeCertificates.trustManager.acceptedIssuers.first()))
|
||||
.build()
|
||||
|
||||
overrideBadImplementation(
|
||||
override = Override.CertificatePinnerOverride,
|
||||
testItFails = testItFails,
|
||||
goodValue = pinner,
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
overrideBadImplementation(override = override.override, testItFails = testItFails)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> overrideBadImplementation(
|
||||
override: Override<T>,
|
||||
testItFails: Boolean,
|
||||
badValue: T = override.badValue,
|
||||
goodValue: T = override.nonDefaultValue,
|
||||
body: RequestBody? = null,
|
||||
) {
|
||||
with(override) {
|
||||
client =
|
||||
client
|
||||
.newBuilder()
|
||||
// Set the bad override directly on the client
|
||||
.withOverride(badValue)
|
||||
.addInterceptor { chain ->
|
||||
// the only way to stop a bad override of a client is with a good override of an interceptor
|
||||
chain
|
||||
.run {
|
||||
if (testItFails) {
|
||||
this
|
||||
} else {
|
||||
withOverride(goodValue)
|
||||
}
|
||||
}.proceed(chain.request())
|
||||
}.build()
|
||||
|
||||
server.enqueue(
|
||||
MockResponse(),
|
||||
)
|
||||
val call = client.newCall(Request(server.url("/"), body = body))
|
||||
val result = runCatching { call.execute().body.bytes() }
|
||||
|
||||
if (testItFails) {
|
||||
assertThat(result).isFailure()
|
||||
} else {
|
||||
result.getOrThrow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class OverrideParam(
|
||||
val override: Override<*>,
|
||||
) {
|
||||
Authenticator(Override.AuthenticatorOverride),
|
||||
Cache(Override.CacheOverride),
|
||||
CertificatePinner(Override.CertificatePinnerOverride),
|
||||
ConnectTimeout(
|
||||
Override.ConnectTimeoutOverride,
|
||||
) {
|
||||
override val paramName: String
|
||||
get() = "Timeouts"
|
||||
},
|
||||
ConnectionPool(Override.ConnectionPoolOverride),
|
||||
CookieJar(Override.CookieJarOverride),
|
||||
Dns(Override.DnsOverride),
|
||||
HostnameVerifier(
|
||||
Override.HostnameVerifierOverride,
|
||||
),
|
||||
Proxy(Override.ProxyOverride),
|
||||
ProxyAuthenticator(Override.ProxyAuthenticatorOverride),
|
||||
ProxySelector(Override.ProxySelectorOverride),
|
||||
ReadTimeout(
|
||||
Override.ReadTimeoutOverride,
|
||||
) {
|
||||
override val paramName: String
|
||||
get() = "Timeouts"
|
||||
},
|
||||
RetryOnConnectionFailure(Override.RetryOnConnectionFailureOverride),
|
||||
SocketFactory(Override.SocketFactoryOverride),
|
||||
SslSocketFactory(
|
||||
Override.SslSocketFactoryOverride,
|
||||
),
|
||||
WriteTimeout(Override.WriteTimeoutOverride) {
|
||||
override val paramName: String
|
||||
get() = "Timeouts"
|
||||
},
|
||||
X509TrustManager(Override.X509TrustManagerOverride), ;
|
||||
|
||||
open val paramName: String
|
||||
get() = override.paramName ?: name.replaceFirstChar { it.lowercase(getDefault()) }
|
||||
}
|
||||
|
||||
class DelayingSocketFactory(
|
||||
val onConnect: Socket.(timeout: Int) -> Unit = {},
|
||||
val onRead: Socket.() -> Unit = {},
|
||||
val onWrite: Socket.() -> Unit = {},
|
||||
) : DelegatingSocketFactory(getDefault()) {
|
||||
override fun createSocket(): Socket {
|
||||
return object : Socket() {
|
||||
override fun connect(
|
||||
endpoint: SocketAddress?,
|
||||
timeout: Int,
|
||||
) {
|
||||
onConnect(timeout)
|
||||
super.connect(endpoint, timeout)
|
||||
}
|
||||
|
||||
override fun getInputStream(): InputStream {
|
||||
return object : FilterInputStream(super.inputStream) {
|
||||
override fun read(
|
||||
b: ByteArray?,
|
||||
off: Int,
|
||||
len: Int,
|
||||
): Int {
|
||||
onRead()
|
||||
return super.read(b, off, len)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getOutputStream(): OutputStream =
|
||||
object : FilterOutputStream(super.outputStream) {
|
||||
override fun write(
|
||||
b: ByteArray?,
|
||||
off: Int,
|
||||
len: Int,
|
||||
) {
|
||||
onWrite()
|
||||
super.write(b, off, len)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface Override<T> {
|
||||
fun Interceptor.Chain.value(): T
|
||||
|
||||
fun Interceptor.Chain.withOverride(value: T): Interceptor.Chain
|
||||
|
||||
fun OkHttpClient.Builder.withOverride(value: T): OkHttpClient.Builder
|
||||
|
||||
val paramName: String?
|
||||
get() = null
|
||||
|
||||
val nonDefaultValue: T
|
||||
|
||||
val badValue: T
|
||||
|
||||
fun isDefaultValue(value: T): Boolean
|
||||
|
||||
object DnsOverride : Override<Dns> {
|
||||
override fun Interceptor.Chain.value(): Dns = dns
|
||||
|
||||
override fun Interceptor.Chain.withOverride(value: Dns): Interceptor.Chain = withDns(value)
|
||||
|
||||
override fun OkHttpClient.Builder.withOverride(value: Dns): OkHttpClient.Builder = dns(value)
|
||||
|
||||
override val nonDefaultValue: Dns = Dns { Dns.SYSTEM.lookup(it) }
|
||||
|
||||
override val badValue: Dns = Dns { TODO() }
|
||||
|
||||
override fun isDefaultValue(value: Dns): Boolean = value === Dns.SYSTEM
|
||||
}
|
||||
|
||||
object SocketFactoryOverride : Override<SocketFactory> {
|
||||
override fun Interceptor.Chain.value(): SocketFactory = socketFactory
|
||||
|
||||
override fun Interceptor.Chain.withOverride(value: SocketFactory): Interceptor.Chain = withSocketFactory(value)
|
||||
|
||||
override fun OkHttpClient.Builder.withOverride(value: SocketFactory): OkHttpClient.Builder = socketFactory(value)
|
||||
|
||||
override val nonDefaultValue: SocketFactory = object : DelegatingSocketFactory(getDefault()) {}
|
||||
|
||||
override val badValue: SocketFactory =
|
||||
object : DelegatingSocketFactory(getDefault()) {
|
||||
override fun configureSocket(socket: Socket): Socket = TODO()
|
||||
}
|
||||
|
||||
override fun isDefaultValue(value: SocketFactory): Boolean = value === SocketFactory.getDefault()
|
||||
}
|
||||
|
||||
object AuthenticatorOverride : Override<Authenticator> {
|
||||
override fun Interceptor.Chain.value(): Authenticator = authenticator
|
||||
|
||||
override fun Interceptor.Chain.withOverride(value: Authenticator): Interceptor.Chain = withAuthenticator(value)
|
||||
|
||||
override fun OkHttpClient.Builder.withOverride(value: Authenticator): OkHttpClient.Builder = authenticator(value)
|
||||
|
||||
override val nonDefaultValue: Authenticator = Authenticator { route, response -> response.request }
|
||||
|
||||
override val badValue: Authenticator = Authenticator { route, response -> TODO() }
|
||||
|
||||
override fun isDefaultValue(value: Authenticator): Boolean = value === Authenticator.NONE
|
||||
}
|
||||
|
||||
object CookieJarOverride : Override<CookieJar> {
|
||||
override fun Interceptor.Chain.value(): CookieJar = cookieJar
|
||||
|
||||
override fun Interceptor.Chain.withOverride(value: CookieJar): Interceptor.Chain = withCookieJar(value)
|
||||
|
||||
override fun OkHttpClient.Builder.withOverride(value: CookieJar): OkHttpClient.Builder = cookieJar(value)
|
||||
|
||||
override val nonDefaultValue: CookieJar =
|
||||
object : CookieJar {
|
||||
override fun saveFromResponse(
|
||||
url: HttpUrl,
|
||||
cookies: List<Cookie>,
|
||||
) {
|
||||
}
|
||||
|
||||
override fun loadForRequest(url: HttpUrl): List<Cookie> = emptyList()
|
||||
}
|
||||
|
||||
override val badValue: CookieJar =
|
||||
object : CookieJar {
|
||||
override fun saveFromResponse(
|
||||
url: HttpUrl,
|
||||
cookies: List<Cookie>,
|
||||
) {
|
||||
}
|
||||
|
||||
override fun loadForRequest(url: HttpUrl): List<Cookie> = TODO()
|
||||
}
|
||||
|
||||
override fun isDefaultValue(value: CookieJar): Boolean = value === CookieJar.NO_COOKIES
|
||||
}
|
||||
|
||||
object CacheOverride : Override<Cache?> {
|
||||
override fun Interceptor.Chain.value(): Cache? = cache
|
||||
|
||||
override fun Interceptor.Chain.withOverride(value: Cache?): Interceptor.Chain = withCache(value)
|
||||
|
||||
override fun OkHttpClient.Builder.withOverride(value: Cache?): OkHttpClient.Builder = cache(value)
|
||||
|
||||
override val nonDefaultValue: Cache = Cache(FakeFileSystem(), "/cash".toPath(), 1)
|
||||
|
||||
override val badValue: Cache =
|
||||
Cache(
|
||||
object : ForwardingFileSystem(FakeFileSystem()) {
|
||||
override fun onPathParameter(
|
||||
path: Path,
|
||||
functionName: String,
|
||||
parameterName: String,
|
||||
): Path = TODO()
|
||||
},
|
||||
"/cash".toPath(),
|
||||
1,
|
||||
)
|
||||
|
||||
override fun isDefaultValue(value: Cache?): Boolean = value == null
|
||||
}
|
||||
|
||||
object ProxyOverride : Override<java.net.Proxy?> {
|
||||
override fun Interceptor.Chain.value(): java.net.Proxy? = proxy
|
||||
|
||||
override fun Interceptor.Chain.withOverride(value: java.net.Proxy?): Interceptor.Chain = withProxy(value)
|
||||
|
||||
override fun OkHttpClient.Builder.withOverride(value: java.net.Proxy?): OkHttpClient.Builder = proxy(value)
|
||||
|
||||
override val nonDefaultValue: java.net.Proxy? = java.net.Proxy.NO_PROXY
|
||||
|
||||
override val badValue: java.net.Proxy? =
|
||||
java.net.Proxy(Proxy.Type.HTTP, InetSocketAddress.createUnresolved("proxy.example.com", 1003))
|
||||
|
||||
override fun isDefaultValue(value: java.net.Proxy?): Boolean = value == null
|
||||
}
|
||||
|
||||
object ProxySelectorOverride : Override<ProxySelector> {
|
||||
override fun Interceptor.Chain.value(): ProxySelector = proxySelector
|
||||
|
||||
override fun Interceptor.Chain.withOverride(value: ProxySelector): Interceptor.Chain = withProxySelector(value)
|
||||
|
||||
override fun OkHttpClient.Builder.withOverride(value: ProxySelector): OkHttpClient.Builder = proxySelector(value)
|
||||
|
||||
override val nonDefaultValue: ProxySelector =
|
||||
object : ProxySelector() {
|
||||
override fun select(uri: URI?): MutableList<Proxy> = mutableListOf(java.net.Proxy.NO_PROXY)
|
||||
|
||||
override fun connectFailed(
|
||||
uri: URI?,
|
||||
sa: SocketAddress?,
|
||||
ioe: java.io.IOException?,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
override val badValue: ProxySelector =
|
||||
object : ProxySelector() {
|
||||
override fun select(uri: URI?): MutableList<Proxy> = TODO()
|
||||
|
||||
override fun connectFailed(
|
||||
uri: URI?,
|
||||
sa: SocketAddress?,
|
||||
ioe: java.io.IOException?,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
override fun isDefaultValue(value: ProxySelector): Boolean = value === ProxySelector.getDefault()
|
||||
}
|
||||
|
||||
object ProxyAuthenticatorOverride : Override<Authenticator> {
|
||||
override fun Interceptor.Chain.value(): Authenticator = proxyAuthenticator
|
||||
|
||||
override fun Interceptor.Chain.withOverride(value: Authenticator): Interceptor.Chain = withProxyAuthenticator(value)
|
||||
|
||||
override fun OkHttpClient.Builder.withOverride(value: Authenticator): OkHttpClient.Builder = proxyAuthenticator(value)
|
||||
|
||||
override val nonDefaultValue: Authenticator = Authenticator { route, response -> response.request }
|
||||
|
||||
override val badValue: Authenticator = Authenticator { route, response -> TODO() }
|
||||
|
||||
override fun isDefaultValue(value: Authenticator): Boolean = value === Authenticator.NONE
|
||||
}
|
||||
|
||||
object SslSocketFactoryOverride : Override<SSLSocketFactory?> {
|
||||
override fun Interceptor.Chain.value(): SSLSocketFactory? = sslSocketFactoryOrNull
|
||||
|
||||
override fun Interceptor.Chain.withOverride(value: SSLSocketFactory?): Interceptor.Chain =
|
||||
withSslSocketFactory(value, x509TrustManagerOrNull)
|
||||
|
||||
override fun OkHttpClient.Builder.withOverride(value: SSLSocketFactory?): OkHttpClient.Builder =
|
||||
sslSocketFactory(value!!, x509TrustManagerOrNull!!)
|
||||
|
||||
override val nonDefaultValue: SSLSocketFactory =
|
||||
object :
|
||||
DelegatingSSLSocketFactory(Platform.get().newSslSocketFactory(Platform.get().platformTrustManager())) {}
|
||||
|
||||
override val badValue: SSLSocketFactory =
|
||||
object : DelegatingSSLSocketFactory(Platform.get().newSslSocketFactory(Platform.get().platformTrustManager())) {
|
||||
override fun configureSocket(sslSocket: SSLSocket): SSLSocket = TODO()
|
||||
}
|
||||
|
||||
override fun isDefaultValue(value: SSLSocketFactory?): Boolean = value !is DelegatingSSLSocketFactory
|
||||
}
|
||||
|
||||
object X509TrustManagerOverride : Override<X509TrustManager?> {
|
||||
override val paramName: String = "sslSocketFactory"
|
||||
|
||||
override fun Interceptor.Chain.value(): X509TrustManager? = x509TrustManagerOrNull
|
||||
|
||||
override fun Interceptor.Chain.withOverride(value: X509TrustManager?): Interceptor.Chain =
|
||||
withSslSocketFactory(Platform.get().newSslSocketFactory(value!!), value)
|
||||
|
||||
override fun OkHttpClient.Builder.withOverride(value: X509TrustManager?): OkHttpClient.Builder =
|
||||
sslSocketFactory(Platform.get().newSslSocketFactory(value!!), value)
|
||||
|
||||
override val nonDefaultValue: X509TrustManager =
|
||||
object : X509TrustManager {
|
||||
override fun checkClientTrusted(
|
||||
x509Certificates: Array<X509Certificate>,
|
||||
s: String,
|
||||
) {
|
||||
}
|
||||
|
||||
override fun checkServerTrusted(
|
||||
x509Certificates: Array<X509Certificate>,
|
||||
s: String,
|
||||
) {
|
||||
}
|
||||
|
||||
override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
|
||||
}
|
||||
|
||||
override val badValue: X509TrustManager =
|
||||
object : X509TrustManager {
|
||||
override fun checkClientTrusted(
|
||||
x509Certificates: Array<X509Certificate>,
|
||||
s: String,
|
||||
) {
|
||||
}
|
||||
|
||||
override fun checkServerTrusted(
|
||||
x509Certificates: Array<X509Certificate>,
|
||||
s: String,
|
||||
) {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
|
||||
}
|
||||
|
||||
override fun isDefaultValue(value: X509TrustManager?): Boolean =
|
||||
!value
|
||||
?.javaClass
|
||||
?.name
|
||||
.orEmpty()
|
||||
.startsWith("okhttp")
|
||||
}
|
||||
|
||||
object HostnameVerifierOverride : Override<HostnameVerifier> {
|
||||
override fun Interceptor.Chain.value(): HostnameVerifier = hostnameVerifier
|
||||
|
||||
override fun Interceptor.Chain.withOverride(value: HostnameVerifier): Interceptor.Chain = withHostnameVerifier(value)
|
||||
|
||||
override fun OkHttpClient.Builder.withOverride(value: HostnameVerifier): OkHttpClient.Builder = hostnameVerifier(value)
|
||||
|
||||
override val nonDefaultValue: HostnameVerifier = HostnameVerifier { _, _ -> true }
|
||||
|
||||
override val badValue: HostnameVerifier = HostnameVerifier { _, _ -> TODO() }
|
||||
|
||||
override fun isDefaultValue(value: HostnameVerifier): Boolean = value === okhttp3.internal.tls.OkHostnameVerifier
|
||||
}
|
||||
|
||||
object CertificatePinnerOverride : Override<CertificatePinner> {
|
||||
override fun Interceptor.Chain.value(): CertificatePinner = certificatePinner
|
||||
|
||||
override fun Interceptor.Chain.withOverride(value: CertificatePinner): Interceptor.Chain = withCertificatePinner(value)
|
||||
|
||||
override fun OkHttpClient.Builder.withOverride(value: CertificatePinner): OkHttpClient.Builder = certificatePinner(value)
|
||||
|
||||
override val nonDefaultValue: CertificatePinner =
|
||||
CertificatePinner
|
||||
.Builder()
|
||||
.add("publicobject.com", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=")
|
||||
.build()
|
||||
|
||||
override val badValue: CertificatePinner =
|
||||
CertificatePinner.Builder().add("localhost", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=").build()
|
||||
|
||||
override fun isDefaultValue(value: CertificatePinner): Boolean = value.pins.isEmpty()
|
||||
}
|
||||
|
||||
object ConnectionPoolOverride : Override<ConnectionPool> {
|
||||
override fun Interceptor.Chain.value(): ConnectionPool = connectionPool
|
||||
|
||||
override fun Interceptor.Chain.withOverride(value: ConnectionPool): Interceptor.Chain = withConnectionPool(value)
|
||||
|
||||
override fun OkHttpClient.Builder.withOverride(value: ConnectionPool): OkHttpClient.Builder = connectionPool(value)
|
||||
|
||||
override val nonDefaultValue: ConnectionPool = ConnectionPool(keepAliveDuration = 1, timeUnit = TimeUnit.MINUTES)
|
||||
|
||||
override val badValue: ConnectionPool =
|
||||
ConnectionPool(
|
||||
keepAliveDuration = 1,
|
||||
timeUnit = TimeUnit.MINUTES,
|
||||
connectionListener =
|
||||
object : ConnectionListener() {
|
||||
override fun connectStart(
|
||||
route: Route,
|
||||
call: Call,
|
||||
): Unit = TODO()
|
||||
},
|
||||
)
|
||||
|
||||
override fun isDefaultValue(value: ConnectionPool): Boolean = value.delegate.keepAliveDurationNs == 5.minutes.inWholeNanoseconds
|
||||
}
|
||||
|
||||
object ConnectTimeoutOverride : Override<Int> {
|
||||
override fun Interceptor.Chain.value(): Int = connectTimeoutMillis()
|
||||
|
||||
override fun Interceptor.Chain.withOverride(value: Int): Interceptor.Chain = withConnectTimeout(value.toLong(), TimeUnit.MILLISECONDS)
|
||||
|
||||
override fun OkHttpClient.Builder.withOverride(value: Int): OkHttpClient.Builder =
|
||||
connectTimeout(value.toLong(), TimeUnit.MILLISECONDS)
|
||||
|
||||
override val nonDefaultValue: Int = 5000
|
||||
|
||||
override val badValue: Int
|
||||
get() = 10
|
||||
|
||||
override fun isDefaultValue(value: Int): Boolean = value == 10000
|
||||
}
|
||||
|
||||
object ReadTimeoutOverride : Override<Int> {
|
||||
override fun Interceptor.Chain.value(): Int = readTimeoutMillis()
|
||||
|
||||
override fun Interceptor.Chain.withOverride(value: Int): Interceptor.Chain = withReadTimeout(value.toLong(), TimeUnit.MILLISECONDS)
|
||||
|
||||
override fun OkHttpClient.Builder.withOverride(value: Int): OkHttpClient.Builder = readTimeout(value.toLong(), TimeUnit.MILLISECONDS)
|
||||
|
||||
override val nonDefaultValue: Int = 5000
|
||||
|
||||
override val badValue: Int
|
||||
get() = 10
|
||||
|
||||
override fun isDefaultValue(value: Int): Boolean = value == 10000
|
||||
}
|
||||
|
||||
object WriteTimeoutOverride : Override<Int> {
|
||||
override fun Interceptor.Chain.value(): Int = writeTimeoutMillis()
|
||||
|
||||
override fun Interceptor.Chain.withOverride(value: Int): Interceptor.Chain = withWriteTimeout(value.toLong(), TimeUnit.MILLISECONDS)
|
||||
|
||||
override fun OkHttpClient.Builder.withOverride(value: Int): OkHttpClient.Builder = writeTimeout(value.toLong(), TimeUnit.MILLISECONDS)
|
||||
|
||||
override val nonDefaultValue: Int = 5000
|
||||
|
||||
override val badValue: Int
|
||||
get() = 10
|
||||
|
||||
override fun isDefaultValue(value: Int): Boolean = value == 10000
|
||||
}
|
||||
|
||||
object RetryOnConnectionFailureOverride : Override<Boolean> {
|
||||
override fun Interceptor.Chain.value(): Boolean = retryOnConnectionFailure
|
||||
|
||||
override fun Interceptor.Chain.withOverride(value: Boolean): Interceptor.Chain = withRetryOnConnectionFailure(value)
|
||||
|
||||
override fun OkHttpClient.Builder.withOverride(value: Boolean): OkHttpClient.Builder = retryOnConnectionFailure(value)
|
||||
|
||||
override val nonDefaultValue: Boolean = false
|
||||
|
||||
override val badValue: Boolean
|
||||
get() = false
|
||||
|
||||
override fun isDefaultValue(value: Boolean): Boolean = value
|
||||
}
|
||||
}
|
||||
|
||||
private fun enableTls() {
|
||||
client =
|
||||
client
|
||||
.newBuilder()
|
||||
.sslSocketFactory(
|
||||
handshakeCertificates.sslSocketFactory(),
|
||||
handshakeCertificates.trustManager,
|
||||
).build()
|
||||
server.useHttps(handshakeCertificates.sslSocketFactory())
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package okhttp3
|
||||
|
||||
import java.io.File
|
||||
@@ -91,13 +92,19 @@ import org.junit.jupiter.api.Test
|
||||
*/
|
||||
@Suppress(
|
||||
"ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE",
|
||||
"AssignedValueIsNeverRead",
|
||||
"CanBeVal",
|
||||
"DEPRECATION",
|
||||
"IMPLICIT_NOTHING_AS_TYPE_PARAMETER",
|
||||
"RedundantExplicitType",
|
||||
"RedundantNullableReturnType",
|
||||
"UNUSED_ANONYMOUS_PARAMETER",
|
||||
"UNUSED_VALUE",
|
||||
"UNUSED_VARIABLE",
|
||||
"VARIABLE_WITH_REDUNDANT_INITIALIZER",
|
||||
"RedundantLambdaArrow",
|
||||
"RedundantExplicitType",
|
||||
"IMPLICIT_NOTHING_AS_TYPE_PARAMETER",
|
||||
"VariableInitializerIsRedundant",
|
||||
"VariableNeverRead",
|
||||
"unused",
|
||||
)
|
||||
@Disabled
|
||||
class KotlinSourceModernTest {
|
||||
@@ -383,7 +390,7 @@ class KotlinSourceModernTest {
|
||||
val maxRequestsPerHost: Int = dispatcher.maxRequestsPerHost
|
||||
dispatcher.maxRequestsPerHost = 0
|
||||
val executorService: ExecutorService = dispatcher.executorService
|
||||
dispatcher.idleCallback = Runnable { ({ TODO() })() }
|
||||
dispatcher.idleCallback = Runnable { TODO() }
|
||||
val queuedCalls: List<Call> = dispatcher.queuedCalls()
|
||||
val runningCalls: List<Call> = dispatcher.runningCalls()
|
||||
val queuedCallsCount: Int = dispatcher.queuedCallsCount()
|
||||
@@ -1344,22 +1351,115 @@ class KotlinSourceModernTest {
|
||||
override fun connectTimeoutMillis(): Int = TODO()
|
||||
|
||||
override fun withConnectTimeout(
|
||||
timeout: Int,
|
||||
timeout: Long,
|
||||
unit: TimeUnit,
|
||||
): Interceptor.Chain = TODO()
|
||||
|
||||
override fun readTimeoutMillis(): Int = TODO()
|
||||
|
||||
override fun withReadTimeout(
|
||||
timeout: Int,
|
||||
timeout: Long,
|
||||
unit: TimeUnit,
|
||||
): Interceptor.Chain = TODO()
|
||||
|
||||
override fun writeTimeoutMillis(): Int = TODO()
|
||||
|
||||
override fun withWriteTimeout(
|
||||
timeout: Int,
|
||||
timeout: Long,
|
||||
unit: TimeUnit,
|
||||
): Interceptor.Chain = TODO()
|
||||
|
||||
override val dns: Dns
|
||||
get() = TODO()
|
||||
|
||||
override val socketFactory: SocketFactory
|
||||
get() = TODO()
|
||||
|
||||
override val retryOnConnectionFailure: Boolean
|
||||
get() = TODO()
|
||||
override val authenticator: Authenticator
|
||||
get() = TODO()
|
||||
override val cookieJar: CookieJar
|
||||
get() = TODO()
|
||||
override val cache: Cache?
|
||||
get() = TODO()
|
||||
override val proxy: Proxy?
|
||||
get() = TODO()
|
||||
override val proxySelector: ProxySelector
|
||||
get() = TODO()
|
||||
override val proxyAuthenticator: Authenticator
|
||||
get() = TODO()
|
||||
override val sslSocketFactoryOrNull: SSLSocketFactory
|
||||
get() = TODO()
|
||||
override val x509TrustManagerOrNull: X509TrustManager
|
||||
get() = TODO()
|
||||
override val hostnameVerifier: HostnameVerifier
|
||||
get() = TODO()
|
||||
override val certificatePinner: CertificatePinner
|
||||
get() = TODO()
|
||||
override val connectionPool: ConnectionPool
|
||||
get() = TODO()
|
||||
|
||||
override fun withDns(dns: Dns): Interceptor.Chain {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override fun withSocketFactory(socketFactory: SocketFactory): Interceptor.Chain {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override fun withRetryOnConnectionFailure(retryOnConnectionFailure: Boolean): Interceptor.Chain {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override fun withAuthenticator(authenticator: Authenticator): Interceptor.Chain {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override fun withCookieJar(cookieJar: CookieJar): Interceptor.Chain {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override fun withCache(cache: Cache?): Interceptor.Chain {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override fun withProxy(proxy: Proxy?): Interceptor.Chain {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override fun withProxySelector(proxySelector: ProxySelector): Interceptor.Chain {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override fun withProxyAuthenticator(proxyAuthenticator: Authenticator): Interceptor.Chain {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override fun withSslSocketFactory(
|
||||
sslSocketFactory: SSLSocketFactory?,
|
||||
x509TrustManager: X509TrustManager?,
|
||||
): Interceptor.Chain {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override fun withHostnameVerifier(hostnameVerifier: HostnameVerifier): Interceptor.Chain {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override fun withCertificatePinner(certificatePinner: CertificatePinner): Interceptor.Chain {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override fun withConnectionPool(connectionPool: ConnectionPool): Interceptor.Chain {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override val followSslRedirects: Boolean
|
||||
get() = TODO()
|
||||
override val followRedirects: Boolean
|
||||
get() = TODO()
|
||||
override val eventListener: EventListener
|
||||
get() = TODO()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user