Skip to content

Commit e421434

Browse files
committed
update with last changes in development
2 parents 4908571 + 3a41831 commit e421434

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1449
-407
lines changed

CHANGES.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
4.12.0 (XXX XX, 2024)
2+
- Added support for injecting user-defined custom headers for all outgoing HTTP calls, typically useful for proxy authentication purposes.
3+
4+
4.11.1 (Feb 29, 2024)
5+
- Fixed deadlock in UniqueKeysTracker when sending Unique Keys.
6+
17
4.11.0 (Jan 9, 2024)
28
- Added impressionsListener method in the IntegrationConfig builder to set Sync or Async Listener execution.
39
- Fixed localhost to read files with yml ending.
@@ -6,7 +12,7 @@
612
- Added getTreatmentsByFlagSets without attributes.
713
- Fixed some issues for flag sets: Not logging a warning when using flag sets that don't contain cached feature flags.
814

9-
4.10.1 (Nov 9, 2023)
15+
4.10.1 (Nov 8, 2023)
1016
- Fixed handler for response http headers.
1117

1218
4.10.0 (Nov 2, 2023)

client/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<parent>
66
<groupId>io.split.client</groupId>
77
<artifactId>java-client-parent</artifactId>
8-
<version>4.11.0</version>
8+
<version>4.12.0-rc3</version>
99
</parent>
1010
<artifactId>java-client</artifactId>
1111
<packaging>jar</packaging>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package io.split.client;
2+
3+
import io.split.client.dtos.RequestContext;
4+
5+
import java.util.Map;
6+
import java.util.List;
7+
8+
public interface CustomHeaderDecorator
9+
{
10+
/**
11+
* Get the additional headers needed for all http operations
12+
* @return HashMap of addition headers
13+
*/
14+
Map<String, List<String>> getHeaderOverrides(RequestContext context);
15+
}

client/src/main/java/io/split/client/HttpSegmentChangeFetcher.java

Lines changed: 11 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,23 @@
22

33
import com.google.common.annotations.VisibleForTesting;
44
import io.split.client.dtos.SegmentChange;
5+
import io.split.client.dtos.SplitHttpResponse;
56
import io.split.client.utils.Json;
67
import io.split.client.utils.Utils;
78
import io.split.engine.common.FetchOptions;
89
import io.split.engine.segments.SegmentChangeFetcher;
10+
import io.split.service.SplitHttpClient;
911
import io.split.telemetry.domain.enums.HTTPLatenciesEnum;
1012
import io.split.telemetry.domain.enums.LastSynchronizationRecordsEnum;
1113
import io.split.telemetry.domain.enums.ResourceEnum;
1214
import io.split.telemetry.storage.TelemetryRuntimeProducer;
13-
import org.apache.hc.client5.http.classic.methods.HttpGet;
14-
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
15-
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
1615
import org.apache.hc.core5.http.HttpStatus;
17-
import org.apache.hc.core5.http.io.entity.EntityUtils;
1816
import org.apache.hc.core5.net.URIBuilder;
1917
import org.slf4j.Logger;
2018
import org.slf4j.LoggerFactory;
2119

2220
import java.net.URI;
2321
import java.net.URISyntaxException;
24-
import java.nio.charset.StandardCharsets;
2522

2623
import static com.google.common.base.Preconditions.checkNotNull;
2724

@@ -33,20 +30,17 @@ public final class HttpSegmentChangeFetcher implements SegmentChangeFetcher {
3330

3431
private static final String SINCE = "since";
3532
private static final String TILL = "till";
36-
private static final String PREFIX = "segmentChangeFetcher";
37-
private static final String CACHE_CONTROL_HEADER_NAME = "Cache-Control";
38-
private static final String CACHE_CONTROL_HEADER_VALUE = "no-cache";
3933

40-
private final CloseableHttpClient _client;
34+
private final SplitHttpClient _client;
4135
private final URI _target;
4236
private final TelemetryRuntimeProducer _telemetryRuntimeProducer;
4337

44-
public static HttpSegmentChangeFetcher create(CloseableHttpClient client, URI root, TelemetryRuntimeProducer telemetryRuntimeProducer)
38+
public static HttpSegmentChangeFetcher create(SplitHttpClient client, URI root, TelemetryRuntimeProducer telemetryRuntimeProducer)
4539
throws URISyntaxException {
4640
return new HttpSegmentChangeFetcher(client, Utils.appendPath(root, "api/segmentChanges"), telemetryRuntimeProducer);
4741
}
4842

49-
private HttpSegmentChangeFetcher(CloseableHttpClient client, URI uri, TelemetryRuntimeProducer telemetryRuntimeProducer) {
43+
private HttpSegmentChangeFetcher(SplitHttpClient client, URI uri, TelemetryRuntimeProducer telemetryRuntimeProducer) {
5044
_client = client;
5145
_target = uri;
5246
checkNotNull(_target);
@@ -57,8 +51,6 @@ private HttpSegmentChangeFetcher(CloseableHttpClient client, URI uri, TelemetryR
5751
public SegmentChange fetch(String segmentName, long since, FetchOptions options) {
5852
long start = System.currentTimeMillis();
5953

60-
CloseableHttpResponse response = null;
61-
6254
try {
6355
String path = _target.getPath() + "/" + segmentName;
6456
URIBuilder uriBuilder = new URIBuilder(_target)
@@ -69,45 +61,27 @@ public SegmentChange fetch(String segmentName, long since, FetchOptions options)
6961
}
7062

7163
URI uri = uriBuilder.build();
72-
HttpGet request = new HttpGet(uri);
73-
74-
if(options.cacheControlHeadersEnabled()) {
75-
request.setHeader(CACHE_CONTROL_HEADER_NAME, CACHE_CONTROL_HEADER_VALUE);
76-
}
77-
78-
response = _client.execute(request);
79-
80-
int statusCode = response.getCode();
8164

82-
if (_log.isDebugEnabled()) {
83-
_log.debug(String.format("[%s] %s. Status code: %s", request.getMethod(), uri.toURL(), statusCode));
84-
}
65+
SplitHttpResponse response = _client.get(uri, options, null);
8566

86-
if (statusCode < HttpStatus.SC_OK || statusCode >= HttpStatus.SC_MULTIPLE_CHOICES) {
87-
_telemetryRuntimeProducer.recordSyncError(ResourceEnum.SEGMENT_SYNC, statusCode);
88-
_log.error(String.format("Response status was: %s. Reason: %s", statusCode , response.getReasonPhrase()));
89-
if (statusCode == HttpStatus.SC_FORBIDDEN) {
67+
if (response.statusCode() < HttpStatus.SC_OK || response.statusCode() >= HttpStatus.SC_MULTIPLE_CHOICES) {
68+
_telemetryRuntimeProducer.recordSyncError(ResourceEnum.SEGMENT_SYNC, response.statusCode());
69+
if (response.statusCode() == HttpStatus.SC_FORBIDDEN) {
9070
_log.error("factory instantiation: you passed a client side type sdkKey, " +
9171
"please grab an sdk key from the Split user interface that is of type server side");
9272
}
9373
throw new IllegalStateException(String.format("Could not retrieve segment changes for %s, since %s; http return code %s",
94-
segmentName, since, statusCode));
74+
segmentName, since, response.statusCode()));
9575
}
96-
9776
_telemetryRuntimeProducer.recordSuccessfulSync(LastSynchronizationRecordsEnum.SEGMENTS, System.currentTimeMillis());
9877

99-
String json = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
100-
101-
return Json.fromJson(json, SegmentChange.class);
78+
return Json.fromJson(response.body(), SegmentChange.class);
10279
} catch (Exception e) {
10380
throw new IllegalStateException(String.format("Error occurred when trying to sync segment: %s, since: %s. Details: %s",
10481
segmentName, since, e), e);
10582
} finally {
10683
_telemetryRuntimeProducer.recordSyncLatency(HTTPLatenciesEnum.SEGMENTS, System.currentTimeMillis()-start);
107-
Utils.forceClose(response);
10884
}
109-
110-
11185
}
11286

11387
@VisibleForTesting

client/src/main/java/io/split/client/HttpSplitChangeFetcher.java

Lines changed: 14 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,23 @@
22

33
import com.google.common.annotations.VisibleForTesting;
44
import io.split.client.dtos.SplitChange;
5+
import io.split.client.dtos.SplitHttpResponse;
56
import io.split.client.exceptions.UriTooLongException;
67
import io.split.client.utils.Json;
78
import io.split.client.utils.Utils;
89
import io.split.engine.common.FetchOptions;
910
import io.split.engine.experiments.SplitChangeFetcher;
11+
import io.split.service.SplitHttpClient;
1012
import io.split.telemetry.domain.enums.HTTPLatenciesEnum;
1113
import io.split.telemetry.domain.enums.ResourceEnum;
1214
import io.split.telemetry.storage.TelemetryRuntimeProducer;
13-
import org.apache.hc.client5.http.classic.methods.HttpGet;
14-
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
15-
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
1615
import org.apache.hc.core5.http.HttpStatus;
17-
import org.apache.hc.core5.http.io.entity.EntityUtils;
1816
import org.apache.hc.core5.net.URIBuilder;
1917
import org.slf4j.Logger;
2018
import org.slf4j.LoggerFactory;
2119

2220
import java.net.URI;
2321
import java.net.URISyntaxException;
24-
import java.nio.charset.StandardCharsets;
2522

2623
import static com.google.common.base.Preconditions.checkNotNull;
2724

@@ -34,20 +31,16 @@ public final class HttpSplitChangeFetcher implements SplitChangeFetcher {
3431
private static final String SINCE = "since";
3532
private static final String TILL = "till";
3633
private static final String SETS = "sets";
37-
38-
private static final String HEADER_CACHE_CONTROL_NAME = "Cache-Control";
39-
private static final String HEADER_CACHE_CONTROL_VALUE = "no-cache";
40-
41-
private final CloseableHttpClient _client;
34+
private final SplitHttpClient _client;
4235
private final URI _target;
4336
private final TelemetryRuntimeProducer _telemetryRuntimeProducer;
4437

45-
public static HttpSplitChangeFetcher create(CloseableHttpClient client, URI root, TelemetryRuntimeProducer telemetryRuntimeProducer)
38+
public static HttpSplitChangeFetcher create(SplitHttpClient client, URI root, TelemetryRuntimeProducer telemetryRuntimeProducer)
4639
throws URISyntaxException {
4740
return new HttpSplitChangeFetcher(client, Utils.appendPath(root, "api/splitChanges"), telemetryRuntimeProducer);
4841
}
4942

50-
private HttpSplitChangeFetcher(CloseableHttpClient client, URI uri, TelemetryRuntimeProducer telemetryRuntimeProducer) {
43+
private HttpSplitChangeFetcher(SplitHttpClient client, URI uri, TelemetryRuntimeProducer telemetryRuntimeProducer) {
5144
_client = client;
5245
_target = uri;
5346
checkNotNull(_target);
@@ -64,8 +57,6 @@ public SplitChange fetch(long since, FetchOptions options) {
6457

6558
long start = System.currentTimeMillis();
6659

67-
CloseableHttpResponse response = null;
68-
6960
try {
7061
URIBuilder uriBuilder = new URIBuilder(_target).addParameter(SINCE, "" + since);
7162
if (options.hasCustomCN()) {
@@ -75,38 +66,24 @@ public SplitChange fetch(long since, FetchOptions options) {
7566
uriBuilder.addParameter(SETS, "" + options.flagSetsFilter());
7667
}
7768
URI uri = uriBuilder.build();
69+
SplitHttpResponse response = _client.get(uri, options, null);
7870

79-
HttpGet request = new HttpGet(uri);
80-
if(options.cacheControlHeadersEnabled()) {
81-
request.setHeader(HEADER_CACHE_CONTROL_NAME, HEADER_CACHE_CONTROL_VALUE);
82-
}
83-
84-
response = _client.execute(request);
85-
86-
int statusCode = response.getCode();
87-
88-
if (_log.isDebugEnabled()) {
89-
_log.debug(String.format("[%s] %s. Status code: %s", request.getMethod(), uri.toURL(), statusCode));
90-
}
91-
92-
if (statusCode < HttpStatus.SC_OK || statusCode >= HttpStatus.SC_MULTIPLE_CHOICES) {
93-
_telemetryRuntimeProducer.recordSyncError(ResourceEnum.SPLIT_SYNC, statusCode);
94-
if (statusCode == HttpStatus.SC_REQUEST_URI_TOO_LONG) {
71+
if (response.statusCode() < HttpStatus.SC_OK || response.statusCode() >= HttpStatus.SC_MULTIPLE_CHOICES) {
72+
if (response.statusCode() == HttpStatus.SC_REQUEST_URI_TOO_LONG) {
9573
_log.error("The amount of flag sets provided are big causing uri length error.");
96-
throw new UriTooLongException(String.format("Status code: %s. Message: %s", statusCode, response.getReasonPhrase()));
74+
throw new UriTooLongException(String.format("Status code: %s. Message: %s", response.statusCode(), response.statusMessage()));
9775
}
98-
_log.warn(String.format("Response status was: %s. Reason: %s", statusCode , response.getReasonPhrase()));
99-
throw new IllegalStateException(String.format("Could not retrieve splitChanges since %s; http return code %s", since, statusCode));
76+
_telemetryRuntimeProducer.recordSyncError(ResourceEnum.SPLIT_SYNC, response.statusCode());
77+
throw new IllegalStateException(
78+
String.format("Could not retrieve splitChanges since %s; http return code %s", since, response.statusCode())
79+
);
10080
}
10181

102-
String json = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
103-
104-
return Json.fromJson(json, SplitChange.class);
82+
return Json.fromJson(response.body(), SplitChange.class);
10583
} catch (Exception e) {
10684
throw new IllegalStateException(String.format("Problem fetching splitChanges since %s: %s", since, e), e);
10785
} finally {
10886
_telemetryRuntimeProducer.recordSyncLatency(HTTPLatenciesEnum.SPLITS, System.currentTimeMillis()-start);
109-
Utils.forceClose(response);
11087
}
11188
}
11289

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package io.split.client;
2+
3+
import io.split.client.CustomHeaderDecorator;
4+
import io.split.client.dtos.RequestContext;
5+
6+
import java.util.HashMap;
7+
import java.util.List;
8+
import java.util.Map;
9+
10+
class NoOpHeaderDecorator implements CustomHeaderDecorator {
11+
public NoOpHeaderDecorator() {
12+
}
13+
14+
@Override
15+
public Map<String, List<String>> getHeaderOverrides(RequestContext context) {
16+
return new HashMap<>();
17+
}
18+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package io.split.client;
2+
3+
import io.split.client.dtos.RequestContext;
4+
5+
import org.apache.hc.core5.http.HttpRequest;
6+
import org.apache.hc.core5.http.Header;
7+
8+
import java.util.HashSet;
9+
import java.util.HashMap;
10+
import java.util.Map;
11+
import java.util.Arrays;
12+
import java.util.ArrayList;
13+
import java.util.Set;
14+
import java.util.List;
15+
16+
public final class RequestDecorator {
17+
CustomHeaderDecorator _headerDecorator;
18+
19+
private static final Set<String> forbiddenHeaders = new HashSet<>(Arrays.asList(
20+
"splitsdkversion",
21+
"splitmachineip",
22+
"splitmachinename",
23+
"splitimpressionsmode",
24+
"host",
25+
"referrer",
26+
"content-type",
27+
"content-length",
28+
"content-encoding",
29+
"accept",
30+
"keep-alive",
31+
"x-fastly-debug"));
32+
33+
public RequestDecorator(CustomHeaderDecorator headerDecorator) {
34+
_headerDecorator = (headerDecorator == null)
35+
? new NoOpHeaderDecorator()
36+
: headerDecorator;
37+
}
38+
39+
public HttpRequest decorateHeaders(HttpRequest request) {
40+
try {
41+
Map<String, List<String>> headers = _headerDecorator
42+
.getHeaderOverrides(new RequestContext(convertToMap(request.getHeaders())));
43+
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
44+
if (isHeaderAllowed(entry.getKey())) {
45+
List<String> values = entry.getValue();
46+
for (int i = 0; i < values.size(); i++) {
47+
if (i == 0) {
48+
request.setHeader(entry.getKey(), values.get(i));
49+
} else {
50+
request.addHeader(entry.getKey(), values.get(i));
51+
}
52+
}
53+
}
54+
}
55+
} catch (Exception e) {
56+
throw new IllegalArgumentException(
57+
String.format("Problem adding custom headers to request decorator: %s", e), e);
58+
}
59+
60+
return request;
61+
}
62+
63+
private boolean isHeaderAllowed(String headerName) {
64+
return !forbiddenHeaders.contains(headerName.toLowerCase());
65+
}
66+
67+
private Map<String, List<String>> convertToMap(Header[] to_convert) {
68+
Map<String, List<String>> to_return = new HashMap<String, List<String>>();
69+
for (Integer i = 0; i < to_convert.length; i++) {
70+
if (!to_return.containsKey(to_convert[i].getName())) {
71+
to_return.put(to_convert[i].getName(), new ArrayList<String>());
72+
}
73+
to_return.get(to_convert[i].getName()).add(to_convert[i].getValue());
74+
}
75+
return to_return;
76+
}
77+
}

0 commit comments

Comments
 (0)