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%
|
||||
*/
|
||||
import java.io.*;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
@ -104,7 +105,7 @@ public class JaxRsResponse extends RestfulResponse<JaxRsRequest> {
|
|||
|
||||
private ResponseBuilder buildResponse(int 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());
|
||||
}
|
||||
return response;
|
||||
|
|
|
@ -21,9 +21,7 @@ package ca.uhn.fhir.rest.server;
|
|||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.*;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
|
||||
|
@ -35,7 +33,7 @@ public abstract class RestfulResponse<T extends RequestDetails> implements IRest
|
|||
|
||||
private IIdType myOperationResourceId;
|
||||
private IPrimitiveType<Date> myOperationResourceLastUpdated;
|
||||
private ConcurrentHashMap<String, String> theHeaders = new ConcurrentHashMap<String, String>();
|
||||
private Map<String, List<String>> theHeaders = new HashMap<>();
|
||||
private T theRequestDetails;
|
||||
|
||||
public RestfulResponse(T requestDetails) {
|
||||
|
@ -44,14 +42,14 @@ public abstract class RestfulResponse<T extends RequestDetails> implements IRest
|
|||
|
||||
@Override
|
||||
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
|
||||
* @return the headers
|
||||
*/
|
||||
public ConcurrentHashMap<String, String> getHeaders() {
|
||||
public Map<String, List<String>> getHeaders() {
|
||||
return theHeaders;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.io.IOException;
|
|||
import java.io.OutputStreamWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.io.Writer;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
|
@ -75,8 +76,18 @@ public class ServletRestfulResponse extends RestfulResponse<ServletRequestDetail
|
|||
private void addHeaders() {
|
||||
HttpServletResponse theHttpResponse = getRequestDetails().getServletResponse();
|
||||
getRequestDetails().getServer().addHeadersToResponse(theHttpResponse);
|
||||
for (Entry<String, String> header : getHeaders().entrySet()) {
|
||||
theHttpResponse.setHeader(header.getKey(), header.getValue());
|
||||
for (Entry<String, List<String>> header : getHeaders().entrySet()) {
|
||||
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