Allows the unique header to be set in the outgoing HTTP response.
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
"overwriteHeaderValue": {
"type": "boolean",
"title": "Overwrite HTTP Header value"
+ },
+ "responseHeader": {
+ "type": "boolean",
+ "title": "Whether to also set the header in the outgoing response.",
+ "default": false
}
}
}

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
package io.apiman.plugins.uniqueheader;
import io.apiman.gateway.engine.beans.ApiRequest;
+import io.apiman.gateway.engine.beans.ApiResponse;
import io.apiman.gateway.engine.beans.exceptions.ConfigurationParseException;
import io.apiman.gateway.engine.beans.util.HeaderMap;
import io.apiman.gateway.engine.policies.AbstractMappedPolicy;
@@ -12,6 +13,9 @@ import org.apache.commons.lang.StringUtils;
import java.util.UUID;
+import static java.lang.Boolean.TRUE;
+import static java.util.Objects.nonNull;
+
/**
* A policy that sets a unique value in a named header.
*
@@ -19,6 +23,7 @@ import java.util.UUID;
*/
public class UniqueHeaderPolicy extends AbstractMappedPolicy<UniqueHeaderBean> {
private static final Messages MESSAGES = new Messages("io.apiman.plugins.uniqueheader", "UniqueHeaderPolicy");
+ private static final String UNIQUE_HEADER_KEY = "unique.header.value";
/**
* @see io.apiman.gateway.engine.policies.AbstractMappedPolicy#getConfigurationClass()
@@ -50,54 +55,46 @@ public class UniqueHeaderPolicy extends AbstractMappedPolicy<UniqueHeaderBean> {
protected void doApply(ApiRequest request, IPolicyContext context, UniqueHeaderBean config,
IPolicyChain<ApiRequest> chain) {
- request.setHeaders(handleHeader(request.getHeaders(), config));
+ handleHeader(request.getHeaders(), context, config);
chain.doApply(request);
}
+ @Override
+ protected void doApply(ApiResponse response, IPolicyContext context, UniqueHeaderBean config,
+ IPolicyChain<ApiResponse> chain) {
+
+ if (TRUE.equals(config.getResponseHeader())) {
+ final String uniqueValue = context.getAttribute(UNIQUE_HEADER_KEY, null);
+ if (nonNull(uniqueValue)) {
+ response.getHeaders().put(config.getHeaderName(), uniqueValue);
+ }
+ }
+ super.doApply(response, context, config, chain);
+ }
+
/**
* 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) {
+ private void handleHeader(HeaderMap headers, IPolicyContext context, UniqueHeaderBean config) {
+ String headerValue = null;
if (!config.isOverwriteHeaderValue()) {
- if(!isHeaderPresent(headers, config)){
- return putHeader(headers, config);
+ headerValue = headers.get(config.getHeaderName());
}
- return headers;
+ if (StringUtils.isBlank(headerValue)) {
+ headerValue = generateUniqueString();
}
-
- 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;
+ headers.put(config.getHeaderName(), headerValue);
+ context.setAttribute(UNIQUE_HEADER_KEY, headerValue);
}
/**
* @return a unique String to set in the header
*/
- protected String generateUniqueString() {
+ private String generateUniqueString() {
return UUID.randomUUID().toString();
}
}

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", "overwriteHeaderValue"})
+@JsonPropertyOrder({"headerName", "overwriteHeaderValue", "responseHeader"})
public class UniqueHeaderBean implements Serializable {
/**
* The name of the HTTP Header to set.
@@ -28,10 +28,18 @@ public class UniqueHeaderBean implements Serializable {
@JsonProperty("overwriteHeaderValue")
private boolean overwriteHeaderValue = false;
+ /**
+ * Whether to also set the header in the outgoing response.
+ */
+ @JsonProperty("responseHeader")
+ private Boolean responseHeader = false;
+
@Override
public int hashCode() {
return new HashCodeBuilder()
.append(headerName)
+ .append(overwriteHeaderValue)
+ .append(responseHeader)
.toHashCode();
}
@@ -46,6 +54,8 @@ public class UniqueHeaderBean implements Serializable {
final UniqueHeaderBean rhs = ((UniqueHeaderBean) other);
return new EqualsBuilder()
.append(headerName, rhs.headerName)
+ .append(overwriteHeaderValue, rhs.overwriteHeaderValue)
+ .append(responseHeader, rhs.responseHeader)
.isEquals();
}
@@ -64,4 +74,12 @@ public class UniqueHeaderBean implements Serializable {
public void setOverwriteHeaderValue(boolean overwriteHeaderValue) {
this.overwriteHeaderValue = overwriteHeaderValue;
}
+
+ public Boolean getResponseHeader() {
+ return responseHeader;
+ }
+
+ public void setResponseHeader(Boolean responseHeader) {
+ this.responseHeader = responseHeader;
+ }
}

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
@@ -21,7 +21,7 @@ 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 final String HEADER_NAME = "X-CorrelationID";
private static ObjectMapper jsonMapper;
@@ -36,8 +36,6 @@ 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
*/
@SuppressWarnings("unchecked")
@Test
@@ -46,7 +44,7 @@ public class UniqueHeaderPolicyTest extends ApimanPolicyTest {
public void testUniqueValueSet() throws Throwable {
final String correlationId = UUID.randomUUID().toString();
final PolicyTestRequest request = PolicyTestRequest.build(PolicyTestRequestType.GET, "/example")
- .header(X_CORRELATION_ID, correlationId);
+ .header(HEADER_NAME, correlationId);
final PolicyTestResponse response = send(request);
assertEquals(HttpURLConnection.HTTP_OK, response.code());
@@ -57,8 +55,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_CORRELATION_ID));
- assertEquals(correlationId, headers.get(X_CORRELATION_ID));
+ assertNotNull(headers.get(HEADER_NAME));
+ assertEquals(correlationId, headers.get(HEADER_NAME));
}
/**
@@ -74,7 +72,7 @@ public class UniqueHeaderPolicyTest extends ApimanPolicyTest {
public void testOverwriteExistentHeaderValue() throws Throwable {
final String correlationId = UUID.randomUUID().toString();
final PolicyTestRequest request = PolicyTestRequest.build(PolicyTestRequestType.GET, "/example")
- .header(X_CORRELATION_ID, correlationId);
+ .header(HEADER_NAME, correlationId);
final PolicyTestResponse response = send(request);
assertEquals(HttpURLConnection.HTTP_OK, response.code());
@@ -85,8 +83,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_CORRELATION_ID));
- assertNotEquals(correlationId, headers.get(X_CORRELATION_ID));
+ assertNotNull(headers.get(HEADER_NAME));
+ assertNotEquals(correlationId, headers.get(HEADER_NAME));
}
/**
@@ -102,7 +100,7 @@ public class UniqueHeaderPolicyTest extends ApimanPolicyTest {
public void testNotOverwriteExistentHeaderValue() throws Throwable {
final String correlationId = UUID.randomUUID().toString();
final PolicyTestRequest request = PolicyTestRequest.build(PolicyTestRequestType.GET, "/example")
- .header(X_CORRELATION_ID, correlationId);
+ .header(HEADER_NAME, correlationId);
final PolicyTestResponse response = send(request);
assertEquals(HttpURLConnection.HTTP_OK, response.code());
@@ -113,14 +111,30 @@ 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_CORRELATION_ID));
- assertEquals(correlationId, headers.get(X_CORRELATION_ID));
+ assertNotNull(headers.get(HEADER_NAME));
+ assertEquals(correlationId, headers.get(HEADER_NAME));
+ }
+
+ /**
+ * Expects that a unique value is set in the response with the HTTP Header name 'X-CorrelationID'.
+ */
+ @Test
+ @Configuration(classpathConfigFile = "response-header-config.json")
+ @BackEndApi(EchoBackEndApi.class)
+ public void testResponseHeaderSet() throws Throwable {
+ final PolicyTestRequest request = PolicyTestRequest.build(PolicyTestRequestType.GET, "/example");
+ final PolicyTestResponse response = send(request);
+
+ assertEquals(HttpURLConnection.HTTP_OK, response.code());
+ assertNotNull(response.body());
+
+ final Map<String, String> headers = response.headers().toMap();
+ assertNotNull(headers);
+ assertNotNull(headers.get(HEADER_NAME));
}
/**
* Expects that a {@link ConfigurationParseException} is thrown if the header name configuration item is not set.
- *
- * @throws Throwable
*/
@Test(expected = ConfigurationParseException.class)
@Configuration(classpathConfigFile = "empty-config.json")

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

Allows the unique header to be set in the outgoing HTTP response.