Skip to content

Commit fa2b6a7

Browse files
committed
re-add request decorator
1 parent 2299e38 commit fa2b6a7

File tree

9 files changed

+163
-105
lines changed

9 files changed

+163
-105
lines changed

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

Lines changed: 7 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,12 @@
22

33
import io.split.client.dtos.RequestContext;
44

5-
import org.apache.hc.core5.http.HttpRequest;
6-
import org.apache.hc.core5.http.Header;
75

86
import java.util.HashSet;
9-
import java.util.HashMap;
107
import java.util.Map;
118
import java.util.Arrays;
12-
import java.util.ArrayList;
139
import java.util.Set;
14-
import java.util.List;
10+
import java.util.stream.Collectors;
1511

1612
public final class RequestDecorator {
1713
CustomHeaderDecorator _headerDecorator;
@@ -36,42 +32,16 @@ public RequestDecorator(CustomHeaderDecorator headerDecorator) {
3632
: headerDecorator;
3733
}
3834

39-
public HttpRequest decorateHeaders(HttpRequest request) {
35+
public RequestContext decorateHeaders(RequestContext request) {
4036
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-
}
37+
return new RequestContext(_headerDecorator.getHeaderOverrides(request)
38+
.entrySet()
39+
.stream()
40+
.filter(e -> !forbiddenHeaders.contains(e.getKey()))
41+
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
5542
} catch (Exception e) {
5643
throw new IllegalArgumentException(
5744
String.format("Problem adding custom headers to request decorator: %s", e), e);
5845
}
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;
7646
}
7747
}

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,13 +188,12 @@ public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyn
188188
// SDKReadinessGates
189189
_gates = new SDKReadinessGates();
190190

191+
RequestDecorator decorator = new RequestDecorator(config.customHeaderDecorator());
191192
// HttpClient
192-
_requestDecorator = new RequestDecorator(config.customHeaderDecorator());
193193
if (config.alternativeHTTPModule() == null) {
194-
_splitHttpClient = buildSplitHttpClient(apiToken, config, _sdkMetadata, _requestDecorator);
194+
_splitHttpClient = buildSplitHttpClient(apiToken, config, _sdkMetadata, decorator);
195195
} else {
196-
_splitHttpClient = config.alternativeHTTPModule().createClient(apiToken, _sdkMetadata); // ,
197-
// _requestDecorator);
196+
_splitHttpClient = config.alternativeHTTPModule().createClient(apiToken, _sdkMetadata, decorator);
198197
}
199198

200199
// Roots
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package io.split.client.utils;
2+
3+
import java.util.ArrayList;
4+
import java.util.HashMap;
5+
import java.util.List;
6+
import java.util.Map;
7+
8+
import org.apache.hc.core5.http.Header;
9+
import org.apache.hc.core5.http.HttpRequest;
10+
11+
import io.split.client.RequestDecorator;
12+
import io.split.client.dtos.RequestContext;
13+
14+
public class ApacheRequestDecorator {
15+
16+
public static HttpRequest decorate(HttpRequest request, RequestDecorator decorator) {
17+
18+
RequestContext ctx = new RequestContext(convertToMap(request.getHeaders()));
19+
for (Map.Entry<String, List<String>> entry : decorator.decorateHeaders(ctx).headers().entrySet()) {
20+
List<String> values = entry.getValue();
21+
for (int i = 0; i < values.size(); i++) {
22+
if (i == 0) {
23+
request.setHeader(entry.getKey(), values.get(i));
24+
} else {
25+
request.addHeader(entry.getKey(), values.get(i));
26+
}
27+
}
28+
}
29+
30+
return request;
31+
}
32+
33+
private static Map<String, List<String>> convertToMap(Header[] to_convert) {
34+
Map<String, List<String>> to_return = new HashMap<String, List<String>>();
35+
for (Integer i = 0; i < to_convert.length; i++) {
36+
if (!to_return.containsKey(to_convert[i].getName())) {
37+
to_return.put(to_convert[i].getName(), new ArrayList<String>());
38+
}
39+
to_return.get(to_convert[i].getName()).add(to_convert[i].getValue());
40+
}
41+
return to_return;
42+
}
43+
}

client/src/main/java/io/split/engine/sse/client/SSEClient.java

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.google.common.base.Strings;
44
import io.split.client.RequestDecorator;
5+
import io.split.client.utils.ApacheRequestDecorator;
56
import io.split.telemetry.domain.StreamingEvent;
67
import io.split.telemetry.domain.enums.StreamEventsEnum;
78
import io.split.telemetry.storage.TelemetryRuntimeProducer;
@@ -64,11 +65,11 @@ private enum ConnectionState {
6465
private final TelemetryRuntimeProducer _telemetryRuntimeProducer;
6566

6667
public SSEClient(Function<RawEvent, Void> eventCallback,
67-
Function<StatusMessage, Void> statusCallback,
68-
CloseableHttpClient client,
69-
TelemetryRuntimeProducer telemetryRuntimeProducer,
70-
ThreadFactory threadFactory,
71-
RequestDecorator requestDecorator) {
68+
Function<StatusMessage, Void> statusCallback,
69+
CloseableHttpClient client,
70+
TelemetryRuntimeProducer telemetryRuntimeProducer,
71+
ThreadFactory threadFactory,
72+
RequestDecorator requestDecorator) {
7273
_eventCallback = eventCallback;
7374
_statusCallback = statusCallback;
7475
_client = client;
@@ -96,7 +97,7 @@ public boolean open(URI uri) {
9697
}
9798
} catch (InterruptedException e) {
9899
Thread.currentThread().interrupt();
99-
if(e.getMessage() == null){
100+
if (e.getMessage() == null) {
100101
_log.info("The thread was interrupted while opening SSEClient");
101102
return false;
102103
}
@@ -152,31 +153,41 @@ private void connectAndLoop(URI uri, CountDownLatch signal) {
152153
_log.debug(exc.getMessage());
153154
if (SOCKET_CLOSED_MESSAGE.equals(exc.getMessage())) { // Connection closed by us
154155
_statusCallback.apply(StatusMessage.FORCED_STOP);
155-
_telemetryRuntimeProducer.recordStreamingEvents(new StreamingEvent(StreamEventsEnum.SSE_CONNECTION_ERROR.getType(),
156-
StreamEventsEnum.SseConnectionErrorValues.REQUESTED_CONNECTION_ERROR.getValue(), System.currentTimeMillis()));
156+
_telemetryRuntimeProducer.recordStreamingEvents(
157+
new StreamingEvent(StreamEventsEnum.SSE_CONNECTION_ERROR.getType(),
158+
StreamEventsEnum.SseConnectionErrorValues.REQUESTED_CONNECTION_ERROR.getValue(),
159+
System.currentTimeMillis()));
157160
return;
158161
}
159162
// Connection closed by server
160163
_statusCallback.apply(StatusMessage.RETRYABLE_ERROR);
161-
_telemetryRuntimeProducer.recordStreamingEvents(new StreamingEvent(StreamEventsEnum.SSE_CONNECTION_ERROR.getType(),
162-
StreamEventsEnum.SseConnectionErrorValues.NON_REQUESTED_CONNECTION_ERROR.getValue(), System.currentTimeMillis()));
164+
_telemetryRuntimeProducer
165+
.recordStreamingEvents(new StreamingEvent(StreamEventsEnum.SSE_CONNECTION_ERROR.getType(),
166+
StreamEventsEnum.SseConnectionErrorValues.NON_REQUESTED_CONNECTION_ERROR.getValue(),
167+
System.currentTimeMillis()));
163168
return;
164169
} catch (IOException exc) { // Other type of connection error
165-
if(!_forcedStop.get()) {
170+
if (!_forcedStop.get()) {
166171
_log.debug(String.format("SSE connection ended abruptly: %s. Retying", exc.getMessage()));
167-
_telemetryRuntimeProducer.recordStreamingEvents(new StreamingEvent(StreamEventsEnum.SSE_CONNECTION_ERROR.getType(),
168-
StreamEventsEnum.SseConnectionErrorValues.REQUESTED_CONNECTION_ERROR.getValue(), System.currentTimeMillis()));
172+
_telemetryRuntimeProducer.recordStreamingEvents(
173+
new StreamingEvent(StreamEventsEnum.SSE_CONNECTION_ERROR.getType(),
174+
StreamEventsEnum.SseConnectionErrorValues.REQUESTED_CONNECTION_ERROR.getValue(),
175+
System.currentTimeMillis()));
169176
_statusCallback.apply(StatusMessage.RETRYABLE_ERROR);
170177
return;
171178
}
172179

173-
_telemetryRuntimeProducer.recordStreamingEvents(new StreamingEvent(StreamEventsEnum.SSE_CONNECTION_ERROR.getType(),
174-
StreamEventsEnum.SseConnectionErrorValues.NON_REQUESTED_CONNECTION_ERROR.getValue(), System.currentTimeMillis()));
180+
_telemetryRuntimeProducer
181+
.recordStreamingEvents(new StreamingEvent(StreamEventsEnum.SSE_CONNECTION_ERROR.getType(),
182+
StreamEventsEnum.SseConnectionErrorValues.NON_REQUESTED_CONNECTION_ERROR.getValue(),
183+
System.currentTimeMillis()));
175184
}
176185
}
177186
} catch (Exception e) { // Any other error non related to the connection disables streaming altogether
178-
_telemetryRuntimeProducer.recordStreamingEvents(new StreamingEvent(StreamEventsEnum.SSE_CONNECTION_ERROR.getType(),
179-
StreamEventsEnum.SseConnectionErrorValues.NON_REQUESTED_CONNECTION_ERROR.getValue(), System.currentTimeMillis()));
187+
_telemetryRuntimeProducer
188+
.recordStreamingEvents(new StreamingEvent(StreamEventsEnum.SSE_CONNECTION_ERROR.getType(),
189+
StreamEventsEnum.SseConnectionErrorValues.NON_REQUESTED_CONNECTION_ERROR.getValue(),
190+
System.currentTimeMillis()));
180191
_log.warn(e.getMessage(), e);
181192
_statusCallback.apply(StatusMessage.NONRETRYABLE_ERROR);
182193
} finally {
@@ -194,12 +205,13 @@ private void connectAndLoop(URI uri, CountDownLatch signal) {
194205

195206
private boolean establishConnection(URI uri, CountDownLatch signal) {
196207
HttpGet request = new HttpGet(uri);
197-
request = (HttpGet) _requestDecorator.decorateHeaders(request);
208+
request = (HttpGet) ApacheRequestDecorator.decorate(request, _requestDecorator);
198209
_ongoingRequest.set(request);
199210
try {
200211
_ongoingResponse.set(_client.execute(_ongoingRequest.get()));
201212
if (_ongoingResponse.get().getCode() != 200) {
202-
_log.error(String.format("Establishing connection, code error: %s. The url is %s", _ongoingResponse.get().getCode(), uri.toURL()));
213+
_log.error(String.format("Establishing connection, code error: %s. The url is %s",
214+
_ongoingResponse.get().getCode(), uri.toURL()));
203215
return false;
204216
}
205217
_state.set(ConnectionState.OPEN);
@@ -236,4 +248,4 @@ private void handleMessage(String message) {
236248
RawEvent e = RawEvent.fromString(message);
237249
_eventCallback.apply(e);
238250
}
239-
}
251+
}

client/src/main/java/io/split/service/CustomHttpModule.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
import java.io.IOException;
77

88
public interface CustomHttpModule {
9-
public SplitHttpClient createClient(String apiToken, SDKMetadata sdkMetadata) throws IOException;
9+
public SplitHttpClient createClient(String apiToken, SDKMetadata sdkMetadata, RequestDecorator decorator)
10+
throws IOException;
1011
}

client/src/main/java/io/split/service/SplitHttpClientImpl.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.split.service;
22

33
import io.split.client.RequestDecorator;
4+
import io.split.client.utils.ApacheRequestDecorator;
45
import io.split.client.utils.SDKMetadata;
56
import io.split.client.utils.Utils;
67
import io.split.engine.common.FetchOptions;
@@ -76,7 +77,7 @@ public SplitHttpResponse get(URI uri, FetchOptions options, Map<String, List<Str
7677
request.setHeader(HEADER_CACHE_CONTROL_NAME, HEADER_CACHE_CONTROL_VALUE);
7778
}
7879

79-
_requestDecorator.decorateHeaders(request);
80+
request = (HttpGet) ApacheRequestDecorator.decorate(request, _requestDecorator);
8081

8182
response = _client.execute(request);
8283

@@ -121,7 +122,7 @@ public SplitHttpResponse post(URI uri, String body, Map<String, List<String>> ad
121122
}
122123
}
123124
request.setEntity(HttpEntities.create(body, ContentType.APPLICATION_JSON));
124-
request = (HttpPost) _requestDecorator.decorateHeaders(request);
125+
request = (HttpPost) ApacheRequestDecorator.decorate(request, _requestDecorator);
125126

126127
response = _client.execute(request);
127128

okhttp-modules/src/main/java/io/split/httpmodules/okhttp/OkHttpClientImpl.java

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.split.httpmodules.okhttp;
22

3+
import io.split.client.RequestDecorator;
34
import io.split.client.dtos.SplitHttpResponse;
45
import io.split.client.utils.SDKMetadata;
56
import io.split.engine.common.FetchOptions;
@@ -15,12 +16,14 @@
1516
import java.net.HttpURLConnection;
1617
import java.net.Proxy;
1718
import java.net.URI;
18-
import java.nio.charset.Charset;
1919
import java.util.ArrayList;
20+
import java.util.Collections;
2021
import java.util.HashMap;
2122
import java.util.List;
2223
import java.util.Map;
2324
import java.util.concurrent.TimeUnit;
25+
import java.util.stream.Collectors;
26+
import java.util.stream.Stream;
2427

2528
public class OkHttpClientImpl implements SplitHttpClient {
2629
protected OkHttpClient httpClient;
@@ -34,20 +37,17 @@ public class OkHttpClientImpl implements SplitHttpClient {
3437
private static final String HEADER_CLIENT_VERSION = "SplitSDKVersion";
3538
private String _apikey;
3639
protected SDKMetadata _metadata;
40+
private final RequestDecorator _decorator;
3741

3842
public OkHttpClientImpl(String apiToken, SDKMetadata sdkMetadata,
3943
Proxy proxy, String proxyAuthKerberosPrincipalName, boolean debugEnabled,
40-
int readTimeout, int connectionTimeout) throws IOException {
44+
int readTimeout, int connectionTimeout, RequestDecorator decorator) throws IOException {
4145
_apikey = apiToken;
4246
_metadata = sdkMetadata;
43-
setHttpClient(proxy, proxyAuthKerberosPrincipalName, debugEnabled,
44-
readTimeout, connectionTimeout);
45-
}
46-
47-
protected void setHttpClient(Proxy proxy, String proxyAuthKerberosPrincipalName, boolean debugEnabled,
48-
int readTimeout, int connectionTimeout) throws IOException {
47+
_decorator = decorator;
4948
httpClient = initializeClient(proxy, proxyAuthKerberosPrincipalName, debugEnabled,
5049
readTimeout, connectionTimeout);
50+
5151
}
5252

5353
protected OkHttpClient initializeClient(Proxy proxy, String proxyAuthKerberosPrincipalName, boolean debugEnabled,
@@ -86,8 +86,8 @@ public SplitHttpResponse get(URI uri, FetchOptions options, Map<String, List<Str
8686
try {
8787
okhttp3.Request.Builder requestBuilder = getRequestBuilder();
8888
requestBuilder.url(uri.toString());
89-
setBasicHeaders(requestBuilder);
90-
setAdditionalAndDecoratedHeaders(requestBuilder, additionalHeaders);
89+
Map<String, List<String>> headers = mergeHeaders(buildBasicHeaders(), additionalHeaders);
90+
requestBuilder = OkHttpRequestDecorator.decorate(headers, requestBuilder, _decorator);
9191
if (options.cacheControlHeadersEnabled()) {
9292
requestBuilder.addHeader(HEADER_CACHE_CONTROL_NAME, HEADER_CACHE_CONTROL_VALUE);
9393
}
@@ -128,8 +128,8 @@ public SplitHttpResponse post(URI url, String entity,
128128
try {
129129
okhttp3.Request.Builder requestBuilder = getRequestBuilder();
130130
requestBuilder.url(url.toString());
131-
setBasicHeaders(requestBuilder);
132-
setAdditionalAndDecoratedHeaders(requestBuilder, additionalHeaders);
131+
Map<String, List<String>> headers = mergeHeaders(buildBasicHeaders(), additionalHeaders);
132+
requestBuilder = OkHttpRequestDecorator.decorate(headers, requestBuilder, _decorator);
133133
requestBuilder.addHeader("Accept-Encoding", "gzip");
134134
requestBuilder.addHeader("Content-Type", "application/json");
135135
RequestBody postBody = RequestBody.create(MediaType.parse("application/json; charset=utf-16"), entity);
@@ -168,25 +168,31 @@ protected Request getRequest(okhttp3.Request.Builder requestBuilder) {
168168
return requestBuilder.build();
169169
}
170170

171-
protected void setBasicHeaders(okhttp3.Request.Builder requestBuilder) {
172-
requestBuilder.addHeader(HEADER_API_KEY, "Bearer " + _apikey);
173-
requestBuilder.addHeader(HEADER_CLIENT_VERSION, _metadata.getSdkVersion());
174-
requestBuilder.addHeader(HEADER_CLIENT_MACHINE_IP, _metadata.getMachineIp());
175-
requestBuilder.addHeader(HEADER_CLIENT_MACHINE_NAME, _metadata.getMachineName());
176-
requestBuilder.addHeader(HEADER_CLIENT_KEY, _apikey.length() > 4
171+
private Map<String, List<String>> buildBasicHeaders() {
172+
Map<String, List<String>> h = new HashMap<>();
173+
h.put(HEADER_API_KEY, Collections.singletonList("Bearer " + _apikey));
174+
h.put(HEADER_CLIENT_VERSION, Collections.singletonList(_metadata.getSdkVersion()));
175+
h.put(HEADER_CLIENT_MACHINE_IP, Collections.singletonList(_metadata.getMachineIp()));
176+
h.put(HEADER_CLIENT_MACHINE_NAME, Collections.singletonList(_metadata.getMachineName()));
177+
h.put(HEADER_CLIENT_KEY, Collections.singletonList(_apikey.length() > 4
177178
? _apikey.substring(_apikey.length() - 4)
178-
: _apikey);
179+
: _apikey));
180+
return h;
179181
}
180182

181-
protected void setAdditionalAndDecoratedHeaders(okhttp3.Request.Builder requestBuilder,
182-
Map<String, List<String>> additionalHeaders) {
183-
if (additionalHeaders != null) {
184-
for (Map.Entry<String, List<String>> entry : additionalHeaders.entrySet()) {
185-
for (String value : entry.getValue()) {
186-
requestBuilder.addHeader(entry.getKey(), value);
187-
}
188-
}
183+
private static Map<String, List<String>> mergeHeaders(Map<String, List<String>> headers,
184+
Map<String, List<String>> toAdd) {
185+
if (toAdd == null || toAdd.size() == 0) {
186+
return headers;
189187
}
188+
189+
for (Map.Entry<String, List<String>> entry : toAdd.entrySet()) {
190+
headers.computeIfPresent(entry.getKey(),
191+
(k, oldValue) -> Stream.concat(oldValue.stream(), entry.getValue().stream())
192+
.collect(Collectors.toList()));
193+
}
194+
195+
return headers;
190196
}
191197

192198
protected SplitHttpResponse.Header[] getResponseHeaders(Response response) {

0 commit comments

Comments
 (0)