Skip to content

Commit 3f74519

Browse files
feat(client): add https config options
1 parent 220503e commit 3f74519

File tree

4 files changed

+182
-4
lines changed

4 files changed

+182
-4
lines changed

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1398,6 +1398,27 @@ OpenAIClient client = OpenAIOkHttpClient.builder()
13981398
.build();
13991399
```
14001400

1401+
### HTTPS
1402+
1403+
> [!NOTE]
1404+
> Most applications should not call these methods, and instead use the system defaults. The defaults include
1405+
> special optimizations that can be lost if the implementations are modified.
1406+
1407+
To configure how HTTPS connections are secured, configure the client using the `sslSocketFactory`, `trustManager`, and `hostnameVerifier` methods:
1408+
1409+
```java
1410+
import com.openai.client.OpenAIClient;
1411+
import com.openai.client.okhttp.OpenAIOkHttpClient;
1412+
1413+
OpenAIClient client = OpenAIOkHttpClient.builder()
1414+
.fromEnv()
1415+
// If `sslSocketFactory` is set, then `trustManager` must be set, and vice versa.
1416+
.sslSocketFactory(yourSSLSocketFactory)
1417+
.trustManager(yourTrustManager)
1418+
.hostnameVerifier(yourHostnameVerifier)
1419+
.build();
1420+
```
1421+
14011422
### Custom HTTP client
14021423

14031424
The SDK consists of three artifacts:

openai-java-client-okhttp/src/main/kotlin/com/openai/client/okhttp/OkHttpClient.kt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ import java.io.InputStream
1414
import java.net.Proxy
1515
import java.time.Duration
1616
import java.util.concurrent.CompletableFuture
17+
import javax.net.ssl.HostnameVerifier
18+
import javax.net.ssl.SSLSocketFactory
19+
import javax.net.ssl.X509TrustManager
1720
import okhttp3.Call
1821
import okhttp3.Callback
1922
import okhttp3.HttpUrl.Companion.toHttpUrl
@@ -189,13 +192,28 @@ class OkHttpClient private constructor(private val okHttpClient: okhttp3.OkHttpC
189192

190193
private var timeout: Timeout = Timeout.default()
191194
private var proxy: Proxy? = null
195+
private var sslSocketFactory: SSLSocketFactory? = null
196+
private var trustManager: X509TrustManager? = null
197+
private var hostnameVerifier: HostnameVerifier? = null
192198

193199
fun timeout(timeout: Timeout) = apply { this.timeout = timeout }
194200

195201
fun timeout(timeout: Duration) = timeout(Timeout.builder().request(timeout).build())
196202

197203
fun proxy(proxy: Proxy?) = apply { this.proxy = proxy }
198204

205+
fun sslSocketFactory(sslSocketFactory: SSLSocketFactory?) = apply {
206+
this.sslSocketFactory = sslSocketFactory
207+
}
208+
209+
fun trustManager(trustManager: X509TrustManager?) = apply {
210+
this.trustManager = trustManager
211+
}
212+
213+
fun hostnameVerifier(hostnameVerifier: HostnameVerifier?) = apply {
214+
this.hostnameVerifier = hostnameVerifier
215+
}
216+
199217
fun build(): OkHttpClient =
200218
OkHttpClient(
201219
okhttp3.OkHttpClient.Builder()
@@ -204,6 +222,19 @@ class OkHttpClient private constructor(private val okHttpClient: okhttp3.OkHttpC
204222
.writeTimeout(timeout.write())
205223
.callTimeout(timeout.request())
206224
.proxy(proxy)
225+
.apply {
226+
val sslSocketFactory = sslSocketFactory
227+
val trustManager = trustManager
228+
if (sslSocketFactory != null && trustManager != null) {
229+
sslSocketFactory(sslSocketFactory, trustManager)
230+
} else {
231+
check((sslSocketFactory != null) == (trustManager != null)) {
232+
"Both or none of `sslSocketFactory` and `trustManager` must be set, but only one was set"
233+
}
234+
}
235+
236+
hostnameVerifier?.let(::hostnameVerifier)
237+
}
207238
.build()
208239
.apply {
209240
// We usually make all our requests to the same host so it makes sense to

openai-java-client-okhttp/src/main/kotlin/com/openai/client/okhttp/OpenAIOkHttpClient.kt

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ import java.time.Clock
1717
import java.time.Duration
1818
import java.util.Optional
1919
import java.util.concurrent.Executor
20+
import javax.net.ssl.HostnameVerifier
21+
import javax.net.ssl.SSLSocketFactory
22+
import javax.net.ssl.X509TrustManager
2023
import kotlin.jvm.optionals.getOrNull
2124

2225
class OpenAIOkHttpClient private constructor() {
@@ -34,8 +37,62 @@ class OpenAIOkHttpClient private constructor() {
3437

3538
private var clientOptions: ClientOptions.Builder = ClientOptions.builder()
3639
private var proxy: Proxy? = null
40+
private var sslSocketFactory: SSLSocketFactory? = null
41+
private var trustManager: X509TrustManager? = null
42+
private var hostnameVerifier: HostnameVerifier? = null
3743

38-
fun proxy(proxy: Proxy) = apply { this.proxy = proxy }
44+
fun proxy(proxy: Proxy?) = apply { this.proxy = proxy }
45+
46+
/** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */
47+
fun proxy(proxy: Optional<Proxy>) = proxy(proxy.getOrNull())
48+
49+
/**
50+
* The socket factory used to secure HTTPS connections.
51+
*
52+
* If this is set, then [trustManager] must also be set.
53+
*
54+
* If unset, then the system default is used. Most applications should not call this method,
55+
* and instead use the system default. The default include special optimizations that can be
56+
* lost if the implementation is modified.
57+
*/
58+
fun sslSocketFactory(sslSocketFactory: SSLSocketFactory?) = apply {
59+
this.sslSocketFactory = sslSocketFactory
60+
}
61+
62+
/** Alias for calling [Builder.sslSocketFactory] with `sslSocketFactory.orElse(null)`. */
63+
fun sslSocketFactory(sslSocketFactory: Optional<SSLSocketFactory>) =
64+
sslSocketFactory(sslSocketFactory.getOrNull())
65+
66+
/**
67+
* The trust manager used to secure HTTPS connections.
68+
*
69+
* If this is set, then [sslSocketFactory] must also be set.
70+
*
71+
* If unset, then the system default is used. Most applications should not call this method,
72+
* and instead use the system default. The default include special optimizations that can be
73+
* lost if the implementation is modified.
74+
*/
75+
fun trustManager(trustManager: X509TrustManager?) = apply {
76+
this.trustManager = trustManager
77+
}
78+
79+
/** Alias for calling [Builder.trustManager] with `trustManager.orElse(null)`. */
80+
fun trustManager(trustManager: Optional<X509TrustManager>) =
81+
trustManager(trustManager.getOrNull())
82+
83+
/**
84+
* The verifier used to confirm that response certificates apply to requested hostnames for
85+
* HTTPS connections.
86+
*
87+
* If unset, then a default hostname verifier is used.
88+
*/
89+
fun hostnameVerifier(hostnameVerifier: HostnameVerifier?) = apply {
90+
this.hostnameVerifier = hostnameVerifier
91+
}
92+
93+
/** Alias for calling [Builder.hostnameVerifier] with `hostnameVerifier.orElse(null)`. */
94+
fun hostnameVerifier(hostnameVerifier: Optional<HostnameVerifier>) =
95+
hostnameVerifier(hostnameVerifier.getOrNull())
3996

4097
/**
4198
* Whether to throw an exception if any of the Jackson versions detected at runtime are
@@ -195,7 +252,13 @@ class OpenAIOkHttpClient private constructor() {
195252
OpenAIClientImpl(
196253
clientOptions
197254
.httpClient(
198-
OkHttpClient.builder().timeout(clientOptions.timeout()).proxy(proxy).build()
255+
OkHttpClient.builder()
256+
.timeout(clientOptions.timeout())
257+
.proxy(proxy)
258+
.sslSocketFactory(sslSocketFactory)
259+
.trustManager(trustManager)
260+
.hostnameVerifier(hostnameVerifier)
261+
.build()
199262
)
200263
.build()
201264
)

openai-java-client-okhttp/src/main/kotlin/com/openai/client/okhttp/OpenAIOkHttpClientAsync.kt

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ import java.time.Clock
1717
import java.time.Duration
1818
import java.util.Optional
1919
import java.util.concurrent.Executor
20+
import javax.net.ssl.HostnameVerifier
21+
import javax.net.ssl.SSLSocketFactory
22+
import javax.net.ssl.X509TrustManager
2023
import kotlin.jvm.optionals.getOrNull
2124

2225
class OpenAIOkHttpClientAsync private constructor() {
@@ -34,8 +37,62 @@ class OpenAIOkHttpClientAsync private constructor() {
3437

3538
private var clientOptions: ClientOptions.Builder = ClientOptions.builder()
3639
private var proxy: Proxy? = null
40+
private var sslSocketFactory: SSLSocketFactory? = null
41+
private var trustManager: X509TrustManager? = null
42+
private var hostnameVerifier: HostnameVerifier? = null
3743

38-
fun proxy(proxy: Proxy) = apply { this.proxy = proxy }
44+
fun proxy(proxy: Proxy?) = apply { this.proxy = proxy }
45+
46+
/** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */
47+
fun proxy(proxy: Optional<Proxy>) = proxy(proxy.getOrNull())
48+
49+
/**
50+
* The socket factory used to secure HTTPS connections.
51+
*
52+
* If this is set, then [trustManager] must also be set.
53+
*
54+
* If unset, then the system default is used. Most applications should not call this method,
55+
* and instead use the system default. The default include special optimizations that can be
56+
* lost if the implementation is modified.
57+
*/
58+
fun sslSocketFactory(sslSocketFactory: SSLSocketFactory?) = apply {
59+
this.sslSocketFactory = sslSocketFactory
60+
}
61+
62+
/** Alias for calling [Builder.sslSocketFactory] with `sslSocketFactory.orElse(null)`. */
63+
fun sslSocketFactory(sslSocketFactory: Optional<SSLSocketFactory>) =
64+
sslSocketFactory(sslSocketFactory.getOrNull())
65+
66+
/**
67+
* The trust manager used to secure HTTPS connections.
68+
*
69+
* If this is set, then [sslSocketFactory] must also be set.
70+
*
71+
* If unset, then the system default is used. Most applications should not call this method,
72+
* and instead use the system default. The default include special optimizations that can be
73+
* lost if the implementation is modified.
74+
*/
75+
fun trustManager(trustManager: X509TrustManager?) = apply {
76+
this.trustManager = trustManager
77+
}
78+
79+
/** Alias for calling [Builder.trustManager] with `trustManager.orElse(null)`. */
80+
fun trustManager(trustManager: Optional<X509TrustManager>) =
81+
trustManager(trustManager.getOrNull())
82+
83+
/**
84+
* The verifier used to confirm that response certificates apply to requested hostnames for
85+
* HTTPS connections.
86+
*
87+
* If unset, then a default hostname verifier is used.
88+
*/
89+
fun hostnameVerifier(hostnameVerifier: HostnameVerifier?) = apply {
90+
this.hostnameVerifier = hostnameVerifier
91+
}
92+
93+
/** Alias for calling [Builder.hostnameVerifier] with `hostnameVerifier.orElse(null)`. */
94+
fun hostnameVerifier(hostnameVerifier: Optional<HostnameVerifier>) =
95+
hostnameVerifier(hostnameVerifier.getOrNull())
3996

4097
/**
4198
* Whether to throw an exception if any of the Jackson versions detected at runtime are
@@ -195,7 +252,13 @@ class OpenAIOkHttpClientAsync private constructor() {
195252
OpenAIClientAsyncImpl(
196253
clientOptions
197254
.httpClient(
198-
OkHttpClient.builder().timeout(clientOptions.timeout()).proxy(proxy).build()
255+
OkHttpClient.builder()
256+
.timeout(clientOptions.timeout())
257+
.proxy(proxy)
258+
.sslSocketFactory(sslSocketFactory)
259+
.trustManager(trustManager)
260+
.hostnameVerifier(hostnameVerifier)
261+
.build()
199262
)
200263
.build()
201264
)

0 commit comments

Comments
 (0)