Retain X-Request-ID header key casing in responses (#5787)

* failing test

* fix

* changelog

* spotless

* fix tests
This commit is contained in:
Nathan Doef 2024-03-20 12:08:05 -04:00 committed by GitHub
parent d6bc8f2e1b
commit 7742aa76c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 55 additions and 6 deletions

View File

@ -0,0 +1,6 @@
---
type: fix
issue: 5788
title: "Previously, the casing of the X-Request-ID header key was not retained in the corresponding response.
This has been fixed."

View File

@ -7,6 +7,7 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException; import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.util.ExtensionConstants; import ca.uhn.fhir.util.ExtensionConstants;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.hl7.fhir.r4.model.CapabilityStatement; import org.hl7.fhir.r4.model.CapabilityStatement;
@ -15,11 +16,15 @@ import org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestResource
import org.hl7.fhir.r4.model.Extension; import org.hl7.fhir.r4.model.Extension;
import org.hl7.fhir.r4.model.Patient; import org.hl7.fhir.r4.model.Patient;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -141,4 +146,26 @@ public class ServerR4Test extends BaseResourceProviderR4Test {
} }
@ParameterizedTest
@ValueSource(strings = {"x-request-id", "X-Request-Id", "X-Request-ID", "X-REQUEST-ID"})
public void testXRequestIdHeaderRetainsCase(String theXRequestIdHeaderKey) throws Exception {
HttpGet get = new HttpGet(myServerBase + "/Patient");
String xRequestIdHeaderValue = "abc123";
get.addHeader(theXRequestIdHeaderKey, xRequestIdHeaderValue);
try (CloseableHttpResponse response = ourHttpClient.execute(get)) {
assertEquals(200, response.getStatusLine().getStatusCode());
String responseContent = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
ourLog.debug(responseContent);
List<Header> xRequestIdHeaders = Arrays.stream(response.getAllHeaders())
.filter(header -> theXRequestIdHeaderKey.equals(header.getName()))
.toList();
assertEquals(1, xRequestIdHeaders.size());
assertEquals(xRequestIdHeaderValue, xRequestIdHeaders.get(0).getValue());
}
}
} }

View File

@ -1325,7 +1325,14 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
} }
protected void addRequestIdToResponse(ServletRequestDetails theRequestDetails, String theRequestId) { protected void addRequestIdToResponse(ServletRequestDetails theRequestDetails, String theRequestId) {
theRequestDetails.getResponse().addHeader(Constants.HEADER_REQUEST_ID, theRequestId); String caseSensitiveRequestIdKey = Constants.HEADER_REQUEST_ID;
for (String key : theRequestDetails.getHeaders().keySet()) {
if (Constants.HEADER_REQUEST_ID.equalsIgnoreCase(key)) {
caseSensitiveRequestIdKey = key;
break;
}
}
theRequestDetails.getResponse().addHeader(caseSensitiveRequestIdKey, theRequestId);
} }
/** /**

View File

@ -9,6 +9,11 @@ import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.test.utilities.HttpClientExtension; import ca.uhn.fhir.test.utilities.HttpClientExtension;
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension; import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
import com.helger.commons.collection.iterate.EmptyEnumeration; import com.helger.commons.collection.iterate.EmptyEnumeration;
import jakarta.annotation.Nonnull;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.collections4.iterators.IteratorEnumeration; import org.apache.commons.collections4.iterators.IteratorEnumeration;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.IdType;
@ -23,11 +28,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import jakarta.annotation.Nonnull;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
@ -36,7 +36,9 @@ import java.io.PrintWriter;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Set;
import static org.apache.commons.collections.CollectionUtils.isEmpty;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.doThrow;
@ -109,6 +111,13 @@ public class ServerConcurrencyTest {
} }
return new EmptyEnumeration<>(); return new EmptyEnumeration<>();
}); });
when(myRequest.getHeaderNames()).thenAnswer(t -> {
Set<String> headerNames = myHeaders.keySet();
if (!isEmpty(headerNames)){
return new IteratorEnumeration<>(headerNames.iterator());
}
return new EmptyEnumeration<>();
});
} }
/** /**