1616import com .ibm .cloud .sdk .core .http .HttpConfigOptions .LoggingLevel ;
1717import com .ibm .cloud .sdk .core .http .gzip .GzipRequestInterceptor ;
1818import com .ibm .cloud .sdk .core .service .security .DelegatingSSLSocketFactory ;
19+ import com .ibm .cloud .sdk .core .util .EnvironmentUtils ;
20+
1921import okhttp3 .Authenticator ;
2022import okhttp3 .ConnectionSpec ;
2123import okhttp3 .Interceptor ;
@@ -179,6 +181,7 @@ private OkHttpClient configureHttpClient() {
179181 final OkHttpClient .Builder builder = new OkHttpClient .Builder ();
180182
181183 addCookieJar (builder );
184+ addRedirectInterceptor (builder );
182185
183186 builder .connectTimeout (60 , TimeUnit .SECONDS );
184187 builder .writeTimeout (60 , TimeUnit .SECONDS );
@@ -197,11 +200,34 @@ private OkHttpClient configureHttpClient() {
197200 *
198201 * @param builder the builder
199202 */
200- private void addCookieJar (final OkHttpClient .Builder builder ) {
203+ private OkHttpClient . Builder addCookieJar (final OkHttpClient .Builder builder ) {
201204 final CookieManager cookieManager = new CookieManager ();
202205 cookieManager .setCookiePolicy (CookiePolicy .ACCEPT_ALL );
203206
204207 builder .cookieJar (new ServiceCookieJar (cookieManager ));
208+ return builder ;
209+ }
210+
211+ /**
212+ * Adds the RedirectInterceptor to the client builder.
213+ * @param builder
214+ */
215+ private OkHttpClient .Builder addRedirectInterceptor (final OkHttpClient .Builder builder ) {
216+ String envvar = EnvironmentUtils .getenv ("IBMCLOUD_BYPASS_CUSTOM_REDIRECTS" );
217+ if (!Boolean .valueOf (envvar )) {
218+ // Disable the built-in "followRedirects" so that okhttp will ignore redirects.
219+ builder .followRedirects (false ).followSslRedirects (false );
220+
221+ // Add our RedirectInterceptor to the client.
222+ builder .addInterceptor (new RedirectInterceptor ());
223+ LOG .log (Level .FINE , "Registered the redirect interceptor." );
224+ } else {
225+ LOG .log (Level .FINE , "Bypassed redirect interceptor via options." );
226+
227+ // Set the defaults for these two options.
228+ builder .followRedirects (true ).followSslRedirects (true );
229+ }
230+ return builder ;
205231 }
206232
207233 /**
@@ -337,30 +363,6 @@ public static void setupTLSProtocol(final OkHttpClient.Builder builder) {
337363 }
338364 }
339365
340- /**
341- * Sets a new list of interceptors for the specified {@link OkHttpClient} instance by removing the specified
342- * interceptor and returns a new instance with the interceptors configured as requested.
343- *
344- * @param client the {@link OkHttpClient} instance to remove the interceptors from
345- * @param interceptorToRemove the class name of the interceptor to remove
346- * @return the new {@link OkHttpClient} instance with the new list of interceptors
347- */
348- private OkHttpClient reconfigureClientInterceptors (OkHttpClient client , String interceptorToRemove ) {
349- OkHttpClient .Builder builder = client .newBuilder ();
350-
351- if (!builder .interceptors ().isEmpty ()) {
352- for (Iterator <Interceptor > iter = builder .interceptors ().iterator (); iter .hasNext (); ) {
353- Interceptor element = iter .next ();
354- if (interceptorToRemove .equals (element .getClass ().getSimpleName ())) {
355- LOG .log (Level .FINE , "Removing interceptor " + element .getClass ().getName () + " from http client instance." );
356- iter .remove ();
357- }
358- }
359- }
360-
361- return builder .build ();
362- }
363-
364366 /**
365367 * Sets a new list of interceptors for the specified {@link OkHttpClient} instance by removing any interceptors
366368 * that implement "interfaceToRemove".
@@ -370,7 +372,7 @@ private OkHttpClient reconfigureClientInterceptors(OkHttpClient client, String i
370372 * @return the new {@link OkHttpClient} instance with the updated list of interceptors
371373 */
372374 private OkHttpClient reconfigureClientInterceptors (OkHttpClient client ,
373- Class <? extends Interceptor > interfaceToRemove ) {
375+ Class <? extends Interceptor > interfaceToRemove ) {
374376 OkHttpClient .Builder builder = client .newBuilder ();
375377
376378 if (!builder .interceptors ().isEmpty ()) {
@@ -395,6 +397,7 @@ private OkHttpClient reconfigureClientInterceptors(OkHttpClient client,
395397 public OkHttpClient createHttpClient () {
396398 Builder builder = okHttpClient .newBuilder ();
397399 addCookieJar (builder );
400+ addRedirectInterceptor (builder );
398401 return builder .build ();
399402 }
400403
@@ -419,7 +422,10 @@ public OkHttpClient configureClient(HttpConfigOptions options) {
419422 * @return a new {@link OkHttpClient} instance with the specified options applied
420423 */
421424 public OkHttpClient configureClient (OkHttpClient client , HttpConfigOptions options ) {
425+ Boolean customRedirects = null ;
422426 if (options != null ) {
427+ customRedirects = options .getCustomRedirects ();
428+
423429 if (options .shouldDisableSslVerification ()) {
424430 client = disableSslVerification (client );
425431 }
@@ -443,6 +449,7 @@ public OkHttpClient configureClient(OkHttpClient client, HttpConfigOptions optio
443449 options .getAuthenticator ());
444450 if (retryInterceptor != null ) {
445451 client = client .newBuilder ().addInterceptor (retryInterceptor ).build ();
452+ LOG .log (Level .FINE , "Registered the retry interceptor." );
446453 } else {
447454 LOG .log (Level .WARNING ,
448455 "The retry interceptor factory returned a null IRetryInterceptor instance. Retries are disabled." );
@@ -453,14 +460,35 @@ public OkHttpClient configureClient(OkHttpClient client, HttpConfigOptions optio
453460 // Configure the GZIP interceptor.
454461 Boolean enableGzip = options .getGzipCompression ();
455462 if (enableGzip != null ) {
456- client = reconfigureClientInterceptors (client , " GzipRequestInterceptor" );
463+ client = reconfigureClientInterceptors (client , GzipRequestInterceptor . class );
457464 if (enableGzip .booleanValue ()) {
458465 client = client .newBuilder ()
459466 .addInterceptor (new GzipRequestInterceptor ())
460467 .build ();
468+ LOG .log (Level .FINE , "Registered the gzip interceptor." );
461469 }
462470 }
463471 }
472+
473+ // Configure the redirect interceptor.
474+ // We want "custom redirects" to be enabled by default (including a scenario
475+ // where "options" is null), hence the need to handle this feature outside the "if" above.
476+ // We want to register the interceptor if:
477+ // 1. options == null
478+ // 2. options != null and "custom redirects" is explicitly set to Boolean.TRUE
479+ //
480+ // We also want to allow "custom redirects" to be bypassed by setting an environment variable.
481+ // This may be only temporary until we are comfortable with this new function, but I'm
482+ // adding support for this environment variable as a quick fix in case there are "unforeseen
483+ // consequences" after this feature hits the street.
484+ // Example:
485+ // export IBMCLOUD_BYPASS_CUSTOM_REDIRECTS=true
486+ // Setting this environment variable will revert back to using the okhttp builtin support for redirects.
487+ client = reconfigureClientInterceptors (client , RedirectInterceptor .class );
488+ if (customRedirects == null || customRedirects .booleanValue ()) {
489+ client = addRedirectInterceptor (client .newBuilder ()).build ();
490+ }
491+
464492 return client ;
465493 }
466494}
0 commit comments