Respect server default encoding if an Accept header is received which

indicates equal weight for both encodings
This commit is contained in:
James Agnew 2015-09-24 17:52:52 -04:00
parent 291fd21836
commit 1361e69177
10 changed files with 84 additions and 22 deletions

View File

@ -245,7 +245,7 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Obje
Set<SummaryEnum> summaryMode = RestfulServerUtils.determineSummaryMode(theRequest);
// Determine response encoding
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequest.getServletRequest());
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequest.getServletRequest(), theServer.getDefaultResponseEncoding());
// Is this request coming from a browser
String uaHeader = theRequest.getServletRequest().getHeader("user-agent");

View File

@ -54,7 +54,7 @@ public class Constants {
public static final String FORMAT_XML = "xml";
public static final String HEADER_ACCEPT = "Accept";
public static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
public static final String HEADER_ACCEPT_VALUE_ALL = CT_FHIR_XML + ";q=1.0, " + CT_FHIR_XML + ";q=1.0";
public static final String HEADER_ACCEPT_VALUE_ALL = CT_FHIR_XML + ";q=1.0, " + CT_FHIR_JSON + ";q=1.0";
public static final String HEADER_ALLOW = "Allow";
public static final String HEADER_AUTHORIZATION = "Authorization";
public static final String HEADER_AUTHORIZATION_VALPREFIX_BASIC = "Basic ";

View File

@ -491,7 +491,7 @@ public class RestfulServer extends HttpServlet {
int start = Math.min(offsetI, resultList.size() - 1);
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequest.getServletRequest());
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequest.getServletRequest(), getDefaultResponseEncoding());
boolean prettyPrint = RestfulServerUtils.prettyPrintResponse(this, theRequest);
boolean requestIsBrowser = requestIsBrowser(theRequest.getServletRequest());
Set<SummaryEnum> summaryMode = RestfulServerUtils.determineSummaryMode(theRequest);

View File

@ -214,7 +214,11 @@ public class RestfulServerUtils {
return retVal;
}
public static EncodingEnum determineResponseEncodingNoDefault(HttpServletRequest theReq) {
/**
* Returns null if the request doesn't express that it wants FHIR. If it expresses that it wants
* XML and JSON equally, returns thePrefer.
*/
public static EncodingEnum determineResponseEncodingNoDefault(HttpServletRequest theReq, EncodingEnum thePrefer) {
String[] format = theReq.getParameterValues(Constants.PARAM_FORMAT);
if (format != null) {
for (String nextFormat : format) {
@ -257,9 +261,11 @@ public class RestfulServerUtils {
}
}
if (q > bestQ && encoding != null) {
retVal = encoding;
bestQ = q;
if (encoding != null) {
if (q > bestQ || (q == bestQ && encoding == thePrefer)) {
retVal = encoding;
bestQ = q;
}
}
if (!",".equals(m.group(5))) {
@ -278,7 +284,7 @@ public class RestfulServerUtils {
* Determine whether a response should be given in JSON or XML format based on the incoming HttpServletRequest's <code>"_format"</code> parameter and <code>"Accept:"</code> HTTP header.
*/
public static EncodingEnum determineResponseEncodingWithDefault(RestfulServer theServer, HttpServletRequest theReq) {
EncodingEnum retVal = determineResponseEncodingNoDefault(theReq);
EncodingEnum retVal = determineResponseEncodingNoDefault(theReq, theServer.getDefaultResponseEncoding());
if (retVal == null) {
retVal = theServer.getDefaultResponseEncoding();
}
@ -328,10 +334,7 @@ public class RestfulServerUtils {
public static IParser getNewParser(FhirContext theContext, RequestDetails theRequestDetails) {
// Determine response encoding
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequestDetails.getServletRequest());
if (responseEncoding == null) {
responseEncoding = theRequestDetails.getServer().getDefaultResponseEncoding();
}
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingWithDefault(theRequestDetails.getServer(), theRequestDetails.getServletRequest());
IParser parser;
switch (responseEncoding) {
case JSON:
@ -472,8 +475,7 @@ public class RestfulServerUtils {
theHttpResponse.setStatus(200);
// Determine response encoding
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequestDetails.getServletRequest());
responseEncoding = responseEncoding != null ? responseEncoding : theServer.getDefaultResponseEncoding();
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingWithDefault(theServer, theRequestDetails.getServletRequest());
if (theRequestIsBrowser && theServer.isUseBrowserFriendlyContentTypes()) {
theHttpResponse.setContentType(responseEncoding.getBrowserFriendlyBundleContentType());
@ -502,7 +504,7 @@ public class RestfulServerUtils {
theHttpResponse.setStatus(stausCode);
// Determine response encoding
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequestDetails.getServletRequest());
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequestDetails.getServletRequest(), theServer.getDefaultResponseEncoding());
String serverBase = theRequestDetails.getFhirServerBase();
if (theAddContentLocationHeader && theResource.getIdElement() != null && theResource.getIdElement().hasIdPart() && isNotBlank(serverBase)) {

View File

@ -198,7 +198,7 @@ public class LoggingInterceptor extends InterceptorAdapter {
} else if (theKey.startsWith("remoteAddr")) {
return StringUtils.defaultString(myRequest.getRemoteAddr());
} else if (theKey.equals("responseEncodingNoDefault")) {
EncodingEnum encoding = RestfulServerUtils.determineResponseEncodingNoDefault(myRequest);
EncodingEnum encoding = RestfulServerUtils.determineResponseEncodingNoDefault(myRequest, myRequestDetails.getServer().getDefaultResponseEncoding());
if (encoding != null) {
return encoding.name();
} else {

View File

@ -1,7 +1,5 @@
package ca.uhn.fhirtest;
import java.sql.DriverManager;
import org.apache.derby.drda.NetworkServerControl;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

View File

@ -18,7 +18,7 @@
<util:list id="myServerInterceptors">
<ref bean="myLoggingInterceptor"/>
<ref bean="mySubscriptionSecurityInterceptor"/>
<!-- <ref bean="mySubscriptionSecurityInterceptor"/> -->
</util:list>
<!--
@ -44,7 +44,9 @@
<bean id="dbServer" class="ca.uhn.fhirtest.DerbyNetworkServer">
</bean>
<!--
<bean id="mySubscriptionSecurityInterceptor" class="ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptor"/>
-->
<!--
Do some fancy logging to create a nice access log that has details

View File

@ -36,9 +36,6 @@ import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.util.PortUtil;
/**
* Created by dsotnikov on 2/25/2014.
*/
public class DefaultEncodingTest {
private static CloseableHttpClient ourClient;
@ -47,6 +44,59 @@ public class DefaultEncodingTest {
private static final FhirContext ourCtx = FhirContext.forDstu1();
private static RestfulServer ourRestfulServer;
@Test
public void testHonoursAcceptHeader() throws Exception {
ourRestfulServer.setDefaultPrettyPrint(false);
ourRestfulServer.setDefaultResponseEncoding(EncodingEnum.JSON);
HttpGet httpGet;
HttpResponse status;
String responseContent;
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
httpGet.addHeader("Accept", "application/json");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertThat(responseContent, containsString("\"identifier\":"));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
httpGet.addHeader("Accept", "application/json+fhir");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertThat(responseContent, containsString("\"identifier\":"));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
httpGet.addHeader("Accept", "application/json+fhir, application/xml+fhir");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertThat(responseContent, containsString("\"identifier\":"));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
httpGet.addHeader("Accept", "application/xml+fhir, application/json+fhir");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertThat(responseContent, containsString("\"identifier\":"));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
httpGet.addHeader("Accept", "application/xml+fhir; q=0.9, application/json+fhir; q=1.0");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertThat(responseContent, containsString("\"identifier\":"));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
httpGet.addHeader("Accept", "application/xml+fhir; q=1.0, application/json+fhir; q=0.9");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertThat(responseContent, not(containsString("\"identifier\":")));
}
@Test
public void testReadWithDefaultJsonPretty() throws Exception {
ourRestfulServer.setDefaultPrettyPrint(true);

View File

@ -220,9 +220,11 @@ public class GenericClientDstu2Test {
assertEquals("http://"+methodName+".example.com/fhir/metadata?_format=json", capt.getAllValues().get(0).getURI().toASCIIString());
assertEquals(1, capt.getAllValues().get(0).getHeaders("Accept").length);
assertThat(capt.getAllValues().get(0).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_JSON));
assertThat(capt.getAllValues().get(0).getHeaders("Accept")[0].getValue(), not(containsString(Constants.CT_FHIR_XML)));
assertEquals("http://"+methodName+".example.com/fhir/Patient/123?_format=json", capt.getAllValues().get(1).getURI().toASCIIString());
assertEquals(1, capt.getAllValues().get(1).getHeaders("Accept").length);
assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_JSON));
assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), not(containsString(Constants.CT_FHIR_XML)));
}
@Test
@ -259,9 +261,13 @@ public class GenericClientDstu2Test {
assertEquals("http://"+methodName+".example.com/fhir/metadata", capt.getAllValues().get(0).getURI().toASCIIString());
assertEquals(1, capt.getAllValues().get(0).getHeaders("Accept").length);
assertThat(capt.getAllValues().get(0).getHeaders("Accept")[0].getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_ALL));
assertThat(capt.getAllValues().get(0).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_XML));
assertThat(capt.getAllValues().get(0).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_JSON));
assertEquals("http://"+methodName+".example.com/fhir/Patient/123", capt.getAllValues().get(1).getURI().toASCIIString());
assertEquals(1, capt.getAllValues().get(1).getHeaders("Accept").length);
assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_ALL));
assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_XML));
assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_JSON));
}

View File

@ -66,6 +66,10 @@
to a resource that is not valid in the location it is found in (e.g. points to Patient/123 but
the field supposed to reference an Organization). Thanks to Bill de Beaubien for reporting!
</action>
<action type="fix">
In server, if a client request is received and it has an Accept header indicating
that it supports both XML and JSON with equal weight, the server's default is used instead of the first entry in the list.
</action>
</release>
<release version="1.2" date="2015-09-18">
<action type="add">