Adds property to allow headers to be passed down the stream rather than overwrite them
MODIFY
unique-header-policy/src/main/apiman/policyDefs/schemas/unique-header-policyDef.schema
unique-header-policy/src/main/apiman/policyDefs/schemas/unique-header-policyDef.schema
"headerName": {
"type": "string",
"title": "HTTP Header Name"
+ },
+ "overwriteHeaderValue": {
+ "type": "boolean",
+ "title": "Overwrite HTTP Header value"
}
}
}
\ No newline at end of file

MODIFY
unique-header-policy/src/main/java/io/apiman/plugins/uniqueheader/UniqueHeaderPolicy.java
unique-header-policy/src/main/java/io/apiman/plugins/uniqueheader/UniqueHeaderPolicy.java
@@ -2,6 +2,7 @@ package io.apiman.plugins.uniqueheader;
import io.apiman.gateway.engine.beans.ApiRequest;
import io.apiman.gateway.engine.beans.exceptions.ConfigurationParseException;
+import io.apiman.gateway.engine.beans.util.HeaderMap;
import io.apiman.gateway.engine.policies.AbstractMappedPolicy;
import io.apiman.gateway.engine.policy.IPolicyChain;
import io.apiman.gateway.engine.policy.IPolicyContext;
@@ -49,10 +50,50 @@ public class UniqueHeaderPolicy extends AbstractMappedPolicy<UniqueHeaderBean> {
protected void doApply(ApiRequest request, IPolicyContext context, UniqueHeaderBean config,
IPolicyChain<ApiRequest> chain) {
- request.getHeaders().put(config.getHeaderName(), generateUniqueString());
+ request.setHeaders(handleHeader(request.getHeaders(), config));
chain.doApply(request);
}
+ /**
+ * Handles the headers in regards to io.apiman.plugins.uniqueheader.beans.UniqueHeaderBean#isOverwriteHeader()
+ * by overwriting the io.apiman.plugins.uniqueheader.beans.UniqueHeaderBean#getHeaderName() if the overwriteHeader
+ * value is true
+ * @param headers provided in the request
+ * @param config the policy's configuration information
+ * @return the header map containing the new header
+ */
+ protected HeaderMap handleHeader(HeaderMap headers, UniqueHeaderBean config) {
+ if(!config.isOverwriteHeaderValue()){
+ if(!isHeaderPresent(headers, config)){
+ return putHeader(headers, config);
+ }
+ return headers;
+ }
+
+ return putHeader(headers, config);
+ }
+
+ /**
+ * Check if the expected header was provided
+ * @param headers provided in the request
+ * @param config the policy's configuration information
+ * @return true if the header is present
+ */
+ protected boolean isHeaderPresent(HeaderMap headers, UniqueHeaderBean config) {
+ return headers.containsKey(config.getHeaderName());
+ }
+
+ /**
+ * Adds a new header into the request.getHeaders()
+ * @param headerMap the request headers
+ * @param config the policy's configuration information
+ * @return the header map containing the new added header
+ */
+ protected HeaderMap putHeader(HeaderMap headerMap, UniqueHeaderBean config) {
+ headerMap.put(config.getHeaderName(), generateUniqueString());
+ return headerMap;
+ }
+
/**
* @return a unique String to set in the header
*/

MODIFY
unique-header-policy/src/main/java/io/apiman/plugins/uniqueheader/beans/UniqueHeaderBean.java
unique-header-policy/src/main/java/io/apiman/plugins/uniqueheader/beans/UniqueHeaderBean.java
@@ -14,7 +14,7 @@ import java.io.Serializable;
* @author Pete Cornish {@literal <outofcoffee@gmail.com>}
*/
@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
-@JsonPropertyOrder({"headerName"})
+@JsonPropertyOrder({"headerName", "overwriteHeaderValue"})
public class UniqueHeaderBean implements Serializable {
/**
* The name of the HTTP Header to set.
@@ -22,6 +22,12 @@ public class UniqueHeaderBean implements Serializable {
@JsonProperty("headerName")
private String headerName;
+ /**
+ * Overwrite the value provided in header
+ */
+ @JsonProperty("overwriteHeaderValue")
+ private boolean overwriteHeaderValue = false;
+
@Override
public int hashCode() {
return new HashCodeBuilder()
@@ -50,4 +56,12 @@ public class UniqueHeaderBean implements Serializable {
public void setHeaderName(String headerName) {
this.headerName = headerName;
}
+
+ public boolean isOverwriteHeaderValue() {
+ return overwriteHeaderValue;
+ }
+
+ public void setOverwriteHeaderValue(boolean overwriteHeaderValue) {
+ this.overwriteHeaderValue = overwriteHeaderValue;
+ }
}

MODIFY
unique-header-policy/src/test/java/io/apiman/plugins/uniqueheader/UniqueHeaderPolicyTest.java
unique-header-policy/src/test/java/io/apiman/plugins/uniqueheader/UniqueHeaderPolicyTest.java
@@ -9,6 +9,7 @@ import org.junit.Test;
import java.net.HttpURLConnection;
import java.util.HashMap;
import java.util.Map;
+import java.util.UUID;
import static org.junit.Assert.*;
@@ -20,6 +21,8 @@ import static org.junit.Assert.*;
@SuppressWarnings("nls")
@TestingPolicy(UniqueHeaderPolicy.class)
public class UniqueHeaderPolicyTest extends ApimanPolicyTest {
+ private static final String X_CORRELATION_ID = "X-CorrelationID";
+
private static ObjectMapper jsonMapper;
/**
@@ -32,6 +35,7 @@ public class UniqueHeaderPolicyTest extends ApimanPolicyTest {
/**
* Expects that a unique value is set with the HTTP Header name 'X-CorrelationID'.
+ * Missing overwriteHeaderValue property should keep the provided header value
*
* @throws Throwable
*/
@@ -40,7 +44,65 @@ public class UniqueHeaderPolicyTest extends ApimanPolicyTest {
@Configuration(classpathConfigFile = "basic-config.json")
@BackEndApi(EchoBackEndApi.class)
public void testUniqueValueSet() throws Throwable {
- final PolicyTestRequest request = PolicyTestRequest.build(PolicyTestRequestType.GET, "/example");
+ final String correlationId = UUID.randomUUID().toString();
+ final PolicyTestRequest request = PolicyTestRequest.build(PolicyTestRequestType.GET, "/example")
+ .header(X_CORRELATION_ID, correlationId);
+ final PolicyTestResponse response = send(request);
+
+ assertEquals(HttpURLConnection.HTTP_OK, response.code());
+ assertNotNull(response.body());
+
+ // the headers are mirrored back by the EchoBackEndApi in its response body
+ final Map<String, Object> responseAsMap = jsonMapper.readValue(response.body(), HashMap.class);
+ final Map<String, Object> headers = (Map<String, Object>) responseAsMap.get("headers");
+ assertNotNull(headers);
+ assertEquals(1, headers.size());
+ assertNotNull(headers.get(X_CORRELATION_ID));
+ assertEquals(correlationId, headers.get(X_CORRELATION_ID));
+ }
+
+ /**
+ * Expects that a unique value is set with the HTTP Header name 'X-CorrelationID'.
+ * "overwriteHeaderValue": true property should set a new header value
+ *
+ * @throws Throwable
+ */
+ @SuppressWarnings("unchecked")
+ @Test
+ @Configuration(classpathConfigFile = "overwrite-header-config.json")
+ @BackEndApi(EchoBackEndApi.class)
+ public void testOverwriteExistentHeaderValue() throws Throwable {
+ final String correlationId = UUID.randomUUID().toString();
+ final PolicyTestRequest request = PolicyTestRequest.build(PolicyTestRequestType.GET, "/example")
+ .header(X_CORRELATION_ID, correlationId);
+ final PolicyTestResponse response = send(request);
+
+ assertEquals(HttpURLConnection.HTTP_OK, response.code());
+ assertNotNull(response.body());
+
+ // the headers are mirrored back by the EchoBackEndApi in its response body
+ final Map<String, Object> responseAsMap = jsonMapper.readValue(response.body(), HashMap.class);
+ final Map<String, Object> headers = (Map<String, Object>) responseAsMap.get("headers");
+ assertNotNull(headers);
+ assertEquals(1, headers.size());
+ assertNotNull(headers.get(X_CORRELATION_ID));
+ assertNotEquals(correlationId, headers.get(X_CORRELATION_ID));
+ }
+
+ /**
+ * Expects that a unique value is set with the HTTP Header name 'X-CorrelationID'.
+ * Explicit "overwriteHeaderValue": false property should not set a new header value and keep the value provided
+ *
+ * @throws Throwable
+ */
+ @SuppressWarnings("unchecked")
+ @Test
+ @Configuration(classpathConfigFile = "not-overwrite-header-config.json")
+ @BackEndApi(EchoBackEndApi.class)
+ public void testNotOverwriteExistentHeaderValue() throws Throwable {
+ final String correlationId = UUID.randomUUID().toString();
+ final PolicyTestRequest request = PolicyTestRequest.build(PolicyTestRequestType.GET, "/example")
+ .header(X_CORRELATION_ID, correlationId);
final PolicyTestResponse response = send(request);
assertEquals(HttpURLConnection.HTTP_OK, response.code());
@@ -51,7 +113,8 @@ public class UniqueHeaderPolicyTest extends ApimanPolicyTest {
final Map<String, Object> headers = (Map<String, Object>) responseAsMap.get("headers");
assertNotNull(headers);
assertEquals(1, headers.size());
- assertNotNull(headers.get("X-CorrelationID"));
+ assertNotNull(headers.get(X_CORRELATION_ID));
+ assertEquals(correlationId, headers.get(X_CORRELATION_ID));
}
/**

ADD
unique-header-policy/src/test/resources/not-overwrite-header-config.json
+{
+ "headerName": "X-CorrelationID",
+ "overwriteHeaderValue": false
+}

ADD
unique-header-policy/src/test/resources/overwrite-header-config.json
+{
+ "headerName": "X-CorrelationID",
+ "overwriteHeaderValue": true
+}

Adds property to allow headers to be passed down the stream rather than overwrite them