Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ private HttpSegmentChangeFetcher(SplitHttpClient client, URI uri, TelemetryRunti
public SegmentChange fetch(String segmentName, long since, FetchOptions options) {
long start = System.currentTimeMillis();

SplitHttpResponse response = null;
SplitHttpResponse response;

try {
String path = _target.getPath() + "/" + segmentName;
Expand All @@ -65,16 +65,15 @@ public SegmentChange fetch(String segmentName, long since, FetchOptions options)
URI uri = uriBuilder.build();

response = _client.get(uri, options);
int statusCode = response.statusCode;

if (statusCode < HttpStatus.SC_OK || statusCode >= HttpStatus.SC_MULTIPLE_CHOICES) {
_telemetryRuntimeProducer.recordSyncError(ResourceEnum.SEGMENT_SYNC, statusCode);
if (statusCode == HttpStatus.SC_FORBIDDEN) {
if (response.statusCode < HttpStatus.SC_OK || response.statusCode >= HttpStatus.SC_MULTIPLE_CHOICES) {
_telemetryRuntimeProducer.recordSyncError(ResourceEnum.SEGMENT_SYNC, response.statusCode);
if (response.statusCode == HttpStatus.SC_FORBIDDEN) {
_log.error("factory instantiation: you passed a client side type sdkKey, " +
"please grab an sdk key from the Split user interface that is of type server side");
}
throw new IllegalStateException(String.format("Could not retrieve segment changes for %s, since %s; http return code %s",
segmentName, since, statusCode));
segmentName, since, response.statusCode));
}
_telemetryRuntimeProducer.recordSuccessfulSync(LastSynchronizationRecordsEnum.SEGMENTS, System.currentTimeMillis());

Expand All @@ -85,8 +84,6 @@ public SegmentChange fetch(String segmentName, long since, FetchOptions options)
} finally {
_telemetryRuntimeProducer.recordSyncLatency(HTTPLatenciesEnum.SEGMENTS, System.currentTimeMillis()-start);
}


}

@VisibleForTesting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,15 @@ public SplitChange fetch(long since, FetchOptions options) {
URI uri = uriBuilder.build();
response = _client.get(uri, options);

int statusCode = response.statusCode;

if (statusCode < HttpStatus.SC_OK || statusCode >= HttpStatus.SC_MULTIPLE_CHOICES) {
if (statusCode == HttpStatus.SC_REQUEST_URI_TOO_LONG) {
if (response.statusCode < HttpStatus.SC_OK || response.statusCode >= HttpStatus.SC_MULTIPLE_CHOICES) {
if (response.statusCode == HttpStatus.SC_REQUEST_URI_TOO_LONG) {
_log.error("The amount of flag sets provided are big causing uri length error.");
throw new UriTooLongException(String.format("Status code: %s. Message: %s", statusCode, response.statusMessage));
throw new UriTooLongException(String.format("Status code: %s. Message: %s", response.statusCode, response.statusMessage));
}
_telemetryRuntimeProducer.recordSyncError(ResourceEnum.SPLIT_SYNC, statusCode);
throw new IllegalStateException(String.format("Could not retrieve splitChanges since %s; http return code %s", since, statusCode));
_telemetryRuntimeProducer.recordSyncError(ResourceEnum.SPLIT_SYNC, response.statusCode);
throw new IllegalStateException(
String.format("Could not retrieve splitChanges since %s; http return code %s", since, response.statusCode)
);
}

return Json.fromJson(response.body, SplitChange.class);
Expand Down
26 changes: 13 additions & 13 deletions client/src/main/java/io/split/client/RequestDecorator.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ public final class RequestDecorator {
UserCustomHeaderDecorator _headerDecorator;

private static final Set<String> forbiddenHeaders = new HashSet<>(Arrays.asList(
"SplitSDKVersion",
"SplitMachineIp",
"SplitMachineName",
"SplitImpressionsMode",
"Host",
"Referrer",
"Content-Type",
"Content-Length",
"Content-Encoding",
"Accept",
"Keep-Alive",
"X-Fastly-Debug"
"splitsdkversion",
"splitmachineip",
"splitmachinename",
"splitimpressionsmode",
"host",
"referrer",
"content-type",
"content-length",
"content-encoding",
"accept",
"keep-alive",
"x-fastly-debug"
));

public RequestDecorator(UserCustomHeaderDecorator headerDecorator) {
Expand All @@ -55,6 +55,6 @@ public HttpUriRequestBase decorateHeaders(HttpUriRequestBase request) {
}

private boolean isHeaderAllowed(String headerName) {
return !forbiddenHeaders.contains(headerName);
return !forbiddenHeaders.contains(headerName.toLowerCase());
}
}
12 changes: 4 additions & 8 deletions client/src/main/java/io/split/client/SplitFactoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ public class SplitFactoryImpl implements SplitFactory {
private final SplitSynchronizationTask _splitSynchronizationTask;
private final EventsTask _eventsTask;
private final SyncManager _syncManager;
private final CloseableHttpClient _httpclient;
private final SplitHttpClient _splitHttpClient;
private final UserStorageWrapper _userStorageWrapper;
private final ImpressionsSender _impressionsSender;
Expand Down Expand Up @@ -186,9 +185,7 @@ public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyn
_gates = new SDKReadinessGates();

// HttpClient
_httpclient = buildHttpClient(apiToken, config, _sdkMetadata);
UserCustomHeaderDecorator _userCustomHeaderDecorator = config.userCustomHeaderDecorator();
_splitHttpClient = SplitHttpClientImpl.create(_httpclient, new RequestDecorator(_userCustomHeaderDecorator));
_splitHttpClient = buildSplitHttpClient(apiToken, config, _sdkMetadata);

// Roots
_rootTarget = URI.create(config.endpoint());
Expand Down Expand Up @@ -279,7 +276,6 @@ protected SplitFactoryImpl(String apiToken, SplitClientConfig config, CustomStor
_splitFetcher = null;
_splitSynchronizationTask = null;
_eventsTask = null;
_httpclient = null;
_splitHttpClient = null;
_rootTarget = null;
_eventsRootTarget = null;
Expand Down Expand Up @@ -361,7 +357,6 @@ protected SplitFactoryImpl(SplitClientConfig config) {
_telemetrySynchronizer = null;
_telemetrySyncTask = null;
_eventsTask = null;
_httpclient = null;
_splitHttpClient = null;
_impressionsSender = null;
_rootTarget = null;
Expand Down Expand Up @@ -478,7 +473,8 @@ public boolean isDestroyed() {
return isTerminated;
}

private static CloseableHttpClient buildHttpClient(String apiToken, SplitClientConfig config, SDKMetadata sdkMetadata) {
private static SplitHttpClient buildSplitHttpClient(String apiToken, SplitClientConfig config, SDKMetadata sdkMetadata)
throws URISyntaxException {
SSLConnectionSocketFactory sslSocketFactory = SSLConnectionSocketFactoryBuilder.create()
.setSslContext(SSLContexts.createSystemDefault())
.setTlsVersions(TLS.V_1_1, TLS.V_1_2)
Expand Down Expand Up @@ -512,7 +508,7 @@ private static CloseableHttpClient buildHttpClient(String apiToken, SplitClientC
httpClientbuilder = setupProxy(httpClientbuilder, config);
}

return httpClientbuilder.build();
return SplitHttpClientImpl.create(httpClientbuilder.build(), new RequestDecorator(config.userCustomHeaderDecorator()));
}

private static CloseableHttpClient buildSSEdHttpClient(String apiToken, SplitClientConfig config, SDKMetadata sdkMetadata) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,8 @@ public void postImpressionsBulk(List<TestImpressions> impressions) {
additionalHeader.put(IMPRESSIONS_MODE_HEADER, _mode.toString());
response = _client.post(_impressionBulkTarget, entity, additionalHeader);

int status = response.statusCode;

if (status < HttpStatus.SC_OK || status >= HttpStatus.SC_MULTIPLE_CHOICES) {
_telemetryRuntimeProducer.recordSyncError(ResourceEnum.IMPRESSION_SYNC, status);
if (response.statusCode < HttpStatus.SC_OK || response.statusCode >= HttpStatus.SC_MULTIPLE_CHOICES) {
_telemetryRuntimeProducer.recordSyncError(ResourceEnum.IMPRESSION_SYNC, response.statusCode);
}
_telemetryRuntimeProducer.recordSuccessfulSync(LastSynchronizationRecordsEnum.IMPRESSIONS, System.currentTimeMillis());

Expand All @@ -98,9 +96,8 @@ public void postCounters(HashMap<ImpressionCounter.Key, Integer> raw) {
Utils.toJsonEntity(ImpressionCount.fromImpressionCounterData(raw)),
null);

int status = response.statusCode;
if (status < HttpStatus.SC_OK || status >= HttpStatus.SC_MULTIPLE_CHOICES) {
_telemetryRuntimeProducer.recordSyncError(ResourceEnum.IMPRESSION_COUNT_SYNC, status);
if (response.statusCode < HttpStatus.SC_OK || response.statusCode >= HttpStatus.SC_MULTIPLE_CHOICES) {
_telemetryRuntimeProducer.recordSyncError(ResourceEnum.IMPRESSION_COUNT_SYNC, response.statusCode);
}
_telemetryRuntimeProducer.recordSyncLatency(HTTPLatenciesEnum.IMPRESSIONS_COUNT, System.currentTimeMillis() - initTime);
_telemetryRuntimeProducer.recordSuccessfulSync(LastSynchronizationRecordsEnum.IMPRESSIONS_COUNT, System.currentTimeMillis());
Expand Down
13 changes: 2 additions & 11 deletions client/src/main/java/io/split/service/HttpPostImp.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import org.apache.hc.core5.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hc.client5.http.classic.methods.HttpPost;

import java.net.URI;

Expand All @@ -28,18 +27,10 @@ public void post(URI uri, Object object, String posted, HttpParamsWrapper httpPa
long initTime = System.currentTimeMillis();
HttpEntity entity = Utils.toJsonEntity(object);

HttpPost request = new HttpPost(uri);
request.setEntity(entity);

if (_logger.isDebugEnabled()) {
_logger.debug(String.format("[%s] %s", request.getMethod(), uri));
}

try {
SplitHttpResponse response = _client.post(uri, entity, null);
int status = response.statusCode;
if (status < HttpStatus.SC_OK || status >= HttpStatus.SC_MULTIPLE_CHOICES) {
_telemetryRuntimeProducer.recordSyncError(httpParamsWrapper.getResourceEnum(), status);
if (response.statusCode < HttpStatus.SC_OK || response.statusCode >= HttpStatus.SC_MULTIPLE_CHOICES) {
_telemetryRuntimeProducer.recordSyncError(httpParamsWrapper.getResourceEnum(), response.statusCode);
return;
}
_telemetryRuntimeProducer.recordSyncLatency(httpParamsWrapper.getHttpLatenciesEnum(), System.currentTimeMillis() - initTime);
Expand Down
10 changes: 4 additions & 6 deletions client/src/main/java/io/split/service/SplitHttpClientImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,17 @@ public SplitHttpResponse get(URI uri, FetchOptions options) {

response = _client.execute(request);

int statusCode = response.getCode();

if (_log.isDebugEnabled()) {
_log.debug(String.format("[%s] %s. Status code: %s", request.getMethod(), uri.toURL(), statusCode));
_log.debug(String.format("[%s] %s. Status code: %s", request.getMethod(), uri.toURL(), response.getCode()));
}

SplitHttpResponse httpResponse = new SplitHttpResponse();
httpResponse.statusMessage = "";
if (statusCode < HttpStatus.SC_OK || statusCode >= HttpStatus.SC_MULTIPLE_CHOICES) {
_log.warn(String.format("Response status was: %s. Reason: %s", statusCode , response.getReasonPhrase()));
if (response.getCode() < HttpStatus.SC_OK || response.getCode() >= HttpStatus.SC_MULTIPLE_CHOICES) {
_log.warn(String.format("Response status was: %s. Reason: %s", response.getCode() , response.getReasonPhrase()));
httpResponse.statusMessage = response.getReasonPhrase();
}
httpResponse.statusCode = statusCode;
httpResponse.statusCode = response.getCode();
httpResponse.body = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
return httpResponse;
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,26 @@ public void testFetcherWithCDNBypassOption() throws IOException, URISyntaxExcept
Assert.assertFalse(captured.get(1).getUri().toString().contains("till="));
}

@Test(expected = IllegalStateException.class)
public void testFetcherWithError() throws IOException, URISyntaxException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
URI rootTarget = URI.create("https://api.split.io");

HttpEntity entityMock = Mockito.mock(HttpEntity.class);
when(entityMock.getContent()).thenReturn(new StringBufferInputStream("{\"till\": 1}"));
ClassicHttpResponse response = Mockito.mock(ClassicHttpResponse.class);
when(response.getCode()).thenReturn(400);
when(response.getEntity()).thenReturn(entityMock);
when(response.getHeaders()).thenReturn(new Header[0]);

ArgumentCaptor<ClassicHttpRequest> requestCaptor = ArgumentCaptor.forClass(ClassicHttpRequest.class);
CloseableHttpClient httpClientMock = Mockito.mock(CloseableHttpClient.class);
SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClientMock, new RequestDecorator(null));

when(httpClientMock.execute(requestCaptor.capture())).thenReturn(TestHelper.classicResponseToCloseableMock(response));

Metrics.NoopMetrics metrics = new Metrics.NoopMetrics();
HttpSegmentChangeFetcher fetcher = HttpSegmentChangeFetcher.create(splitHtpClient, rootTarget, Mockito.mock(TelemetryStorage.class));

fetcher.fetch("someSegment", -1, new FetchOptions.Builder().build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,9 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.sql.Array;
import java.util.*;
import java.util.stream.Collectors;

import static org.mockito.Mockito.when;

Expand Down Expand Up @@ -143,4 +142,30 @@ public void testRandomNumberGeneration() throws URISyntaxException {

Assert.assertTrue(seen.size() >= (total * 0.9999));
}

@Test(expected = IllegalStateException.class)
public void testURLTooLong() throws IOException, URISyntaxException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
URI rootTarget = URI.create("https://api.split.io");

HttpEntity entityMock = Mockito.mock(HttpEntity.class);
when(entityMock.getContent()).thenReturn(new ByteArrayInputStream("{\"till\": 1}".getBytes(StandardCharsets.UTF_8)));
ClassicHttpResponse response = Mockito.mock(ClassicHttpResponse.class);
when(response.getCode()).thenReturn(414);
when(response.getEntity()).thenReturn(entityMock);
when(response.getHeaders()).thenReturn(new Header[0]);
CloseableHttpClient httpClientMock = Mockito.mock(CloseableHttpClient.class);
ArgumentCaptor<ClassicHttpRequest> requestCaptor = ArgumentCaptor.forClass(ClassicHttpRequest.class);
when(httpClientMock.execute(requestCaptor.capture())).thenReturn(TestHelper.classicResponseToCloseableMock(response));

SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClientMock, new RequestDecorator(null));
HttpSplitChangeFetcher fetcher = HttpSplitChangeFetcher.create(splitHtpClient, rootTarget, Mockito.mock(TelemetryRuntimeProducer.class));
List<String> sets = new ArrayList<String>();
for (Integer i=0; i<100; i++) {
sets.add("set" + i.toString());
}
String result = sets.stream()
.map(n -> String.valueOf(n))
.collect(Collectors.joining(",", "", ""));
fetcher.fetch(-1, new FetchOptions.Builder().flagSetsFilter(result).cacheControlHeaders(false).build());
}
}
12 changes: 12 additions & 0 deletions client/src/test/java/io/split/client/RequestDecoratorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,18 @@ public Map<String, String> getHeaderOverrides() {
{{
put("first", "1");
put("SplitSDKVersion", "2.4");
put("SplitMachineip", "xx");
put("splitMachineName", "xx");
put("splitimpressionsmode", "xx");
put("HOST", "xx");
put("referrer", "xx");
put("content-type", "xx");
put("content-length", "xx");
put("content-encoding", "xx");
put("ACCEPT", "xx");
put("keep-alive", "xx");
put("x-fastly-debug", "xx");

}};
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
package io.split.client.events;

import io.split.TestHelper;
import io.split.client.RequestDecorator;
import io.split.client.dtos.Event;
import io.split.service.SplitHttpClient;
import io.split.service.SplitHttpClientImpl;
import io.split.telemetry.storage.TelemetryRuntimeProducer;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.core5.http.HttpStatus;
import org.jetbrains.annotations.NotNull;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;

public class EventsSenderTest {

Expand Down Expand Up @@ -48,4 +55,13 @@ public void testCustomURLAppendingPathNoBackslash() throws URISyntaxException {
EventsSender fetcher = EventsSender.create(SPLIT_HTTP_CLIENT, rootTarget, TELEMETRY_RUNTIME_CONSUMER);
Assert.assertEquals("https://kubernetesturl.com/split/api/events/bulk", fetcher.getBulkEndpoint().toString());
}
@Test
public void testHttpError() throws URISyntaxException, IOException, InvocationTargetException, IllegalAccessException, NoSuchMethodException {
URI rootTarget = URI.create("https://kubernetesturl.com/split");
CloseableHttpClient httpClient = TestHelper.mockHttpClient("", HttpStatus.SC_BAD_REQUEST);
SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClient, new RequestDecorator(null));
EventsSender sender = EventsSender.create(splitHtpClient, rootTarget, TELEMETRY_RUNTIME_CONSUMER);
// should not raise exception
sender.sendEvents(new ArrayList<>());
}
}
Loading