From fa8de3f457efb87bc12b82df4305aef9384621ce Mon Sep 17 00:00:00 2001 From: Bilal Al Date: Tue, 13 Aug 2024 09:04:40 -0700 Subject: [PATCH 1/8] added kerberos auth support --- .../io/split/client/SplitClientConfig.java | 35 ++- .../io/split/client/SplitFactoryImpl.java | 8 + .../service/SplitHttpClientKerberosImpl.java | 214 ++++++++++++++++++ .../split/client/SplitClientConfigTest.java | 25 ++ .../io/split/client/SplitFactoryImplTest.java | 19 ++ .../service/HttpSplitClientKerberosTest.java | 198 ++++++++++++++++ 6 files changed, 493 insertions(+), 6 deletions(-) create mode 100644 client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java create mode 100644 client/src/test/java/io/split/service/HttpSplitClientKerberosTest.java diff --git a/client/src/main/java/io/split/client/SplitClientConfig.java b/client/src/main/java/io/split/client/SplitClientConfig.java index 2f29c1719..3d69a6283 100644 --- a/client/src/main/java/io/split/client/SplitClientConfig.java +++ b/client/src/main/java/io/split/client/SplitClientConfig.java @@ -10,10 +10,7 @@ import pluggable.CustomStorageWrapper; import java.io.IOException; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Properties; +import java.util.*; import java.util.concurrent.ThreadFactory; import java.io.InputStream; @@ -91,6 +88,7 @@ public class SplitClientConfig { private final HashSet _flagSetsFilter; private final int _invalidSets; private final CustomHeaderDecorator _customHeaderDecorator; + private final String _authScheme; public static Builder builder() { @@ -148,7 +146,8 @@ private SplitClientConfig(String endpoint, ThreadFactory threadFactory, HashSet flagSetsFilter, int invalidSets, - CustomHeaderDecorator customHeaderDecorator) { + CustomHeaderDecorator customHeaderDecorator, + String authScheme) { _endpoint = endpoint; _eventsEndpoint = eventsEndpoint; _featuresRefreshRate = pollForFeatureChangesEveryNSeconds; @@ -201,6 +200,7 @@ private SplitClientConfig(String endpoint, _flagSetsFilter = flagSetsFilter; _invalidSets = invalidSets; _customHeaderDecorator = customHeaderDecorator; + _authScheme = authScheme; Properties props = new Properties(); try { @@ -408,6 +408,9 @@ public int getInvalidSets() { public CustomHeaderDecorator customHeaderDecorator() { return _customHeaderDecorator; } + public String authScheme() { + return _authScheme; + } public static final class Builder { @@ -466,6 +469,7 @@ public static final class Builder { private HashSet _flagSetsFilter = new HashSet<>(); private int _invalidSetsCount = 0; private CustomHeaderDecorator _customHeaderDecorator = null; + private String _authScheme = null; public Builder() { } @@ -960,6 +964,17 @@ public Builder customHeaderDecorator(CustomHeaderDecorator customHeaderDecorator return this; } + /** + * Authentication Scheme + * + * @param authScheme + * @return this builder + */ + public Builder authScheme(String authScheme) { + _authScheme = authScheme; + return this; + } + /** * Thread Factory * @@ -1068,6 +1083,13 @@ public SplitClientConfig build() { _storageMode = StorageMode.PLUGGABLE; } + if(_authScheme != null) { + if (!_authScheme.toLowerCase(Locale.ROOT).equals("kerberos")) { + throw new IllegalArgumentException("authScheme must be either null or `kerberos`."); + } + _authScheme = "kerberos"; + } + return new SplitClientConfig( _endpoint, _eventsEndpoint, @@ -1120,7 +1142,8 @@ public SplitClientConfig build() { _threadFactory, _flagSetsFilter, _invalidSetsCount, - _customHeaderDecorator); + _customHeaderDecorator, + _authScheme); } } } \ No newline at end of file diff --git a/client/src/main/java/io/split/client/SplitFactoryImpl.java b/client/src/main/java/io/split/client/SplitFactoryImpl.java index a783b1445..0dc967304 100644 --- a/client/src/main/java/io/split/client/SplitFactoryImpl.java +++ b/client/src/main/java/io/split/client/SplitFactoryImpl.java @@ -59,6 +59,7 @@ import io.split.integrations.IntegrationsConfig; import io.split.service.SplitHttpClient; import io.split.service.SplitHttpClientImpl; +import io.split.service.SplitHttpClientKerberosImpl; import io.split.storages.SegmentCache; import io.split.storages.SegmentCacheConsumer; import io.split.storages.SegmentCacheProducer; @@ -525,6 +526,13 @@ private static SplitHttpClient buildSplitHttpClient(String apiToken, SplitClient httpClientbuilder = setupProxy(httpClientbuilder, config); } + if (config.authScheme() != null) { + return SplitHttpClientKerberosImpl.create( + requestDecorator, + apiToken, + sdkMetadata); + + } return SplitHttpClientImpl.create(httpClientbuilder.build(), requestDecorator, apiToken, diff --git a/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java b/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java new file mode 100644 index 000000000..11bd85305 --- /dev/null +++ b/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java @@ -0,0 +1,214 @@ +package io.split.service; + +import io.split.client.RequestDecorator; +import io.split.client.dtos.SplitHttpResponse; +import io.split.client.utils.SDKMetadata; +import io.split.engine.common.FetchOptions; + +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.HttpRequest; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.message.BasicHeader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.*; +import java.net.*; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class SplitHttpClientKerberosImpl implements SplitHttpClient { + + private static final Logger _log = LoggerFactory.getLogger(SplitHttpClient.class); + private static final String HEADER_CACHE_CONTROL_NAME = "Cache-Control"; + private static final String HEADER_CACHE_CONTROL_VALUE = "no-cache"; + private static final String HEADER_API_KEY = "Authorization"; + private static final String HEADER_CLIENT_KEY = "SplitSDKClientKey"; + private static final String HEADER_CLIENT_MACHINE_NAME = "SplitSDKMachineName"; + private static final String HEADER_CLIENT_MACHINE_IP = "SplitSDKMachineIP"; + private static final String HEADER_CLIENT_VERSION = "SplitSDKVersion"; + + private final RequestDecorator _requestDecorator; + private final String _apikey; + private final SDKMetadata _metadata; + + public static SplitHttpClientKerberosImpl create(RequestDecorator requestDecorator, + String apikey, + SDKMetadata metadata) throws URISyntaxException { + return new SplitHttpClientKerberosImpl(requestDecorator, apikey, metadata); + } + + SplitHttpClientKerberosImpl(RequestDecorator requestDecorator, + String apikey, + SDKMetadata metadata) { + _requestDecorator = requestDecorator; + _apikey = apikey; + _metadata = metadata; + } + + public synchronized SplitHttpResponse get(URI uri, FetchOptions options, Map> additionalHeaders) { + HttpURLConnection getHttpURLConnection = null; + try { + getHttpURLConnection = (HttpURLConnection) uri.toURL().openConnection(); + return _get(getHttpURLConnection, options, additionalHeaders); + } catch (Exception e) { + throw new IllegalStateException(String.format("Problem in http get operation: %s", e), e); + } finally { + try { + getHttpURLConnection.disconnect(); + } catch (Exception e) { + _log.error(String.format("Could not close HTTP URL Connection: %s", e), e); + } + } + } + public SplitHttpResponse _get(HttpURLConnection getHttpURLConnection, FetchOptions options, Map> additionalHeaders) { + InputStreamReader inputStreamReader = null; + try { + getHttpURLConnection.setRequestMethod("GET"); + + setBasicHeaders(getHttpURLConnection); + setAdditionalAndDecoratedHeaders(getHttpURLConnection, additionalHeaders); + + if (options.cacheControlHeadersEnabled()) { + getHttpURLConnection.setRequestProperty(HEADER_CACHE_CONTROL_NAME, HEADER_CACHE_CONTROL_VALUE); + } + + _log.debug(String.format("Request Headers: %s", getHttpURLConnection.getRequestProperties())); + + int responseCode = getHttpURLConnection.getResponseCode(); + + if (_log.isDebugEnabled()) { + _log.debug(String.format("[%s] %s. Status code: %s", + getHttpURLConnection.getRequestMethod(), + getHttpURLConnection.getURL().toString(), + responseCode)); + } + + String statusMessage = ""; + if (responseCode < HttpURLConnection.HTTP_OK || responseCode >= HttpURLConnection.HTTP_MULT_CHOICE) { + _log.warn(String.format("Response status was: %s. Reason: %s", responseCode, + getHttpURLConnection.getResponseMessage())); + statusMessage = getHttpURLConnection.getResponseMessage(); + } + + inputStreamReader = new InputStreamReader(getHttpURLConnection.getInputStream()); + BufferedReader br = new BufferedReader(inputStreamReader); + String strCurrentLine; + String responseBody = new String(); + while ((strCurrentLine = br.readLine()) != null) { + responseBody = responseBody + strCurrentLine; + } + return new SplitHttpResponse(responseCode, + statusMessage, + responseBody, + getResponseHeaders(getHttpURLConnection)); + } catch (Exception e) { + throw new IllegalStateException(String.format("Problem in http get operation: %s", e), e); + } finally { + try { + inputStreamReader.close(); + } catch (Exception e) { + _log.error(String.format("Could not close HTTP Stream: %s", e), e); + } + } + } + + public synchronized SplitHttpResponse post(URI uri, HttpEntity entity, Map> additionalHeaders) throws IOException { + HttpURLConnection postHttpURLConnection = null; + try { + postHttpURLConnection = (HttpURLConnection) uri.toURL().openConnection(); + return _post(postHttpURLConnection, entity, additionalHeaders); + } catch (Exception e) { + throw new IOException(String.format("Problem in http post operation: %s", e), e); + } finally { + try { + postHttpURLConnection.disconnect(); + } catch (Exception e) { + _log.error(String.format("Could not close URL Connection: %s", e), e); + } + } + } + + public SplitHttpResponse _post(HttpURLConnection postHttpURLConnection, + HttpEntity entity, + Map> additionalHeaders) + throws IOException { + try { + postHttpURLConnection.setRequestMethod("POST"); + setBasicHeaders(postHttpURLConnection); + setAdditionalAndDecoratedHeaders(postHttpURLConnection, additionalHeaders); + + if (postHttpURLConnection.getHeaderField("Accept-Encoding") == null) { + postHttpURLConnection.setRequestProperty("Accept-Encoding", "gzip"); + } + postHttpURLConnection.setRequestProperty("Content-Type", "application/json"); + _log.debug(String.format("Request Headers: %s", postHttpURLConnection.getRequestProperties())); + + postHttpURLConnection.setDoOutput(true); + String postBody = EntityUtils.toString(entity); + OutputStream os = postHttpURLConnection.getOutputStream(); + os.write(postBody.getBytes(StandardCharsets.UTF_8)); + os.flush(); + os.close(); + _log.debug(String.format("Posting: %s", postBody)); + + int responseCode = postHttpURLConnection.getResponseCode(); + String statusMessage = ""; + if (responseCode < HttpURLConnection.HTTP_OK || responseCode >= HttpURLConnection.HTTP_MULT_CHOICE) { + statusMessage = postHttpURLConnection.getResponseMessage(); + _log.warn(String.format("Response status was: %s. Reason: %s", responseCode, + statusMessage)); + } + return new SplitHttpResponse(responseCode, statusMessage, "", getResponseHeaders(postHttpURLConnection)); + } catch (Exception e) { + throw new IOException(String.format("Problem in http post operation: %s", e), e); + } + } + + private void setBasicHeaders(HttpURLConnection urlConnection) { + urlConnection.setRequestProperty(HEADER_API_KEY, "Bearer " + _apikey); + urlConnection.setRequestProperty(HEADER_CLIENT_VERSION, _metadata.getSdkVersion()); + urlConnection.setRequestProperty(HEADER_CLIENT_MACHINE_IP, _metadata.getMachineIp()); + urlConnection.setRequestProperty(HEADER_CLIENT_MACHINE_NAME, _metadata.getMachineName()); + urlConnection.setRequestProperty(HEADER_CLIENT_KEY, _apikey.length() > 4 + ? _apikey.substring(_apikey.length() - 4) + : _apikey); + } + + private void setAdditionalAndDecoratedHeaders(HttpURLConnection urlConnection, Map> additionalHeaders) { + if (additionalHeaders != null) { + for (Map.Entry> entry : additionalHeaders.entrySet()) { + for (String value : entry.getValue()) { + urlConnection.setRequestProperty(entry.getKey(), value); + } + } + } + HttpRequest request = new HttpGet(""); + _requestDecorator.decorateHeaders(request); + for (Header header : request.getHeaders()) { + urlConnection.setRequestProperty(header.getName(), header.getValue()); + } + request = null; + } + + private Header[] getResponseHeaders(HttpURLConnection urlConnection) { + List responseHeaders = new ArrayList(); + Map> map = urlConnection.getHeaderFields(); + for (Map.Entry> entry : map.entrySet()) { + if (entry.getKey() != null) { + BasicHeader responseHeader = new BasicHeader(entry.getKey(), entry.getValue()); + responseHeaders.add(responseHeader); + } + } + return responseHeaders.toArray(new Header[0]); + + } + @Override + public void close() throws IOException { +// _client.close(); + } +} diff --git a/client/src/test/java/io/split/client/SplitClientConfigTest.java b/client/src/test/java/io/split/client/SplitClientConfigTest.java index 1b640071c..d323ebe21 100644 --- a/client/src/test/java/io/split/client/SplitClientConfigTest.java +++ b/client/src/test/java/io/split/client/SplitClientConfigTest.java @@ -254,4 +254,29 @@ public Map> getHeaderOverrides(RequestContext context) { Assert.assertNull(config2.customHeaderDecorator()); } + + @Test + public void checkExpectedAuthScheme() { + SplitClientConfig cfg = SplitClientConfig.builder() + .authScheme("kerberos") + .build(); + Assert.assertEquals("kerberos", cfg.authScheme()); + + cfg = SplitClientConfig.builder() + .authScheme("KERberos") + .build(); + Assert.assertEquals("kerberos", cfg.authScheme()); + + cfg = SplitClientConfig.builder() + .build(); + Assert.assertEquals(null, cfg.authScheme()); + } + + @Test(expected = IllegalArgumentException.class) + public void checkUnexpectedAuthScheme() { + SplitClientConfig cfg = SplitClientConfig.builder() + .authScheme("proxy") + .build(); + Assert.assertEquals(null, cfg.authScheme()); + } } \ No newline at end of file diff --git a/client/src/test/java/io/split/client/SplitFactoryImplTest.java b/client/src/test/java/io/split/client/SplitFactoryImplTest.java index 2d548f9e6..00e9f626b 100644 --- a/client/src/test/java/io/split/client/SplitFactoryImplTest.java +++ b/client/src/test/java/io/split/client/SplitFactoryImplTest.java @@ -2,7 +2,9 @@ import io.split.client.impressions.ImpressionsManager; import io.split.client.utils.FileTypeEnum; +import io.split.client.utils.SDKMetadata; import io.split.integrations.IntegrationsConfig; +import io.split.service.SplitHttpClientKerberosImpl; import io.split.storages.enums.OperationMode; import io.split.storages.pluggable.domain.UserStorageWrapper; import io.split.telemetry.storage.TelemetryStorage; @@ -22,6 +24,8 @@ import java.lang.reflect.Modifier; import java.net.URISyntaxException; +import static io.split.client.SplitClientConfig.splitSdkVersion; + public class SplitFactoryImplTest extends TestCase { public static final String API_KEY ="29013ionasdasd09u"; public static final String ENDPOINT = "https://sdk.split-stage.io"; @@ -344,4 +348,19 @@ public void testLocalhosJsonInputStreamNullAndFileTypeNull() throws URISyntaxExc Object splitChangeFetcher = method.invoke(splitFactory, splitClientConfig); Assert.assertTrue(splitChangeFetcher instanceof LegacyLocalhostSplitChangeFetcher); } + + @Test + public void testFactoryKerberosInstance() throws URISyntaxException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { + SplitClientConfig splitClientConfig = SplitClientConfig.builder() + .setBlockUntilReadyTimeout(10000) + .authScheme("kerberos") + .build(); + SplitFactoryImpl splitFactory = new SplitFactoryImpl("asdf", splitClientConfig); + + Method method = SplitFactoryImpl.class.getDeclaredMethod("buildSplitHttpClient", String.class, + SplitClientConfig.class, SDKMetadata.class, RequestDecorator.class); + method.setAccessible(true); + Object SplitHttpClient = method.invoke(splitFactory, "asdf", splitClientConfig, new SDKMetadata(splitSdkVersion, "", ""), new RequestDecorator(null)); + Assert.assertTrue(SplitHttpClient instanceof SplitHttpClientKerberosImpl); + } } \ No newline at end of file diff --git a/client/src/test/java/io/split/service/HttpSplitClientKerberosTest.java b/client/src/test/java/io/split/service/HttpSplitClientKerberosTest.java new file mode 100644 index 000000000..afbf0e718 --- /dev/null +++ b/client/src/test/java/io/split/service/HttpSplitClientKerberosTest.java @@ -0,0 +1,198 @@ +package io.split.service; + +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import io.split.TestHelper; +import io.split.client.RequestDecorator; +import io.split.client.dtos.*; +import io.split.client.impressions.Impression; +import io.split.client.utils.Json; +import io.split.client.utils.SDKMetadata; +import io.split.client.utils.Utils; +import io.split.engine.common.FetchOptions; + +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.core5.http.*; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + +import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.net.*; +import java.nio.charset.StandardCharsets; +import java.util.*; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; + +public class HttpSplitClientKerberosTest { + + @Test + public void testGetWithSpecialCharacters() throws URISyntaxException, IOException { + Map> responseHeaders = new HashMap>(); + responseHeaders.put((HttpHeaders.VIA), Arrays.asList("HTTP/1.1 s_proxy_rio1")); + + HttpURLConnection mockHttpURLConnection = Mockito.mock(HttpURLConnection.class); + when(mockHttpURLConnection.getHeaderFields()).thenReturn(responseHeaders); + + RequestDecorator decorator = new RequestDecorator(null); + + Mockito.when(mockHttpURLConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); + ByteArrayInputStream stubInputStream = new ByteArrayInputStream(Files.asCharSource( + new File("src/test/resources/split-change-special-characters.json"), Charsets.UTF_8).read().getBytes(Charsets.UTF_8)); + when(mockHttpURLConnection.getInputStream()).thenReturn(stubInputStream); + + SplitHttpClientKerberosImpl splitHtpClientKerberos = SplitHttpClientKerberosImpl.create(decorator, "qwerty", metadata()); + + Map> additionalHeaders = Collections.singletonMap("AdditionalHeader", + Collections.singletonList("add")); + + SplitHttpResponse splitHttpResponse = splitHtpClientKerberos._get(mockHttpURLConnection, + new FetchOptions.Builder().cacheControlHeaders(true).build(), additionalHeaders); + SplitChange change = Json.fromJson(splitHttpResponse.body(), SplitChange.class); + + Header[] headers = splitHttpResponse.responseHeaders(); + assertThat(headers[0].getName(), is(equalTo("Via"))); + assertThat(headers[0].getValue(), is(equalTo("[HTTP/1.1 s_proxy_rio1]"))); + Assert.assertNotNull(change); + Assert.assertEquals(1, change.splits.size()); + Assert.assertNotNull(change.splits.get(0)); + + Split split = change.splits.get(0); + Map configs = split.configurations; + Assert.assertEquals(2, configs.size()); + Assert.assertEquals("{\"test\": \"blue\",\"grüne Straße\": 13}", configs.get("on")); + Assert.assertEquals("{\"test\": \"blue\",\"size\": 15}", configs.get("off")); + Assert.assertEquals(2, split.sets.size()); + } + + @Test + public void testGetParameters() throws URISyntaxException, MalformedURLException { + URI uri = new URI("https://api.split.io/splitChanges?since=1234567"); + FetchOptions options = new FetchOptions.Builder().cacheControlHeaders(true).build(); + SplitHttpClientKerberosImpl splitHtpClientKerberos = Mockito.mock(SplitHttpClientKerberosImpl.class); + when(splitHtpClientKerberos.get(uri, options, null)).thenCallRealMethod(); + + SplitHttpResponse splitHttpResponse = splitHtpClientKerberos.get(uri, options, null); + + ArgumentCaptor connectionCaptor = ArgumentCaptor.forClass(HttpURLConnection.class); + ArgumentCaptor optionsCaptor = ArgumentCaptor.forClass(FetchOptions.class); + ArgumentCaptor headersCaptor = ArgumentCaptor.forClass(HashMap.class); + verify(splitHtpClientKerberos)._get(connectionCaptor.capture(), optionsCaptor.capture(), headersCaptor.capture()); + + assertThat(connectionCaptor.getValue().getRequestMethod(), is(equalTo("GET"))); + assertThat(connectionCaptor.getValue().getURL().toString(), is(equalTo(new URL("https://api.split.io/splitChanges?since=1234567").toString()))); + + assertThat(optionsCaptor.getValue().cacheControlHeadersEnabled(), is(equalTo(true))); + } + + @Test + public void testGetError() throws URISyntaxException, IOException { + HttpURLConnection mockHttpURLConnection = Mockito.mock(HttpURLConnection.class); + RequestDecorator decorator = new RequestDecorator(null); + + Mockito.when(mockHttpURLConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_INTERNAL_ERROR); + ByteArrayInputStream stubInputStream = new ByteArrayInputStream(Files.asCharSource( + new File("/Users/bilalal-shahwany/repos/java/kerberos/java-client/client/src/test/resources/split-change-special-characters.json"), Charsets.UTF_8).read().getBytes(Charsets.UTF_8)); + when(mockHttpURLConnection.getInputStream()).thenReturn(stubInputStream); + + SplitHttpClientKerberosImpl splitHtpClientKerberos = SplitHttpClientKerberosImpl.create(decorator, "qwerty", metadata()); + SplitHttpResponse splitHttpResponse = splitHtpClientKerberos._get(mockHttpURLConnection, + new FetchOptions.Builder().cacheControlHeaders(true).build(), null); + Assert.assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, (long) splitHttpResponse.statusCode()); + } + + @Test(expected = IllegalStateException.class) + public void testException() throws URISyntaxException, InvocationTargetException, NoSuchMethodException, + IllegalAccessException, IOException { + URI rootTarget = URI.create("https://api.split.io/splitChanges?since=1234567"); + CloseableHttpClient httpClientMock = TestHelper.mockHttpClient("split-change-special-characters.json", + HttpStatus.SC_INTERNAL_SERVER_ERROR); + RequestDecorator decorator = null; + + SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClientMock, decorator, "qwerty", metadata()); + splitHtpClient.get(rootTarget, + new FetchOptions.Builder().cacheControlHeaders(true).build(), null); + } + + @Test + public void testPost() throws URISyntaxException, IOException, ParseException { + HttpURLConnection mockHttpURLConnection = Mockito.mock(HttpURLConnection.class); + RequestDecorator decorator = new RequestDecorator(null); + Mockito.when(mockHttpURLConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); + + SplitHttpClientKerberosImpl splitHtpClientKerberos = SplitHttpClientKerberosImpl.create(decorator, "qwerty", metadata()); + + // Send impressions + List toSend = Arrays.asList(new TestImpressions("t1", Arrays.asList( + KeyImpression.fromImpression(new Impression("k1", null, "t1", "on", 123L, "r1", 456L, null)), + KeyImpression.fromImpression(new Impression("k2", null, "t1", "on", 123L, "r1", 456L, null)), + KeyImpression.fromImpression(new Impression("k3", null, "t1", "on", 123L, "r1", 456L, null)))), + new TestImpressions("t2", Arrays.asList( + KeyImpression.fromImpression(new Impression("k1", null, "t2", "on", 123L, "r1", 456L, null)), + KeyImpression.fromImpression(new Impression("k2", null, "t2", "on", 123L, "r1", 456L, null)), + KeyImpression.fromImpression(new Impression("k3", null, "t2", "on", 123L, "r1", 456L, null))))); + + Map> additionalHeaders = Collections.singletonMap("SplitSDKImpressionsMode", + Collections.singletonList("OPTIMIZED")); + when(mockHttpURLConnection.getHeaderFields()).thenReturn(additionalHeaders); + + ByteArrayOutputStream mockOs = Mockito.mock( ByteArrayOutputStream.class); + when(mockHttpURLConnection.getOutputStream()).thenReturn(mockOs); + + SplitHttpResponse splitHttpResponse = splitHtpClientKerberos._post(mockHttpURLConnection, Utils.toJsonEntity(toSend), + additionalHeaders); + + // Capture outgoing request and validate it + ArgumentCaptor captor = ArgumentCaptor.forClass(byte[].class); + verify(mockOs).write(captor.capture()); + String postBody = EntityUtils.toString(Utils.toJsonEntity(toSend)); + assertThat(captor.getValue(), is(equalTo(postBody.getBytes(StandardCharsets.UTF_8)))); + + Header[] headers = splitHttpResponse.responseHeaders(); + assertThat(headers[0].getName(), is(equalTo("SplitSDKImpressionsMode"))); + assertThat(headers[0].getValue(), is(equalTo("[OPTIMIZED]"))); + + Assert.assertEquals(200, (long) splitHttpResponse.statusCode()); + } + + @Test + public void testPotParameters() throws URISyntaxException, IOException { + URI uri = new URI("https://kubernetesturl.com/split/api/testImpressions/bulk"); + SplitHttpClientKerberosImpl splitHtpClientKerberos = Mockito.mock(SplitHttpClientKerberosImpl.class); + when(splitHtpClientKerberos.post(uri, null, null)).thenCallRealMethod(); + + SplitHttpResponse splitHttpResponse = splitHtpClientKerberos.post(uri, null, null); + + ArgumentCaptor connectionCaptor = ArgumentCaptor.forClass(HttpURLConnection.class); + ArgumentCaptor entityCaptor = ArgumentCaptor.forClass(HttpEntity.class); + ArgumentCaptor headersCaptor = ArgumentCaptor.forClass(HashMap.class); + verify(splitHtpClientKerberos)._post(connectionCaptor.capture(), entityCaptor.capture(), headersCaptor.capture()); + + assertThat(connectionCaptor.getValue().getURL().toString(), is(equalTo(new URL("https://kubernetesturl.com/split/api/testImpressions/bulk").toString()))); + } + + @Test(expected = IOException.class) + public void testPosttException() throws URISyntaxException, IOException { + HttpURLConnection mockHttpURLConnection = Mockito.mock(HttpURLConnection.class); + RequestDecorator decorator = new RequestDecorator(null); + Mockito.when(mockHttpURLConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_INTERNAL_ERROR); + + SplitHttpClientKerberosImpl splitHtpClientKerberos = SplitHttpClientKerberosImpl.create(decorator, "qwerty", metadata()); + SplitHttpResponse splitHttpResponse = splitHtpClientKerberos._post(mockHttpURLConnection, + Utils.toJsonEntity(Arrays.asList(new String[] { "A", "B", "C", "D" })), null); + + Assert.assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, (long) splitHttpResponse.statusCode()); + } + + private SDKMetadata metadata() { + return new SDKMetadata("java-1.2.3", "1.2.3.4", "someIP"); + } + +} From 2234a3c0a70e4830a6061b3ac13ef05a169d8735 Mon Sep 17 00:00:00 2001 From: Bilal Al Date: Tue, 13 Aug 2024 09:58:56 -0700 Subject: [PATCH 2/8] polish --- .../io/split/client/SplitClientConfig.java | 6 +++- .../service/SplitHttpClientKerberosImpl.java | 6 ++-- .../service/HttpSplitClientKerberosTest.java | 32 ++++++++++++++----- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/client/src/main/java/io/split/client/SplitClientConfig.java b/client/src/main/java/io/split/client/SplitClientConfig.java index 3d69a6283..43695d8da 100644 --- a/client/src/main/java/io/split/client/SplitClientConfig.java +++ b/client/src/main/java/io/split/client/SplitClientConfig.java @@ -10,8 +10,12 @@ import pluggable.CustomStorageWrapper; import java.io.IOException; -import java.util.*; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Properties; import java.util.concurrent.ThreadFactory; +import java.util.Locale; import java.io.InputStream; import static io.split.inputValidation.FlagSetsValidator.cleanup; diff --git a/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java b/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java index 11bd85305..3b69ec395 100644 --- a/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java +++ b/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java @@ -123,7 +123,7 @@ public synchronized SplitHttpResponse post(URI uri, HttpEntity entity, Map Date: Tue, 13 Aug 2024 10:12:10 -0700 Subject: [PATCH 3/8] polish --- .../java/io/split/service/SplitHttpClientKerberosImpl.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java b/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java index 3b69ec395..696c756ed 100644 --- a/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java +++ b/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java @@ -60,6 +60,8 @@ public synchronized SplitHttpResponse get(URI uri, FetchOptions options, Map Date: Tue, 13 Aug 2024 10:22:54 -0700 Subject: [PATCH 4/8] polish --- .../service/SplitHttpClientKerberosImpl.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java b/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java index 696c756ed..3536aa0a3 100644 --- a/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java +++ b/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java @@ -59,9 +59,9 @@ public synchronized SplitHttpResponse get(URI uri, FetchOptions options, Map Date: Tue, 13 Aug 2024 13:25:17 -0700 Subject: [PATCH 5/8] added enum for AuthScheme --- .../io/split/client/SplitClientConfig.java | 18 ++++++----------- .../io/split/client/SplitFactoryImpl.java | 3 ++- .../java/io/split/service/HttpAuthScheme.java | 5 +++++ .../service/SplitHttpClientKerberosImpl.java | 20 +++++++------------ .../split/client/SplitClientConfigTest.java | 18 +++-------------- .../io/split/client/SplitFactoryImplTest.java | 3 ++- .../service/HttpSplitClientKerberosTest.java | 16 +++++++-------- 7 files changed, 33 insertions(+), 50 deletions(-) create mode 100644 client/src/main/java/io/split/service/HttpAuthScheme.java diff --git a/client/src/main/java/io/split/client/SplitClientConfig.java b/client/src/main/java/io/split/client/SplitClientConfig.java index 43695d8da..2c305a133 100644 --- a/client/src/main/java/io/split/client/SplitClientConfig.java +++ b/client/src/main/java/io/split/client/SplitClientConfig.java @@ -6,6 +6,7 @@ import io.split.integrations.IntegrationsConfig; import io.split.storages.enums.OperationMode; import io.split.storages.enums.StorageMode; +import io.split.service.HttpAuthScheme; import org.apache.hc.core5.http.HttpHost; import pluggable.CustomStorageWrapper; @@ -92,7 +93,7 @@ public class SplitClientConfig { private final HashSet _flagSetsFilter; private final int _invalidSets; private final CustomHeaderDecorator _customHeaderDecorator; - private final String _authScheme; + private final HttpAuthScheme _authScheme; public static Builder builder() { @@ -151,7 +152,7 @@ private SplitClientConfig(String endpoint, HashSet flagSetsFilter, int invalidSets, CustomHeaderDecorator customHeaderDecorator, - String authScheme) { + HttpAuthScheme authScheme) { _endpoint = endpoint; _eventsEndpoint = eventsEndpoint; _featuresRefreshRate = pollForFeatureChangesEveryNSeconds; @@ -412,7 +413,7 @@ public int getInvalidSets() { public CustomHeaderDecorator customHeaderDecorator() { return _customHeaderDecorator; } - public String authScheme() { + public HttpAuthScheme authScheme() { return _authScheme; } @@ -473,7 +474,7 @@ public static final class Builder { private HashSet _flagSetsFilter = new HashSet<>(); private int _invalidSetsCount = 0; private CustomHeaderDecorator _customHeaderDecorator = null; - private String _authScheme = null; + private HttpAuthScheme _authScheme = null; public Builder() { } @@ -974,7 +975,7 @@ public Builder customHeaderDecorator(CustomHeaderDecorator customHeaderDecorator * @param authScheme * @return this builder */ - public Builder authScheme(String authScheme) { + public Builder authScheme(HttpAuthScheme authScheme) { _authScheme = authScheme; return this; } @@ -1087,13 +1088,6 @@ public SplitClientConfig build() { _storageMode = StorageMode.PLUGGABLE; } - if(_authScheme != null) { - if (!_authScheme.toLowerCase(Locale.ROOT).equals("kerberos")) { - throw new IllegalArgumentException("authScheme must be either null or `kerberos`."); - } - _authScheme = "kerberos"; - } - return new SplitClientConfig( _endpoint, _eventsEndpoint, diff --git a/client/src/main/java/io/split/client/SplitFactoryImpl.java b/client/src/main/java/io/split/client/SplitFactoryImpl.java index 0dc967304..68eeba672 100644 --- a/client/src/main/java/io/split/client/SplitFactoryImpl.java +++ b/client/src/main/java/io/split/client/SplitFactoryImpl.java @@ -57,6 +57,7 @@ import io.split.engine.segments.SegmentChangeFetcher; import io.split.engine.segments.SegmentSynchronizationTaskImp; import io.split.integrations.IntegrationsConfig; +import io.split.service.HttpAuthScheme; import io.split.service.SplitHttpClient; import io.split.service.SplitHttpClientImpl; import io.split.service.SplitHttpClientKerberosImpl; @@ -526,7 +527,7 @@ private static SplitHttpClient buildSplitHttpClient(String apiToken, SplitClient httpClientbuilder = setupProxy(httpClientbuilder, config); } - if (config.authScheme() != null) { + if (config.authScheme() == HttpAuthScheme.KERBEROS) { return SplitHttpClientKerberosImpl.create( requestDecorator, apiToken, diff --git a/client/src/main/java/io/split/service/HttpAuthScheme.java b/client/src/main/java/io/split/service/HttpAuthScheme.java new file mode 100644 index 000000000..1753f7369 --- /dev/null +++ b/client/src/main/java/io/split/service/HttpAuthScheme.java @@ -0,0 +1,5 @@ +package io.split.service; + +public enum HttpAuthScheme { + KERBEROS +} diff --git a/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java b/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java index 3536aa0a3..83f31ee74 100644 --- a/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java +++ b/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java @@ -23,7 +23,7 @@ public class SplitHttpClientKerberosImpl implements SplitHttpClient { - private static final Logger _log = LoggerFactory.getLogger(SplitHttpClient.class); + private static final Logger _log = LoggerFactory.getLogger(SplitHttpClientKerberosImpl.class); private static final String HEADER_CACHE_CONTROL_NAME = "Cache-Control"; private static final String HEADER_CACHE_CONTROL_VALUE = "no-cache"; private static final String HEADER_API_KEY = "Authorization"; @@ -54,7 +54,7 @@ public synchronized SplitHttpResponse get(URI uri, FetchOptions options, Map> additionalHeaders) { + public SplitHttpResponse doGet(HttpURLConnection getHttpURLConnection, FetchOptions options, Map> additionalHeaders) { InputStreamReader inputStreamReader = null; try { getHttpURLConnection.setRequestMethod("GET"); - setBasicHeaders(getHttpURLConnection); setAdditionalAndDecoratedHeaders(getHttpURLConnection, additionalHeaders); @@ -125,7 +124,7 @@ public synchronized SplitHttpResponse post(URI uri, HttpEntity entity, Map> additionalHeaders) - throws IOException { + Map> additionalHeaders) { try { postHttpURLConnection.setRequestMethod("POST"); setBasicHeaders(postHttpURLConnection); setAdditionalAndDecoratedHeaders(postHttpURLConnection, additionalHeaders); - if (postHttpURLConnection.getHeaderField("Accept-Encoding") == null) { - postHttpURLConnection.setRequestProperty("Accept-Encoding", "gzip"); - } + postHttpURLConnection.setRequestProperty("Accept-Encoding", "gzip"); postHttpURLConnection.setRequestProperty("Content-Type", "application/json"); _log.debug(String.format("Request Headers: %s", postHttpURLConnection.getRequestProperties())); @@ -198,7 +194,6 @@ private void setAdditionalAndDecoratedHeaders(HttpURLConnection urlConnection, M for (Header header : request.getHeaders()) { urlConnection.setRequestProperty(header.getName(), header.getValue()); } - request = null; } private Header[] getResponseHeaders(HttpURLConnection urlConnection) { @@ -211,7 +206,6 @@ private Header[] getResponseHeaders(HttpURLConnection urlConnection) { } } return responseHeaders.toArray(new Header[0]); - } @Override public void close() throws IOException { diff --git a/client/src/test/java/io/split/client/SplitClientConfigTest.java b/client/src/test/java/io/split/client/SplitClientConfigTest.java index d323ebe21..86b185419 100644 --- a/client/src/test/java/io/split/client/SplitClientConfigTest.java +++ b/client/src/test/java/io/split/client/SplitClientConfigTest.java @@ -6,6 +6,7 @@ import io.split.client.impressions.ImpressionsManager; import io.split.client.dtos.RequestContext; import io.split.integrations.IntegrationsConfig; +import io.split.service.HttpAuthScheme; import org.junit.Assert; import org.junit.Test; import org.mockito.Mockito; @@ -258,24 +259,11 @@ public Map> getHeaderOverrides(RequestContext context) { @Test public void checkExpectedAuthScheme() { SplitClientConfig cfg = SplitClientConfig.builder() - .authScheme("kerberos") + .authScheme(HttpAuthScheme.KERBEROS) .build(); - Assert.assertEquals("kerberos", cfg.authScheme()); + Assert.assertEquals(HttpAuthScheme.KERBEROS, cfg.authScheme()); cfg = SplitClientConfig.builder() - .authScheme("KERberos") - .build(); - Assert.assertEquals("kerberos", cfg.authScheme()); - - cfg = SplitClientConfig.builder() - .build(); - Assert.assertEquals(null, cfg.authScheme()); - } - - @Test(expected = IllegalArgumentException.class) - public void checkUnexpectedAuthScheme() { - SplitClientConfig cfg = SplitClientConfig.builder() - .authScheme("proxy") .build(); Assert.assertEquals(null, cfg.authScheme()); } diff --git a/client/src/test/java/io/split/client/SplitFactoryImplTest.java b/client/src/test/java/io/split/client/SplitFactoryImplTest.java index 00e9f626b..57441ced6 100644 --- a/client/src/test/java/io/split/client/SplitFactoryImplTest.java +++ b/client/src/test/java/io/split/client/SplitFactoryImplTest.java @@ -4,6 +4,7 @@ import io.split.client.utils.FileTypeEnum; import io.split.client.utils.SDKMetadata; import io.split.integrations.IntegrationsConfig; +import io.split.service.HttpAuthScheme; import io.split.service.SplitHttpClientKerberosImpl; import io.split.storages.enums.OperationMode; import io.split.storages.pluggable.domain.UserStorageWrapper; @@ -353,7 +354,7 @@ public void testLocalhosJsonInputStreamNullAndFileTypeNull() throws URISyntaxExc public void testFactoryKerberosInstance() throws URISyntaxException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { SplitClientConfig splitClientConfig = SplitClientConfig.builder() .setBlockUntilReadyTimeout(10000) - .authScheme("kerberos") + .authScheme(HttpAuthScheme.KERBEROS) .build(); SplitFactoryImpl splitFactory = new SplitFactoryImpl("asdf", splitClientConfig); diff --git a/client/src/test/java/io/split/service/HttpSplitClientKerberosTest.java b/client/src/test/java/io/split/service/HttpSplitClientKerberosTest.java index 74f958741..4f814c31d 100644 --- a/client/src/test/java/io/split/service/HttpSplitClientKerberosTest.java +++ b/client/src/test/java/io/split/service/HttpSplitClientKerberosTest.java @@ -53,7 +53,7 @@ public void testGetWithSpecialCharacters() throws URISyntaxException, IOExceptio Map> additionalHeaders = Collections.singletonMap("AdditionalHeader", Collections.singletonList("add")); - SplitHttpResponse splitHttpResponse = splitHtpClientKerberos._get(mockHttpURLConnection, + SplitHttpResponse splitHttpResponse = splitHtpClientKerberos.doGet(mockHttpURLConnection, new FetchOptions.Builder().cacheControlHeaders(true).build(), additionalHeaders); SplitChange change = Json.fromJson(splitHttpResponse.body(), SplitChange.class); @@ -84,7 +84,7 @@ public void testGetParameters() throws URISyntaxException, MalformedURLException ArgumentCaptor connectionCaptor = ArgumentCaptor.forClass(HttpURLConnection.class); ArgumentCaptor optionsCaptor = ArgumentCaptor.forClass(FetchOptions.class); ArgumentCaptor headersCaptor = ArgumentCaptor.forClass(HashMap.class); - verify(splitHtpClientKerberos)._get(connectionCaptor.capture(), optionsCaptor.capture(), headersCaptor.capture()); + verify(splitHtpClientKerberos).doGet(connectionCaptor.capture(), optionsCaptor.capture(), headersCaptor.capture()); assertThat(connectionCaptor.getValue().getRequestMethod(), is(equalTo("GET"))); assertThat(connectionCaptor.getValue().getURL().toString(), is(equalTo(new URL("https://api.split.io/splitChanges?since=1234567").toString()))); @@ -103,7 +103,7 @@ public void testGetError() throws URISyntaxException, IOException { when(mockHttpURLConnection.getInputStream()).thenReturn(stubInputStream); SplitHttpClientKerberosImpl splitHtpClientKerberos = SplitHttpClientKerberosImpl.create(decorator, "qwerty", metadata()); - SplitHttpResponse splitHttpResponse = splitHtpClientKerberos._get(mockHttpURLConnection, + SplitHttpResponse splitHttpResponse = splitHtpClientKerberos.doGet(mockHttpURLConnection, new FetchOptions.Builder().cacheControlHeaders(true).build(), null); Assert.assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, (long) splitHttpResponse.statusCode()); } @@ -120,7 +120,7 @@ public void testException() throws URISyntaxException, InvocationTargetException when(mockHttpURLConnection.getInputStream()).thenReturn(stubInputStream); SplitHttpClientKerberosImpl splitHtpClientKerberos = SplitHttpClientKerberosImpl.create(decorator, "qwerty", metadata()); - SplitHttpResponse splitHttpResponse = splitHtpClientKerberos._get(mockHttpURLConnection, + SplitHttpResponse splitHttpResponse = splitHtpClientKerberos.doGet(mockHttpURLConnection, new FetchOptions.Builder().cacheControlHeaders(true).build(), null); } @@ -149,7 +149,7 @@ public void testPost() throws URISyntaxException, IOException, ParseException { ByteArrayOutputStream mockOs = Mockito.mock( ByteArrayOutputStream.class); when(mockHttpURLConnection.getOutputStream()).thenReturn(mockOs); - SplitHttpResponse splitHttpResponse = splitHtpClientKerberos._post(mockHttpURLConnection, Utils.toJsonEntity(toSend), + SplitHttpResponse splitHttpResponse = splitHtpClientKerberos.doPost(mockHttpURLConnection, Utils.toJsonEntity(toSend), additionalHeaders); // Capture outgoing request and validate it @@ -176,7 +176,7 @@ public void testPotParameters() throws URISyntaxException, IOException { ArgumentCaptor connectionCaptor = ArgumentCaptor.forClass(HttpURLConnection.class); ArgumentCaptor entityCaptor = ArgumentCaptor.forClass(HttpEntity.class); ArgumentCaptor headersCaptor = ArgumentCaptor.forClass(HashMap.class); - verify(splitHtpClientKerberos)._post(connectionCaptor.capture(), entityCaptor.capture(), headersCaptor.capture()); + verify(splitHtpClientKerberos).doPost(connectionCaptor.capture(), entityCaptor.capture(), headersCaptor.capture()); assertThat(connectionCaptor.getValue().getURL().toString(), is(equalTo(new URL("https://kubernetesturl.com/split/api/testImpressions/bulk").toString()))); } @@ -190,7 +190,7 @@ public void testPosttError() throws URISyntaxException, IOException { when(mockHttpURLConnection.getOutputStream()).thenReturn(mockOs); SplitHttpClientKerberosImpl splitHtpClientKerberos = SplitHttpClientKerberosImpl.create(decorator, "qwerty", metadata()); - SplitHttpResponse splitHttpResponse = splitHtpClientKerberos._post(mockHttpURLConnection, + SplitHttpResponse splitHttpResponse = splitHtpClientKerberos.doPost(mockHttpURLConnection, Utils.toJsonEntity(Arrays.asList(new String[] { "A", "B", "C", "D" })), null); Assert.assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, (long) splitHttpResponse.statusCode()); @@ -203,7 +203,7 @@ public void testPosttException() throws URISyntaxException, IOException { Mockito.when(mockHttpURLConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); SplitHttpClientKerberosImpl splitHtpClientKerberos = SplitHttpClientKerberosImpl.create(decorator, "qwerty", metadata()); - SplitHttpResponse splitHttpResponse = splitHtpClientKerberos._post(mockHttpURLConnection, + SplitHttpResponse splitHttpResponse = splitHtpClientKerberos.doPost(mockHttpURLConnection, Utils.toJsonEntity(Arrays.asList(new String[] { "A", "B", "C", "D" })), null); } From 4a7079a3f638b5925e7b16bca5585e8899010633 Mon Sep 17 00:00:00 2001 From: Bilal Al Date: Wed, 14 Aug 2024 11:43:14 -0700 Subject: [PATCH 6/8] polish --- .../io/split/client/SplitClientConfig.java | 1 - .../service/SplitHttpClientKerberosImpl.java | 19 ++++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/client/src/main/java/io/split/client/SplitClientConfig.java b/client/src/main/java/io/split/client/SplitClientConfig.java index 2c305a133..ec4e49cf3 100644 --- a/client/src/main/java/io/split/client/SplitClientConfig.java +++ b/client/src/main/java/io/split/client/SplitClientConfig.java @@ -16,7 +16,6 @@ import java.util.List; import java.util.Properties; import java.util.concurrent.ThreadFactory; -import java.util.Locale; import java.io.InputStream; import static io.split.inputValidation.FlagSetsValidator.cleanup; diff --git a/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java b/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java index 83f31ee74..35dd16e2e 100644 --- a/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java +++ b/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java @@ -14,8 +14,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.*; -import java.net.*; +import java.io.InputStreamReader; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; +import java.net.HttpURLConnection; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; @@ -38,7 +42,7 @@ public class SplitHttpClientKerberosImpl implements SplitHttpClient { public static SplitHttpClientKerberosImpl create(RequestDecorator requestDecorator, String apikey, - SDKMetadata metadata) throws URISyntaxException { + SDKMetadata metadata) { return new SplitHttpClientKerberosImpl(requestDecorator, apikey, metadata); } @@ -99,10 +103,11 @@ public SplitHttpResponse doGet(HttpURLConnection getHttpURLConnection, FetchOpti inputStreamReader = new InputStreamReader(getHttpURLConnection.getInputStream()); BufferedReader br = new BufferedReader(inputStreamReader); String strCurrentLine; - String responseBody = new String(); + StringBuilder bld = new StringBuilder(); while ((strCurrentLine = br.readLine()) != null) { - responseBody = responseBody + strCurrentLine; + bld.append(strCurrentLine); } + String responseBody = bld.toString(); return new SplitHttpResponse(responseCode, statusMessage, responseBody, @@ -197,7 +202,7 @@ private void setAdditionalAndDecoratedHeaders(HttpURLConnection urlConnection, M } private Header[] getResponseHeaders(HttpURLConnection urlConnection) { - List responseHeaders = new ArrayList(); + List responseHeaders = new ArrayList<>(); Map> map = urlConnection.getHeaderFields(); for (Map.Entry> entry : map.entrySet()) { if (entry.getKey() != null) { @@ -209,6 +214,6 @@ private Header[] getResponseHeaders(HttpURLConnection urlConnection) { } @Override public void close() throws IOException { - + // Added for compatibility with HttpSplitClient, no action needed as URLConnection objects are closed. } } From 2ec4789b7e12a207a210a6fb39404ea9358ef34f Mon Sep 17 00:00:00 2001 From: Bilal Al Date: Wed, 14 Aug 2024 12:14:24 -0700 Subject: [PATCH 7/8] polish --- .../split/service/SplitHttpClientKerberosImpl.java | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java b/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java index 35dd16e2e..82dd9a35b 100644 --- a/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java +++ b/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java @@ -72,7 +72,6 @@ public synchronized SplitHttpResponse get(URI uri, FetchOptions options, Map> additionalHeaders) { - InputStreamReader inputStreamReader = null; try { getHttpURLConnection.setRequestMethod("GET"); setBasicHeaders(getHttpURLConnection); @@ -100,7 +99,7 @@ public SplitHttpResponse doGet(HttpURLConnection getHttpURLConnection, FetchOpti statusMessage = getHttpURLConnection.getResponseMessage(); } - inputStreamReader = new InputStreamReader(getHttpURLConnection.getInputStream()); + InputStreamReader inputStreamReader = new InputStreamReader(getHttpURLConnection.getInputStream()); BufferedReader br = new BufferedReader(inputStreamReader); String strCurrentLine; StringBuilder bld = new StringBuilder(); @@ -108,20 +107,13 @@ public SplitHttpResponse doGet(HttpURLConnection getHttpURLConnection, FetchOpti bld.append(strCurrentLine); } String responseBody = bld.toString(); + inputStreamReader.close(); return new SplitHttpResponse(responseCode, statusMessage, responseBody, getResponseHeaders(getHttpURLConnection)); } catch (Exception e) { throw new IllegalStateException(String.format("Problem in http get operation: %s", e), e); - } finally { - try { - if (inputStreamReader != null) { - inputStreamReader.close(); - } - } catch (Exception e) { - _log.error(String.format("Could not close HTTP Stream: %s", e), e); - } } } From 97bf31b8adde1b90b805ce850533688c191dfd29 Mon Sep 17 00:00:00 2001 From: Bilal Al Date: Wed, 14 Aug 2024 12:50:59 -0700 Subject: [PATCH 8/8] updated version --- client/pom.xml | 2 +- pluggable-storage/pom.xml | 2 +- pom.xml | 2 +- redis-wrapper/pom.xml | 2 +- testing/pom.xml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client/pom.xml b/client/pom.xml index b8d94bba7..6bd936d6c 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -5,7 +5,7 @@ io.split.client java-client-parent - 4.12.1 + 4.13.0-rc1 java-client jar diff --git a/pluggable-storage/pom.xml b/pluggable-storage/pom.xml index f643564f9..39128cb90 100644 --- a/pluggable-storage/pom.xml +++ b/pluggable-storage/pom.xml @@ -6,7 +6,7 @@ java-client-parent io.split.client - 4.12.1 + 4.13.0-rc1 2.1.0 diff --git a/pom.xml b/pom.xml index 3dc7d33f9..bf2f4cb01 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 io.split.client java-client-parent - 4.12.1 + 4.13.0-rc1 diff --git a/redis-wrapper/pom.xml b/redis-wrapper/pom.xml index a8ce195f5..e0a3c8380 100644 --- a/redis-wrapper/pom.xml +++ b/redis-wrapper/pom.xml @@ -6,7 +6,7 @@ java-client-parent io.split.client - 4.12.1 + 4.13.0-rc1 redis-wrapper 3.1.0 diff --git a/testing/pom.xml b/testing/pom.xml index 2240c94db..556d98afb 100644 --- a/testing/pom.xml +++ b/testing/pom.xml @@ -5,7 +5,7 @@ io.split.client java-client-parent - 4.12.1 + 4.13.0-rc1 java-client-testing jar