From 9f55500bede03f1cdd63b5740c79ec1c5e04a290 Mon Sep 17 00:00:00 2001 From: Christoph Deppisch Date: Wed, 30 Aug 2023 23:06:34 +0200 Subject: [PATCH] fix(#472): Add Http header name ignore case setting Enable/disable header name case-insensitive verification mode --- java/docs/steps-http.adoc | 14 ++++++++++++++ .../citrusframework/yaks/http/HttpClientSteps.java | 11 +++++++++-- .../citrusframework/yaks/http/HttpServerSteps.java | 9 +++++++++ .../citrusframework/yaks/http/HttpSettings.java | 10 ++++++++++ 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/java/docs/steps-http.adoc b/java/docs/steps-http.adoc index f8492e6a..f1f5913e 100644 --- a/java/docs/steps-http.adoc +++ b/java/docs/steps-http.adoc @@ -266,6 +266,20 @@ Then expect HTTP response headers | Content-Type | application/json | ---- +==== Header name ignore case + +Header names are not case-sensitive per Http specification. This means servers and clients may choose the header name case individually. In order to avoid verification errors when expecting headers in Http the header validation mechanism in Citrus is able to ignore the header name case. + +.@Given("^HTTP header name ignore case is (enabled|disabled)$") +[source,gherkin] +---- +Given HTTP header name ignore case is enabled +---- + +This will enable the mode where header name verification is case-insensitive. + +You may also use a environment setting `YAKS_HTTP_HEADER_NAME_IGNORE_CASE=true/false` in `yaks-config` to enable/disable the setting for the whole test suite. By default, the setting is disabled so header names are verified with case-sensitive mode. + ==== Response body .@Then("^expect HTTP response body: {body}$") diff --git a/java/steps/yaks-http/src/main/java/org/citrusframework/yaks/http/HttpClientSteps.java b/java/steps/yaks-http/src/main/java/org/citrusframework/yaks/http/HttpClientSteps.java index 03910261..bab12cd4 100644 --- a/java/steps/yaks-http/src/main/java/org/citrusframework/yaks/http/HttpClientSteps.java +++ b/java/steps/yaks-http/src/main/java/org/citrusframework/yaks/http/HttpClientSteps.java @@ -17,13 +17,13 @@ package org.citrusframework.yaks.http; -import javax.net.ssl.SSLContext; import java.io.IOException; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; +import javax.net.ssl.SSLContext; import com.consol.citrus.Citrus; import com.consol.citrus.CitrusSettings; @@ -78,6 +78,7 @@ public class HttpClientSteps implements HttpSteps { private Map responseHeaders = new HashMap<>(); private Map requestParams = new HashMap<>(); + private boolean headerNameIgnoreCase = HttpSettings.isHeaderNameIgnoreCase(); private Map bodyValidationExpressions = new HashMap<>(); private String requestMessageType; @@ -147,6 +148,11 @@ public void configureForkMode(String mode) { this.forkMode = "enabled".equals(mode); } + @Given("^HTTP header name ignore case is (enabled|disabled)$") + public void configureHeaderNameIgnoreCase(String mode) { + this.headerNameIgnoreCase = "enabled".equals(mode); + } + @Given("^(?:URL|url) is healthy$") public void healthCheck() { waitForHttpUrl(requestUrl); @@ -350,7 +356,8 @@ private void sendClientRequest(HttpMessage request) { private void receiveClientResponse(HttpMessage response) { HttpClientResponseActionBuilder.HttpMessageBuilderSupport responseBuilder = http().client(httpClient).receive() .response(response.getStatusCode()) - .message(response); + .message(response) + .headerNameIgnoreCase(headerNameIgnoreCase); responseBuilder.validate(pathExpression().expressions(bodyValidationExpressions)); bodyValidationExpressions.clear(); diff --git a/java/steps/yaks-http/src/main/java/org/citrusframework/yaks/http/HttpServerSteps.java b/java/steps/yaks-http/src/main/java/org/citrusframework/yaks/http/HttpServerSteps.java index 43ecce1d..9c05cb15 100644 --- a/java/steps/yaks-http/src/main/java/org/citrusframework/yaks/http/HttpServerSteps.java +++ b/java/steps/yaks-http/src/main/java/org/citrusframework/yaks/http/HttpServerSteps.java @@ -84,6 +84,8 @@ public class HttpServerSteps implements HttpSteps { private Map responseHeaders = new HashMap<>(); private Map requestParams = new HashMap<>(); + private boolean headerNameIgnoreCase = HttpSettings.isHeaderNameIgnoreCase(); + private Map bodyValidationExpressions = new HashMap<>(); private String requestMessageType; @@ -140,6 +142,11 @@ public void setServer(String name) { } } + @Given("^HTTP server header name ignore case is (enabled|disabled)$") + public void configureHeaderNameIgnoreCase(String mode) { + this.headerNameIgnoreCase = "enabled".equals(mode); + } + @Given("^HTTP server \"([^\"\\s]+)\" with configuration$") public void setServerWithProperties(String name, DataTable properties) { configureServer(properties.asMap(String.class, String.class)); @@ -356,6 +363,8 @@ public void receiveServerRequest(HttpMessage request) { requestBuilder = receiveBuilder.post().message(request); } + requestBuilder.headerNameIgnoreCase(headerNameIgnoreCase); + if (!bodyValidationExpressions.isEmpty()) { requestBuilder.validate(pathExpression().expressions(bodyValidationExpressions)); bodyValidationExpressions.clear(); diff --git a/java/steps/yaks-http/src/main/java/org/citrusframework/yaks/http/HttpSettings.java b/java/steps/yaks-http/src/main/java/org/citrusframework/yaks/http/HttpSettings.java index 47115753..7b07b58b 100644 --- a/java/steps/yaks-http/src/main/java/org/citrusframework/yaks/http/HttpSettings.java +++ b/java/steps/yaks-http/src/main/java/org/citrusframework/yaks/http/HttpSettings.java @@ -53,6 +53,10 @@ public class HttpSettings { private static final String SECURE_KEYSTORE_PASSWORD_ENV = HTTP_ENV_PREFIX + "SECURE_KEYSTORE_PASSWORD"; private static final String SECURE_KEYSTORE_PASSWORD_DEFAULT = "secret"; + private static final String HEADER_NAME_IGNORE_CASE_PROPERTY = HTTP_PROPERTY_PREFIX + "header.name.ignore.case"; + private static final String HEADER_NAME_IGNORE_CASE_ENV = HTTP_ENV_PREFIX + "HEADER_NAME_IGNORE_CASE"; + private static final String HEADER_NAME_IGNORE_CASE_DEFAULT = "false"; + private HttpSettings() { // prevent instantiation of utility class } @@ -121,4 +125,10 @@ public static String getSslKeyStorePassword() { System.getenv(SECURE_KEYSTORE_PASSWORD_ENV) != null ? System.getenv(SECURE_KEYSTORE_PASSWORD_ENV) : SECURE_KEYSTORE_PASSWORD_DEFAULT); } + + public static boolean isHeaderNameIgnoreCase() { + return Boolean.parseBoolean(System.getProperty(HEADER_NAME_IGNORE_CASE_PROPERTY, + System.getenv(HEADER_NAME_IGNORE_CASE_ENV) != null ? System.getenv(HEADER_NAME_IGNORE_CASE_ENV) : + HEADER_NAME_IGNORE_CASE_DEFAULT)); + } }