From 508489a4ea7000b9e24cdb0ea48f5357010d783e Mon Sep 17 00:00:00 2001 From: Marek SzwaƂkiewicz Date: Thu, 2 Mar 2023 12:43:50 +0100 Subject: Enable case insensitive matching of http headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change creates simple case insensitive map implementation that is used in HttpSdcResponse class to store the response headers. Generally HTTP headers are supposed to be case insensitive and sometimes get transformed (in our case - by istio sidecar) to lower case. With this change lower case will still be matched and the original behaviour will not break. Issue-ID: SDC-4233 Signed-off-by: Marek SzwaƂkiewicz Change-Id: I1cb9d9e75ff656ccb12c690c553bccc672332a12 --- .../java/org/onap/sdc/http/HttpRequestFactory.java | 9 ++-- .../main/java/org/onap/sdc/http/HttpSdcClient.java | 13 +++--- .../java/org/onap/sdc/http/HttpSdcResponse.java | 12 ++--- .../java/org/onap/sdc/http/IHttpSdcClient.java | 7 ++- .../java/org/onap/sdc/http/SdcConnectorClient.java | 15 +++--- .../org/onap/sdc/utils/CaseInsensitiveMap.java | 53 ++++++++++++++++++++++ .../java/org/onap/sdc/http/HttpAsdcClientTest.java | 3 +- .../org/onap/sdc/http/HttpRequestFactoryTest.java | 5 +- .../org/onap/sdc/http/SdcConnectorClientTest.java | 14 ++++-- 9 files changed, 95 insertions(+), 36 deletions(-) create mode 100644 sdc-distribution-client/src/main/java/org/onap/sdc/utils/CaseInsensitiveMap.java diff --git a/sdc-distribution-client/src/main/java/org/onap/sdc/http/HttpRequestFactory.java b/sdc-distribution-client/src/main/java/org/onap/sdc/http/HttpRequestFactory.java index 9e2f3ee..ab4bd29 100644 --- a/sdc-distribution-client/src/main/java/org/onap/sdc/http/HttpRequestFactory.java +++ b/sdc-distribution-client/src/main/java/org/onap/sdc/http/HttpRequestFactory.java @@ -19,15 +19,16 @@ */ package org.onap.sdc.http; + import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.message.BasicHeader; +import org.onap.sdc.utils.CaseInsensitiveMap; import java.util.Base64; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; public class HttpRequestFactory { @@ -40,14 +41,14 @@ public class HttpRequestFactory { this.authHeaderValue = "Basic " + Base64.getEncoder().encodeToString(createAuthHeaderData(user, password)); } - public HttpGet createHttpGetRequest(String url, Map headersMap) { + public HttpGet createHttpGetRequest(String url, CaseInsensitiveMap headersMap) { HttpGet httpGet = new HttpGet(url); httpGet.setHeaders(createHttpRequestHeaders(headersMap, authHeaderValue)); return httpGet; } - public HttpPost createHttpPostRequest(String url, Map headersMap, HttpEntity entity) { + public HttpPost createHttpPostRequest(String url, CaseInsensitiveMap headersMap, HttpEntity entity) { HttpPost httpPost = new HttpPost(url); httpPost.setHeaders(createHttpRequestHeaders(headersMap, authHeaderValue)); httpPost.setEntity(entity); @@ -55,7 +56,7 @@ public class HttpRequestFactory { return httpPost; } - private Header[] createHttpRequestHeaders(Map headersMap, String authorizationValue) { + private Header[] createHttpRequestHeaders(CaseInsensitiveMap headersMap, String authorizationValue) { final List
headers = headersMap.entrySet().stream() .map(it -> new BasicHeader(it.getKey(), it.getValue())) .collect(Collectors.toList()); diff --git a/sdc-distribution-client/src/main/java/org/onap/sdc/http/HttpSdcClient.java b/sdc-distribution-client/src/main/java/org/onap/sdc/http/HttpSdcClient.java index 8b6ee0a..73663e6 100644 --- a/sdc-distribution-client/src/main/java/org/onap/sdc/http/HttpSdcClient.java +++ b/sdc-distribution-client/src/main/java/org/onap/sdc/http/HttpSdcClient.java @@ -31,6 +31,7 @@ import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.onap.sdc.api.consumer.IConfiguration; import org.onap.sdc.utils.Pair; +import org.onap.sdc.utils.CaseInsensitiveMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,8 +39,6 @@ import java.io.IOException; import java.net.ConnectException; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; public class HttpSdcClient implements IHttpSdcClient { @@ -75,11 +74,11 @@ public class HttpSdcClient implements IHttpSdcClient { this.httpClient = httpClientPair.getSecond(); } - public HttpSdcResponse postRequest(String requestUrl, HttpEntity entity, Map headersMap) { + public HttpSdcResponse postRequest(String requestUrl, HttpEntity entity, CaseInsensitiveMap headersMap) { return postRequest(requestUrl, entity, headersMap, ALWAYS_CLOSE_THE_REQUEST_CONNECTION).getFirst(); } - public Pair postRequest(String requestUrl, HttpEntity entity, Map headersMap, boolean closeTheRequest) { + public Pair postRequest(String requestUrl, HttpEntity entity, CaseInsensitiveMap headersMap, boolean closeTheRequest) { Pair ret; final String url = resolveUrl(requestUrl); log.debug("url to send {}", url); @@ -100,11 +99,11 @@ public class HttpSdcClient implements IHttpSdcClient { return ret; } - public HttpSdcResponse getRequest(String requestUrl, Map headersMap) { + public HttpSdcResponse getRequest(String requestUrl, CaseInsensitiveMap headersMap) { return getRequest(requestUrl, headersMap, ALWAYS_CLOSE_THE_REQUEST_CONNECTION).getFirst(); } - public Pair getRequest(String requestUrl, Map headersMap, boolean closeTheRequest) { + public Pair getRequest(String requestUrl, CaseInsensitiveMap headersMap, boolean closeTheRequest) { Pair ret; final String url = resolveUrl(requestUrl); @@ -118,7 +117,7 @@ public class HttpSdcClient implements IHttpSdcClient { log.debug("GET Response Status {}", httpResponse.getStatusLine().getStatusCode()); Header[] headersRes = httpResponse.getAllHeaders(); - Map headersResMap = new HashMap<>(); + CaseInsensitiveMap headersResMap = new CaseInsensitiveMap<>(); for (Header header : headersRes) { headersResMap.put(header.getName(), header.getValue()); } diff --git a/sdc-distribution-client/src/main/java/org/onap/sdc/http/HttpSdcResponse.java b/sdc-distribution-client/src/main/java/org/onap/sdc/http/HttpSdcResponse.java index ad64f3f..46a2c48 100644 --- a/sdc-distribution-client/src/main/java/org/onap/sdc/http/HttpSdcResponse.java +++ b/sdc-distribution-client/src/main/java/org/onap/sdc/http/HttpSdcResponse.java @@ -20,15 +20,15 @@ package org.onap.sdc.http; -import java.util.Map; - import org.apache.http.HttpEntity; +import org.onap.sdc.utils.CaseInsensitiveMap; + public class HttpSdcResponse { private int status; private HttpEntity message; - private Map headersMap; + private CaseInsensitiveMap headersMap; public HttpSdcResponse(int status, HttpEntity message) { super(); @@ -36,18 +36,18 @@ public class HttpSdcResponse { this.message = message; } - public HttpSdcResponse(int status, HttpEntity message, Map headersMap) { + public HttpSdcResponse(int status, HttpEntity message, CaseInsensitiveMap headersMap) { super(); this.status = status; this.message = message; this.headersMap = headersMap; } - public Map getHeadersMap() { + public CaseInsensitiveMap getHeadersMap() { return headersMap; } - public void setHeadersMap(Map headersMap) { + public void setHeadersMap(CaseInsensitiveMap headersMap) { this.headersMap = headersMap; } diff --git a/sdc-distribution-client/src/main/java/org/onap/sdc/http/IHttpSdcClient.java b/sdc-distribution-client/src/main/java/org/onap/sdc/http/IHttpSdcClient.java index 9adce23..3ea4795 100644 --- a/sdc-distribution-client/src/main/java/org/onap/sdc/http/IHttpSdcClient.java +++ b/sdc-distribution-client/src/main/java/org/onap/sdc/http/IHttpSdcClient.java @@ -20,15 +20,14 @@ package org.onap.sdc.http; -import java.util.Map; - +import org.onap.sdc.utils.CaseInsensitiveMap; import org.apache.http.HttpEntity; public interface IHttpSdcClient { - HttpSdcResponse postRequest(String requestUrl, HttpEntity entity, Map headersMap); + HttpSdcResponse postRequest(String requestUrl, HttpEntity entity, CaseInsensitiveMap headersMap); - HttpSdcResponse getRequest(String requestUrl, Map headersMap); + HttpSdcResponse getRequest(String requestUrl, CaseInsensitiveMap headersMap); void closeHttpClient(); diff --git a/sdc-distribution-client/src/main/java/org/onap/sdc/http/SdcConnectorClient.java b/sdc-distribution-client/src/main/java/org/onap/sdc/http/SdcConnectorClient.java index 18aba95..f96a9a8 100644 --- a/sdc-distribution-client/src/main/java/org/onap/sdc/http/SdcConnectorClient.java +++ b/sdc-distribution-client/src/main/java/org/onap/sdc/http/SdcConnectorClient.java @@ -29,9 +29,7 @@ import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Type; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.UUID; import org.apache.commons.io.IOUtils; @@ -50,6 +48,7 @@ import org.onap.sdc.utils.DistributionActionResultEnum; import org.onap.sdc.utils.DistributionClientConstants; import org.onap.sdc.utils.Pair; import org.onap.sdc.utils.kafka.KafkaDataResponse; +import org.onap.sdc.utils.CaseInsensitiveMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -116,7 +115,7 @@ public class SdcConnectorClient { private Pair performSdcServerRequest(String sdcUrl) { String requestId = generateRequestId(); - Map requestHeaders = addHeadersToHttpRequest(requestId); + CaseInsensitiveMap requestHeaders = addHeadersToHttpRequest(requestId); log.debug("about to perform get on SDC. requestId= {} url= {}", requestId, sdcUrl); return httpClient.getRequest(sdcUrl, requestHeaders, false); } @@ -129,7 +128,7 @@ public class SdcConnectorClient { DistributionClientDownloadResultImpl response; String requestId = generateRequestId(); - Map requestHeaders = new HashMap<>(); + CaseInsensitiveMap requestHeaders = new CaseInsensitiveMap<>(); requestHeaders.put(DistributionClientConstants.HEADER_REQUEST_ID, requestId); requestHeaders.put(DistributionClientConstants.HEADER_INSTANCE_ID, configuration.getConsumerID()); requestHeaders.put(HttpHeaders.ACCEPT, ContentType.APPLICATION_OCTET_STREAM.toString()); @@ -196,8 +195,8 @@ public class SdcConnectorClient { return result; } - protected Map addHeadersToHttpRequest(String requestId) { - Map requestHeaders = new HashMap<>(); + protected CaseInsensitiveMap addHeadersToHttpRequest(String requestId) { + CaseInsensitiveMap requestHeaders = new CaseInsensitiveMap<>(); requestHeaders.put(DistributionClientConstants.HEADER_REQUEST_ID, requestId); requestHeaders.put(DistributionClientConstants.HEADER_INSTANCE_ID, configuration.getConsumerID()); requestHeaders.put(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()); @@ -269,8 +268,8 @@ public class SdcConnectorClient { try { is = entity.getContent(); String artifactName = ""; - if (getServersResponse.getHeadersMap().containsKey(CONTENT_DISPOSITION_HEADER)) { - artifactName = getServersResponse.getHeadersMap().get(CONTENT_DISPOSITION_HEADER); + if (getServersResponse.getHeadersMap().containsCaseInsensitiveKey(CONTENT_DISPOSITION_HEADER)) { + artifactName = getServersResponse.getHeadersMap().getCaseInsensitiveKey(CONTENT_DISPOSITION_HEADER); } byte[] payload = IOUtils.toByteArray(is); diff --git a/sdc-distribution-client/src/main/java/org/onap/sdc/utils/CaseInsensitiveMap.java b/sdc-distribution-client/src/main/java/org/onap/sdc/utils/CaseInsensitiveMap.java new file mode 100644 index 0000000..efb1120 --- /dev/null +++ b/sdc-distribution-client/src/main/java/org/onap/sdc/utils/CaseInsensitiveMap.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * sdc-distribution-client + * ================================================================================ + * Copyright (C) 2023 Deutsche Telekom Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.utils; + +import java.util.HashMap; + +/** + * A custom map implementation that allows case-insensitive key checks + * + * This is used for response/request headers that can be transformed to + * lowercase by the ingress/envoy sidecar. + * HTTP headers are case-insensitive according to RFC 2616 + * + * @author mszwalkiewicz + */ +public class CaseInsensitiveMap extends HashMap { + + public boolean containsCaseInsensitiveKey(String key) { + for (K existingKey : keySet()) { + if (existingKey.toString().equalsIgnoreCase(key)) { + return true; + } + } + return false; + } + + public V getCaseInsensitiveKey(String key) { + for (K existingKey : keySet()) { + if (existingKey.toString().equalsIgnoreCase(key)) { + return super.get(existingKey); + } + } + return null; + } +} diff --git a/sdc-distribution-client/src/test/java/org/onap/sdc/http/HttpAsdcClientTest.java b/sdc-distribution-client/src/test/java/org/onap/sdc/http/HttpAsdcClientTest.java index cbd12c3..6193e4c 100644 --- a/sdc-distribution-client/src/test/java/org/onap/sdc/http/HttpAsdcClientTest.java +++ b/sdc-distribution-client/src/test/java/org/onap/sdc/http/HttpAsdcClientTest.java @@ -41,6 +41,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.onap.sdc.utils.Pair; import org.onap.sdc.utils.TestConfiguration; +import org.onap.sdc.utils.CaseInsensitiveMap; @ExtendWith(MockitoExtension.class) class HttpSdcClientTest { @@ -51,7 +52,7 @@ class HttpSdcClientTest { private static final String K_2 = "k2"; private static final String V_2 = "v2"; private static final Header[] HEADERS = new Header[]{new BasicHeader(K_1, V_1), new BasicHeader(K_2, V_2)}; - private static final HashMap HEADERS_MAP = new HashMap() {{ + private static final CaseInsensitiveMap HEADERS_MAP = new CaseInsensitiveMap() {{ put("key1", "key2"); }}; diff --git a/sdc-distribution-client/src/test/java/org/onap/sdc/http/HttpRequestFactoryTest.java b/sdc-distribution-client/src/test/java/org/onap/sdc/http/HttpRequestFactoryTest.java index c9eb4b3..a5404ae 100644 --- a/sdc-distribution-client/src/test/java/org/onap/sdc/http/HttpRequestFactoryTest.java +++ b/sdc-distribution-client/src/test/java/org/onap/sdc/http/HttpRequestFactoryTest.java @@ -25,12 +25,11 @@ import static org.mockito.Mockito.mock; import java.net.URI; import java.net.URISyntaxException; -import java.util.HashMap; -import java.util.Map; import org.apache.http.HttpEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.junit.jupiter.api.Test; +import org.onap.sdc.utils.CaseInsensitiveMap; class HttpRequestFactoryTest { @@ -40,7 +39,7 @@ class HttpRequestFactoryTest { private static final String HEADER_KEY_2 = "key2"; private static final String HEADER_VALUE_1 = "value1"; private static final String HEADER_VALUE_2 = "value2"; - private static final Map HEADERS = new HashMap() { + private static final CaseInsensitiveMap HEADERS = new CaseInsensitiveMap() { { put(HEADER_KEY_1, HEADER_VALUE_1); put(HEADER_KEY_2, HEADER_VALUE_2); diff --git a/sdc-distribution-client/src/test/java/org/onap/sdc/http/SdcConnectorClientTest.java b/sdc-distribution-client/src/test/java/org/onap/sdc/http/SdcConnectorClientTest.java index 61b8388..e449c4c 100644 --- a/sdc-distribution-client/src/test/java/org/onap/sdc/http/SdcConnectorClientTest.java +++ b/sdc-distribution-client/src/test/java/org/onap/sdc/http/SdcConnectorClientTest.java @@ -38,7 +38,6 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; -import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.http.HttpEntity; @@ -54,6 +53,7 @@ import org.onap.sdc.api.results.IDistributionClientResult; import org.onap.sdc.utils.DistributionActionResultEnum; import org.onap.sdc.utils.Pair; import org.onap.sdc.utils.kafka.KafkaDataResponse; +import org.onap.sdc.utils.CaseInsensitiveMap; public class SdcConnectorClientTest { @@ -61,7 +61,7 @@ public class SdcConnectorClientTest { private static final HttpSdcClient httpClient = mock(HttpSdcClient.class); private static final IConfiguration configuration = mock(IConfiguration.class); private static final HttpSdcResponse httpSdcResponse = mock(HttpSdcResponse.class); - private static final Map mockHeaders = new HashMap<>(); + private static final Map mockHeaders = new CaseInsensitiveMap<>(); private static SdcConnectorClient sdcClient; private static final String ARTIFACT_URL = "http://127.0.0.1/artifact/url"; @@ -219,7 +219,7 @@ public class SdcConnectorClientTest { @Test public void downloadArtifactHappyScenarioTest() throws IOException { - Map headers = new HashMap<>(); + CaseInsensitiveMap headers = new CaseInsensitiveMap<>(); headers.put(SdcConnectorClient.CONTENT_DISPOSITION_HEADER, "SomeHeader"); IArtifactInfo artifactInfo = mock(IArtifactInfo.class); @@ -242,6 +242,9 @@ public class SdcConnectorClientTest { @Test public void downloadArtifactDataIntegrityProblemTest() throws IOException { + CaseInsensitiveMap headers = new CaseInsensitiveMap<>(); + headers.put(SdcConnectorClient.CONTENT_DISPOSITION_HEADER, "SomeHeader"); + IArtifactInfo artifactInfo = mock(IArtifactInfo.class); when(artifactInfo.getArtifactURL()).thenReturn(ARTIFACT_URL); @@ -251,6 +254,7 @@ public class SdcConnectorClientTest { when(responseMock.getStatus()).thenReturn(HttpStatus.SC_OK); when(responseMock.getMessage()).thenReturn(messageMock); + when(responseMock.getHeadersMap()).thenReturn(headers); when(messageMock.getContent()).thenReturn(new ByteArrayInputStream(BYTES)); doReturn(responsePair).when(httpClient).getRequest(eq(ARTIFACT_URL), any(), eq(false)); @@ -260,6 +264,9 @@ public class SdcConnectorClientTest { @Test public void downloadArtifactExceptionDuringDownloadHandlingTest() throws IOException { + CaseInsensitiveMap headers = new CaseInsensitiveMap<>(); + headers.put(SdcConnectorClient.CONTENT_DISPOSITION_HEADER, "SomeHeader"); + IArtifactInfo artifactInfo = mock(IArtifactInfo.class); when(artifactInfo.getArtifactURL()).thenReturn(ARTIFACT_URL); @@ -269,6 +276,7 @@ public class SdcConnectorClientTest { when(responseMock.getStatus()).thenReturn(HttpStatus.SC_OK); when(responseMock.getMessage()).thenReturn(messageMock); + when(responseMock.getHeadersMap()).thenReturn(headers); when(messageMock.getContent()).thenReturn(new ThrowingInputStreamForTesting()); doReturn(responsePair).when(httpClient).getRequest(eq(ARTIFACT_URL), any(), eq(false)); -- cgit 1.2.3-korg