Multiple values for one HTTP header were reduced to the last value.
This commit is contained in:
parent
92936d6889
commit
20f5df6657
|
@ -22,6 +22,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
|
@ -104,7 +105,7 @@ public class JaxRsResponse extends RestfulResponse<JaxRsRequest> {
|
||||||
|
|
||||||
private ResponseBuilder buildResponse(int statusCode) {
|
private ResponseBuilder buildResponse(int statusCode) {
|
||||||
ResponseBuilder response = Response.status(statusCode);
|
ResponseBuilder response = Response.status(statusCode);
|
||||||
for (Entry<String, String> header : getHeaders().entrySet()) {
|
for (Entry<String, List<String>> header : getHeaders().entrySet()) {
|
||||||
response.header(header.getKey(), header.getValue());
|
response.header(header.getKey(), header.getValue());
|
||||||
}
|
}
|
||||||
return response;
|
return response;
|
||||||
|
|
|
@ -21,9 +21,7 @@ package ca.uhn.fhir.rest.server;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Date;
|
import java.util.*;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
import org.hl7.fhir.instance.model.api.*;
|
import org.hl7.fhir.instance.model.api.*;
|
||||||
|
|
||||||
|
@ -35,7 +33,7 @@ public abstract class RestfulResponse<T extends RequestDetails> implements IRest
|
||||||
|
|
||||||
private IIdType myOperationResourceId;
|
private IIdType myOperationResourceId;
|
||||||
private IPrimitiveType<Date> myOperationResourceLastUpdated;
|
private IPrimitiveType<Date> myOperationResourceLastUpdated;
|
||||||
private ConcurrentHashMap<String, String> theHeaders = new ConcurrentHashMap<String, String>();
|
private Map<String, List<String>> theHeaders = new HashMap<>();
|
||||||
private T theRequestDetails;
|
private T theRequestDetails;
|
||||||
|
|
||||||
public RestfulResponse(T requestDetails) {
|
public RestfulResponse(T requestDetails) {
|
||||||
|
@ -44,14 +42,14 @@ public abstract class RestfulResponse<T extends RequestDetails> implements IRest
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addHeader(String headerKey, String headerValue) {
|
public void addHeader(String headerKey, String headerValue) {
|
||||||
this.getHeaders().put(headerKey, headerValue);
|
this.getHeaders().computeIfAbsent(headerKey, k -> new ArrayList<>()).add(headerValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the http headers
|
* Get the http headers
|
||||||
* @return the headers
|
* @return the headers
|
||||||
*/
|
*/
|
||||||
public ConcurrentHashMap<String, String> getHeaders() {
|
public Map<String, List<String>> getHeaders() {
|
||||||
return theHeaders;
|
return theHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.io.IOException;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.zip.GZIPOutputStream;
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
|
@ -75,8 +76,18 @@ public class ServletRestfulResponse extends RestfulResponse<ServletRequestDetail
|
||||||
private void addHeaders() {
|
private void addHeaders() {
|
||||||
HttpServletResponse theHttpResponse = getRequestDetails().getServletResponse();
|
HttpServletResponse theHttpResponse = getRequestDetails().getServletResponse();
|
||||||
getRequestDetails().getServer().addHeadersToResponse(theHttpResponse);
|
getRequestDetails().getServer().addHeadersToResponse(theHttpResponse);
|
||||||
for (Entry<String, String> header : getHeaders().entrySet()) {
|
for (Entry<String, List<String>> header : getHeaders().entrySet()) {
|
||||||
theHttpResponse.setHeader(header.getKey(), header.getValue());
|
final String key = header.getKey();
|
||||||
|
boolean first = true;
|
||||||
|
for (String value : header.getValue()) {
|
||||||
|
// existing headers should be overridden
|
||||||
|
if (first) {
|
||||||
|
theHttpResponse.setHeader(key, value);
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
theHttpResponse.addHeader(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
package ca.uhn.fhir.rest.server;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.MockSettings;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.mockito.Mockito.CALLS_REAL_METHODS;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.withSettings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests of {@link RestfulResponse}.
|
||||||
|
*/
|
||||||
|
public class RestfulResponseTest {
|
||||||
|
@Test
|
||||||
|
public void addMultipleHeaderValues() {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
final RestfulResponse<?> restfulResponse =
|
||||||
|
mock(RestfulResponse.class, withSettings()
|
||||||
|
.useConstructor((RequestDetails) null).defaultAnswer(CALLS_REAL_METHODS));
|
||||||
|
|
||||||
|
restfulResponse.addHeader("Authorization", "Basic");
|
||||||
|
restfulResponse.addHeader("Authorization", "Bearer");
|
||||||
|
restfulResponse.addHeader("Cache-Control", "no-cache, no-store");
|
||||||
|
|
||||||
|
assertEquals(2, restfulResponse.getHeaders().size());
|
||||||
|
assertThat(restfulResponse.getHeaders().get("Authorization"), Matchers.contains("Basic", "Bearer"));
|
||||||
|
assertThat(restfulResponse.getHeaders().get("Cache-Control"), Matchers.contains("no-cache, no-store"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package ca.uhn.fhir.rest.server.servlet;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.InOrder;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.junit.MockitoJUnit;
|
||||||
|
import org.mockito.junit.MockitoRule;
|
||||||
|
|
||||||
|
import javax.servlet.ServletOutputStream;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests of {@link ServletRestfulResponse}.
|
||||||
|
*/
|
||||||
|
public class ServletRestfulResponseTest {
|
||||||
|
@Mock
|
||||||
|
private RestfulServer server;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ServletOutputStream servletOutputStream;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private HttpServletResponse servletResponse;
|
||||||
|
|
||||||
|
private ServletRequestDetails requestDetails;
|
||||||
|
|
||||||
|
private ServletRestfulResponse response;
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public MockitoRule mockitoRule = MockitoJUnit.rule();
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() throws IOException {
|
||||||
|
Mockito.when(servletResponse.getOutputStream()).thenReturn(servletOutputStream);
|
||||||
|
|
||||||
|
requestDetails = new ServletRequestDetails();
|
||||||
|
requestDetails.setServer(server);
|
||||||
|
requestDetails.setServletResponse(servletResponse);
|
||||||
|
response = new ServletRestfulResponse(requestDetails);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addMultipleHeaderValues() throws IOException {
|
||||||
|
final ServletRestfulResponse response = new ServletRestfulResponse(requestDetails);
|
||||||
|
response.addHeader("Authorization", "Basic");
|
||||||
|
response.addHeader("Authorization", "Bearer");
|
||||||
|
response.addHeader("Cache-Control", "no-cache, no-store");
|
||||||
|
|
||||||
|
response.getResponseWriter(200, "Status", "text/plain", "UTF-8", false);
|
||||||
|
|
||||||
|
final InOrder orderVerifier = Mockito.inOrder(servletResponse);
|
||||||
|
orderVerifier.verify(servletResponse).setHeader(eq("Authorization"), eq("Basic"));
|
||||||
|
orderVerifier.verify(servletResponse).addHeader(eq("Authorization"), eq("Bearer"));
|
||||||
|
verify(servletResponse).setHeader(eq("Cache-Control"), eq("no-cache, no-store"));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue