diff --git a/openai-java-client-okhttp/build.gradle.kts b/openai-java-client-okhttp/build.gradle.kts index 08db9a7e2..550ca86cd 100644 --- a/openai-java-client-okhttp/build.gradle.kts +++ b/openai-java-client-okhttp/build.gradle.kts @@ -30,7 +30,7 @@ listOf(configurations.testCompileClasspath, configurations.testRuntimeClasspath) dependencies { api(project(":openai-java-core")) - implementation("com.squareup.okhttp3:okhttp:4.12.0") + api("com.squareup.okhttp3:okhttp:4.12.0") testImplementation(kotlin("test")) testImplementation("org.assertj:assertj-core:3.27.7") diff --git a/openai-java-client-okhttp/src/main/kotlin/com/openai/client/okhttp/OkHttpClient.kt b/openai-java-client-okhttp/src/main/kotlin/com/openai/client/okhttp/OkHttpClient.kt index be33ffaa7..97eaf61a1 100644 --- a/openai-java-client-okhttp/src/main/kotlin/com/openai/client/okhttp/OkHttpClient.kt +++ b/openai-java-client-okhttp/src/main/kotlin/com/openai/client/okhttp/OkHttpClient.kt @@ -29,6 +29,7 @@ import okhttp3.ConnectionPool import okhttp3.Dispatcher import okhttp3.HttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.Interceptor import okhttp3.MediaType import okhttp3.MediaType.Companion.toMediaType import okhttp3.Request @@ -211,6 +212,7 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null private var hostnameVerifier: HostnameVerifier? = null + private val interceptors: MutableList = mutableListOf() fun timeout(timeout: Timeout) = apply { this.timeout = timeout } @@ -227,6 +229,9 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie this.proxyAuthenticator = proxyAuthenticator } + /** Adds an application interceptor to the underlying OkHttp transport. */ + fun addInterceptor(interceptor: Interceptor) = apply { interceptors.add(interceptor) } + /** * Sets the maximum number of idle connections kept by the underlying [ConnectionPool]. * @@ -279,6 +284,8 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie .callTimeout(timeout.request()) .proxy(proxy) .apply { + interceptors.forEach(::addInterceptor) + proxyAuthenticator?.let { auth -> proxyAuthenticator { route, response -> val proxy = route?.proxy ?: Proxy.NO_PROXY diff --git a/openai-java-client-okhttp/src/test/kotlin/com/openai/client/okhttp/OkHttpClientTest.kt b/openai-java-client-okhttp/src/test/kotlin/com/openai/client/okhttp/OkHttpClientTest.kt index c06334bd8..1dd6b4401 100644 --- a/openai-java-client-okhttp/src/test/kotlin/com/openai/client/okhttp/OkHttpClientTest.kt +++ b/openai-java-client-okhttp/src/test/kotlin/com/openai/client/okhttp/OkHttpClientTest.kt @@ -126,6 +126,42 @@ internal class OkHttpClientTest { assertThat(call.isCanceled()).isTrue() } + @Test + fun execute_runsConfiguredApplicationInterceptor() { + stubFor(get(urlPathEqualTo("/something")).willReturn(ok())) + val client = + OkHttpClient.builder() + .addInterceptor( + Interceptor { chain -> + chain.proceed( + chain + .request() + .newBuilder() + .header("X-Test-Interceptor", "applied") + .build() + ) + } + ) + .build() + + client + .execute( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(baseUrl) + .addPathSegment("something") + .build() + ) + .use { assertThat(it.statusCode()).isEqualTo(200) } + + verify( + 1, + getRequestedFor(urlPathEqualTo("/something")) + .withHeader("X-Test-Interceptor", equalTo("applied")), + ) + client.close() + } + @Test fun cancellingMultipartUploadAbortsCallWaitingForResponse() { val callFailed = CountDownLatch(1)