Fix #837 - Use non-legacy content-type for plain json and xml accept

header
This commit is contained in:
jamesagnew 2018-02-02 06:43:19 -05:00
parent ad8eb0b939
commit 351a2fc2f1
5 changed files with 291 additions and 243 deletions

View File

@ -19,12 +19,14 @@ package ca.uhn.fhir.rest.api;
* limitations under the License. * limitations under the License.
* #L% * #L%
*/ */
import java.util.*;
import org.apache.commons.lang3.ObjectUtils;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import org.apache.commons.lang3.ObjectUtils;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public enum EncodingEnum { public enum EncodingEnum {
@ -40,39 +42,40 @@ public enum EncodingEnum {
public IParser newParser(FhirContext theContext) { public IParser newParser(FhirContext theContext) {
return theContext.newXmlParser(); return theContext.newXmlParser();
} }
} };
; /**
* "json"
/** "json" */ */
public static final String JSON_PLAIN_STRING = "json"; public static final String JSON_PLAIN_STRING = "json";
private static Map<String, EncodingEnum> ourContentTypeToEncoding; /**
* "xml"
private static Map<String, EncodingEnum> ourContentTypeToEncodingNonLegacy; */
private static Map<String, EncodingEnum> ourContentTypeToEncodingStrict;
/** "xml" */
public static final String XML_PLAIN_STRING = "xml"; public static final String XML_PLAIN_STRING = "xml";
private static Map<String, EncodingEnum> ourContentTypeToEncoding;
private static Map<String, EncodingEnum> ourContentTypeToEncodingLegacy;
private static Map<String, EncodingEnum> ourContentTypeToEncodingStrict;
static { static {
ourContentTypeToEncoding = new HashMap<String, EncodingEnum>(); ourContentTypeToEncoding = new HashMap<>();
ourContentTypeToEncodingNonLegacy = new HashMap<String, EncodingEnum>(); ourContentTypeToEncodingLegacy = new HashMap<>();
for (EncodingEnum next : values()) { for (EncodingEnum next : values()) {
ourContentTypeToEncoding.put(next.myResourceContentTypeNonLegacy, next); ourContentTypeToEncoding.put(next.myResourceContentTypeNonLegacy, next);
ourContentTypeToEncoding.put(next.myResourceContentTypeLegacy, next); ourContentTypeToEncoding.put(next.myResourceContentTypeLegacy, next);
ourContentTypeToEncodingNonLegacy.put(next.myResourceContentTypeNonLegacy, next); ourContentTypeToEncodingLegacy.put(next.myResourceContentTypeLegacy, next);
/* /*
* See #346 * See #346
*/ */
ourContentTypeToEncoding.put(next.myResourceContentTypeNonLegacy.replace('+', ' '), next); ourContentTypeToEncoding.put(next.myResourceContentTypeNonLegacy.replace('+', ' '), next);
ourContentTypeToEncoding.put(next.myResourceContentTypeLegacy.replace('+', ' '), next); ourContentTypeToEncoding.put(next.myResourceContentTypeLegacy.replace('+', ' '), next);
ourContentTypeToEncodingNonLegacy.put(next.myResourceContentTypeNonLegacy.replace('+', ' '), next); ourContentTypeToEncodingLegacy.put(next.myResourceContentTypeLegacy.replace('+', ' '), next);
} }
// Add before we add the lenient ones // Add before we add the lenient ones
ourContentTypeToEncodingStrict = Collections.unmodifiableMap(new HashMap<String, EncodingEnum>(ourContentTypeToEncoding)); ourContentTypeToEncodingStrict = Collections.unmodifiableMap(new HashMap<>(ourContentTypeToEncoding));
/* /*
* These are wrong, but we add them just to be tolerant of other * These are wrong, but we add them just to be tolerant of other
@ -89,7 +92,7 @@ public enum EncodingEnum {
ourContentTypeToEncoding.put(JSON_PLAIN_STRING, JSON); ourContentTypeToEncoding.put(JSON_PLAIN_STRING, JSON);
ourContentTypeToEncoding.put(XML_PLAIN_STRING, XML); ourContentTypeToEncoding.put(XML_PLAIN_STRING, XML);
ourContentTypeToEncodingNonLegacy = Collections.unmodifiableMap(ourContentTypeToEncodingNonLegacy); ourContentTypeToEncodingLegacy = Collections.unmodifiableMap(ourContentTypeToEncodingLegacy);
} }
@ -107,10 +110,6 @@ public enum EncodingEnum {
return myFormatContentType; return myFormatContentType;
} }
public String getRequestContentType() {
return myFormatContentType;
}
/** /**
* Will return application/xml+fhir style * Will return application/xml+fhir style
*/ */
@ -167,14 +166,18 @@ public enum EncodingEnum {
* <p> * <p>
* <b>This method is NOT lenient!</b> Things like "application/xml" will return <code>null</code> * <b>This method is NOT lenient!</b> Things like "application/xml" will return <code>null</code>
* </p> * </p>
*
* @see #forContentType(String) * @see #forContentType(String)
*/ */
public static EncodingEnum forContentTypeStrict(String theContentType) { public static EncodingEnum forContentTypeStrict(String theContentType) {
return ourContentTypeToEncodingStrict.get(theContentType); return ourContentTypeToEncodingStrict.get(theContentType);
} }
public static boolean isNonLegacy(String theFormat) { /**
return ourContentTypeToEncodingNonLegacy.containsKey(theFormat); * Is the given type a FHIR legacy (pre-DSTU3) content type?
*/
public static boolean isLegacy(String theFormat) {
return ourContentTypeToEncodingLegacy.containsKey(theFormat);
} }

View File

@ -764,12 +764,11 @@ public class RestfulServerUtils {
super(); super();
myEncoding = theEncoding; myEncoding = theEncoding;
if (theContentType != null) { if (theContentType != null) {
FhirVersionEnum ctxtEnum = theCtx.getVersion().getVersion();
if (theContentType.equals(EncodingEnum.JSON_PLAIN_STRING) || theContentType.equals(EncodingEnum.XML_PLAIN_STRING)) { if (theContentType.equals(EncodingEnum.JSON_PLAIN_STRING) || theContentType.equals(EncodingEnum.XML_PLAIN_STRING)) {
FhirVersionEnum ctxtEnum = theCtx.getVersion().getVersion(); myNonLegacy = ctxtEnum.isNewerThan(FhirVersionEnum.DSTU2);
myNonLegacy = ctxtEnum.isNewerThan(FhirVersionEnum.DSTU3)
|| (ctxtEnum.isEquivalentTo(FhirVersionEnum.DSTU3) && !"1.4.0".equals(theCtx.getVersion().getVersion().getFhirVersionString()));
} else { } else {
myNonLegacy = EncodingEnum.isNonLegacy(theContentType); myNonLegacy = ctxtEnum.isNewerThan(FhirVersionEnum.DSTU2) && !EncodingEnum.isLegacy(theContentType);
} }
} else { } else {
FhirVersionEnum ctxtEnum = theCtx.getVersion().getVersion(); FhirVersionEnum ctxtEnum = theCtx.getVersion().getVersion();

View File

@ -1,18 +1,13 @@
package ca.uhn.fhir.rest.server; package ca.uhn.fhir.rest.server;
import static org.hamcrest.Matchers.contains; import ca.uhn.fhir.context.FhirContext;
import static org.hamcrest.Matchers.containsString; import ca.uhn.fhir.rest.annotation.*;
import static org.hamcrest.Matchers.not; import ca.uhn.fhir.rest.api.Constants;
import static org.junit.Assert.assertEquals; import ca.uhn.fhir.rest.api.EncodingEnum;
import static org.junit.Assert.assertThat; import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.client.MyPatientWithExtensions;
import java.io.IOException; import ca.uhn.fhir.util.PortUtil;
import java.net.URI; import ca.uhn.fhir.util.TestUtil;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.client.methods.*; import org.apache.http.client.methods.*;
@ -26,23 +21,45 @@ import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.*; import org.hl7.fhir.r4.model.*;
import org.junit.*; import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext; import java.io.IOException;
import ca.uhn.fhir.rest.annotation.*; import java.net.URI;
import ca.uhn.fhir.rest.api.Constants; import java.nio.charset.StandardCharsets;
import ca.uhn.fhir.rest.api.MethodOutcome; import java.util.ArrayList;
import ca.uhn.fhir.rest.client.MyPatientWithExtensions; import java.util.List;
import ca.uhn.fhir.util.PortUtil; import java.util.concurrent.TimeUnit;
import ca.uhn.fhir.util.TestUtil;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
public class ServerMimetypeR4Test { public class ServerMimetypeR4Test {
private static CloseableHttpClient ourClient;
private static FhirContext ourCtx = FhirContext.forR4();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerMimetypeR4Test.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerMimetypeR4Test.class);
private static CloseableHttpClient ourClient;
private static FhirContext ourCtx = FhirContext.forR4();
private static int ourPort; private static int ourPort;
private static Server ourServer; private static Server ourServer;
private static RestfulServer ourServlet;
@Before
public void before() {
ourServlet.setDefaultResponseEncoding(EncodingEnum.XML);
}
private String readAndReturnContentType(String theAccept) throws IOException {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
if (theAccept != null) {
httpGet.addHeader(Constants.HEADER_ACCEPT, theAccept);
}
HttpResponse status = ourClient.execute(httpGet);
String contentType = status.getEntity().getContentType().getValue();
IOUtils.closeQuietly(status.getEntity().getContent());
contentType = contentType.replaceAll(";.*", "");
return contentType;
}
@Test @Test
public void testConformanceMetadataUsesNewMimetypes() throws Exception { public void testConformanceMetadataUsesNewMimetypes() throws Exception {
@ -58,109 +75,6 @@ public class ServerMimetypeR4Test {
} }
} }
private List<String> toStrings(List<CodeType> theFormat) {
ArrayList<String> retVal = new ArrayList<String>();
for (CodeType next : theFormat) {
retVal.add(next.asStringValue());
}
return retVal;
}
@Test
public void testCreateWithXmlLegacyNoAcceptHeader() throws Exception {
Patient p = new Patient();
p.addName().setFamily("FAMILY");
String enc = ourCtx.newXmlParser().encodeResourceToString(p);
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
httpPost.setEntity(new StringEntity(enc, ContentType.parse(Constants.CT_FHIR_XML + "; charset=utf-8")));
HttpResponse status = ourClient.execute(httpPost);
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
assertEquals(201, status.getStatusLine().getStatusCode());
assertEquals(Constants.CT_FHIR_XML, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
assertEquals("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><issue><diagnostics value=\"FAMILY\"/></issue></OperationOutcome>", responseContent);
}
@Test
public void testHttpTraceNotEnabled() throws Exception {
HttpTrace req = new HttpTrace("http://localhost:" + ourPort + "/Patient");
CloseableHttpResponse status = ourClient.execute(req);
try {
ourLog.info(status.toString());
assertEquals(400, status.getStatusLine().getStatusCode());
} finally {
IOUtils.closeQuietly(status.getEntity().getContent());
}
}
@Test
public void testHttpTrackNotEnabled() throws Exception {
HttpRequestBase req = new HttpRequestBase() {
@Override
public String getMethod() {
return "TRACK";
}};
req.setURI(new URI("http://localhost:" + ourPort + "/Patient"));
CloseableHttpResponse status = ourClient.execute(req);
try {
ourLog.info(status.toString());
assertEquals(400, status.getStatusLine().getStatusCode());
} finally {
IOUtils.closeQuietly(status.getEntity().getContent());
}
}
@Test
public void testCreateWithXmlNewNoAcceptHeader() throws Exception {
Patient p = new Patient();
p.addName().setFamily("FAMILY");
String enc = ourCtx.newXmlParser().encodeResourceToString(p);
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
httpPost.setEntity(new StringEntity(enc, ContentType.parse(Constants.CT_FHIR_XML_NEW + "; charset=utf-8")));
HttpResponse status = ourClient.execute(httpPost);
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
assertEquals(201, status.getStatusLine().getStatusCode());
assertEquals(Constants.CT_FHIR_XML_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
assertEquals("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><issue><diagnostics value=\"FAMILY\"/></issue></OperationOutcome>", responseContent);
}
@Test
public void testCreateWithXmlNewWithAcceptHeader() throws Exception {
Patient p = new Patient();
p.addName().setFamily("FAMILY");
String enc = ourCtx.newXmlParser().encodeResourceToString(p);
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
httpPost.setEntity(new StringEntity(enc, ContentType.parse(Constants.CT_FHIR_XML + "; charset=utf-8")));
httpPost.addHeader(Constants.HEADER_ACCEPT, Constants.CT_FHIR_XML_NEW);
HttpResponse status = ourClient.execute(httpPost);
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
assertEquals(201, status.getStatusLine().getStatusCode());
assertEquals(Constants.CT_FHIR_XML_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
assertEquals("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><issue><diagnostics value=\"FAMILY\"/></issue></OperationOutcome>", responseContent);
}
@Test @Test
public void testCreateWithJsonLegacyNoAcceptHeader() throws Exception { public void testCreateWithJsonLegacyNoAcceptHeader() throws Exception {
Patient p = new Patient(); Patient p = new Patient();
@ -223,9 +137,147 @@ public class ServerMimetypeR4Test {
} }
@Test @Test
public void testSearchWithFormatXmlSimple() throws Exception { public void testCreateWithXmlLegacyNoAcceptHeader() throws Exception {
Patient p = new Patient();
p.addName().setFamily("FAMILY");
String enc = ourCtx.newXmlParser().encodeResourceToString(p);
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=xml"); HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
httpPost.setEntity(new StringEntity(enc, ContentType.parse(Constants.CT_FHIR_XML + "; charset=utf-8")));
HttpResponse status = ourClient.execute(httpPost);
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
assertEquals(201, status.getStatusLine().getStatusCode());
assertEquals(Constants.CT_FHIR_XML, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
assertEquals("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><issue><diagnostics value=\"FAMILY\"/></issue></OperationOutcome>", responseContent);
}
@Test
public void testCreateWithXmlNewNoAcceptHeader() throws Exception {
Patient p = new Patient();
p.addName().setFamily("FAMILY");
String enc = ourCtx.newXmlParser().encodeResourceToString(p);
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
httpPost.setEntity(new StringEntity(enc, ContentType.parse(Constants.CT_FHIR_XML_NEW + "; charset=utf-8")));
HttpResponse status = ourClient.execute(httpPost);
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
assertEquals(201, status.getStatusLine().getStatusCode());
assertEquals(Constants.CT_FHIR_XML_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
assertEquals("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><issue><diagnostics value=\"FAMILY\"/></issue></OperationOutcome>", responseContent);
}
@Test
public void testCreateWithXmlNewWithAcceptHeader() throws Exception {
Patient p = new Patient();
p.addName().setFamily("FAMILY");
String enc = ourCtx.newXmlParser().encodeResourceToString(p);
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
httpPost.setEntity(new StringEntity(enc, ContentType.parse(Constants.CT_FHIR_XML + "; charset=utf-8")));
httpPost.addHeader(Constants.HEADER_ACCEPT, Constants.CT_FHIR_XML_NEW);
HttpResponse status = ourClient.execute(httpPost);
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
assertEquals(201, status.getStatusLine().getStatusCode());
assertEquals(Constants.CT_FHIR_XML_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
assertEquals("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><issue><diagnostics value=\"FAMILY\"/></issue></OperationOutcome>", responseContent);
}
@Test
public void testHttpTraceNotEnabled() throws Exception {
HttpTrace req = new HttpTrace("http://localhost:" + ourPort + "/Patient");
CloseableHttpResponse status = ourClient.execute(req);
try {
ourLog.info(status.toString());
assertEquals(400, status.getStatusLine().getStatusCode());
} finally {
IOUtils.closeQuietly(status.getEntity().getContent());
}
}
@Test
public void testHttpTrackNotEnabled() throws Exception {
HttpRequestBase req = new HttpRequestBase() {
@Override
public String getMethod() {
return "TRACK";
}
};
req.setURI(new URI("http://localhost:" + ourPort + "/Patient"));
CloseableHttpResponse status = ourClient.execute(req);
try {
ourLog.info(status.toString());
assertEquals(400, status.getStatusLine().getStatusCode());
} finally {
IOUtils.closeQuietly(status.getEntity().getContent());
}
}
/**
* See #837
*/
@Test
public void testResponseContentTypesJson() throws IOException {
ourServlet.setDefaultResponseEncoding(EncodingEnum.XML);
// None given
assertEquals("application/fhir+xml", readAndReturnContentType(null));
// Legacy given
assertEquals("application/json+fhir", readAndReturnContentType("application/json+fhir"));
// Everything else JSON
assertEquals("application/fhir+json", readAndReturnContentType("application/fhir+json"));
assertEquals("application/fhir+json", readAndReturnContentType("application/json"));
assertEquals("application/fhir+json", readAndReturnContentType("application/fhir+json,application/json;q=0.9"));
assertEquals("application/fhir+json", readAndReturnContentType("json"));
// Invalid
assertEquals("application/fhir+xml", readAndReturnContentType("text/plain"));
}
/**
* See #837
*/
@Test
public void testResponseContentTypesXml() throws IOException {
ourServlet.setDefaultResponseEncoding(EncodingEnum.JSON);
// None given
assertEquals("application/fhir+json", readAndReturnContentType(null));
// Legacy given
assertEquals("application/xml+fhir", readAndReturnContentType("application/xml+fhir"));
// Everything else JSON
assertEquals("application/fhir+xml", readAndReturnContentType("application/fhir+xml"));
assertEquals("application/fhir+xml", readAndReturnContentType("application/xml"));
assertEquals("application/fhir+xml", readAndReturnContentType("application/fhir+xml,application/xml;q=0.9"));
assertEquals("application/fhir+xml", readAndReturnContentType("xml"));
// Invalid
assertEquals("application/fhir+json", readAndReturnContentType("text/plain"));
}
@Test
public void testSearchWithFormatJsonLegacy() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=" + Constants.CT_FHIR_JSON);
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
@ -234,9 +286,40 @@ public class ServerMimetypeR4Test {
ourLog.info("Response was:\n{}", responseContent); ourLog.info("Response was:\n{}", responseContent);
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("<Patient xmlns=\"http://hl7.org/fhir\">")); assertThat(responseContent, containsString("\"resourceType\""));
assertThat(responseContent, not(containsString("http://hl7.org/fhir/"))); assertEquals(Constants.CT_FHIR_JSON, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
assertEquals(Constants.CT_FHIR_XML_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", "")); }
@Test
public void testSearchWithFormatJsonNew() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=" + Constants.CT_FHIR_JSON_NEW);
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("\"resourceType\""));
assertEquals(Constants.CT_FHIR_JSON_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
}
@Test
public void testSearchWithFormatJsonSimple() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=json");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("\"resourceType\""));
assertEquals(Constants.CT_FHIR_JSON_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
} }
@Test @Test
@ -273,77 +356,29 @@ public class ServerMimetypeR4Test {
assertEquals(Constants.CT_FHIR_XML_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", "")); assertEquals(Constants.CT_FHIR_XML_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
} }
/**
* See #837
*/
@Test @Test
public void testResponseContentTypes() throws IOException { public void testSearchWithFormatXmlSimple() throws Exception {
assertEquals("application/fhir+json", readAndReturnContentType("application/fhir+json"));
assertEquals("application/fhir+xml", readAndReturnContentType(null)); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=xml");
assertEquals("application/json+fhir", readAndReturnContentType("application/json+fhir")); HttpResponse status = ourClient.execute(httpGet);
assertEquals("application/json+fhir", readAndReturnContentType("application/json"));
assertEquals("application/fhir+json", readAndReturnContentType("application/fhir+json,application/json;q=0.9")); String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("<Patient xmlns=\"http://hl7.org/fhir\">"));
assertThat(responseContent, not(containsString("http://hl7.org/fhir/")));
assertEquals(Constants.CT_FHIR_XML_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
} }
private String readAndReturnContentType(String theAccept) throws IOException { private List<String> toStrings(List<CodeType> theFormat) {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient"); ArrayList<String> retVal = new ArrayList<String>();
if (theAccept != null) { for (CodeType next : theFormat) {
httpGet.addHeader(Constants.HEADER_ACCEPT, theAccept); retVal.add(next.asStringValue());
} }
HttpResponse status = ourClient.execute(httpGet); return retVal;
String contentType = status.getEntity().getContentType().getValue();
IOUtils.closeQuietly(status.getEntity().getContent());
contentType = contentType.replaceAll(";.*","");
return contentType;
}
@Test
public void testSearchWithFormatJsonSimple() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=json");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("\"resourceType\""));
assertEquals(Constants.CT_FHIR_JSON_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
}
@Test
public void testSearchWithFormatJsonLegacy() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=" + Constants.CT_FHIR_JSON);
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("\"resourceType\""));
assertEquals(Constants.CT_FHIR_JSON, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
}
@Test
public void testSearchWithFormatJsonNew() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=" + Constants.CT_FHIR_JSON_NEW);
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("\"resourceType\""));
assertEquals(Constants.CT_FHIR_JSON_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
} }
@AfterClass @AfterClass
@ -360,10 +395,10 @@ public class ServerMimetypeR4Test {
PatientProvider patientProvider = new PatientProvider(); PatientProvider patientProvider = new PatientProvider();
ServletHandler proxyHandler = new ServletHandler(); ServletHandler proxyHandler = new ServletHandler();
RestfulServer servlet = new RestfulServer(ourCtx); ourServlet = new RestfulServer(ourCtx);
servlet.setResourceProviders(patientProvider); ourServlet.setResourceProviders(patientProvider);
ServletHolder servletHolder = new ServletHolder(servlet); ServletHolder servletHolder = new ServletHolder(ourServlet);
proxyHandler.addServletWithMapping(servletHolder, "/*"); proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler); ourServer.setHandler(proxyHandler);
ourServer.start(); ourServer.start();

View File

@ -334,7 +334,7 @@ public class Controller extends BaseController {
if (client.getEncoding() != null) { if (client.getEncoding() != null) {
clientCodeJsonWriter.name("format"); clientCodeJsonWriter.name("format");
clientCodeJsonWriter.value(client.getEncoding().getRequestContentType()); clientCodeJsonWriter.value(client.getEncoding().getFormatContentType());
} else { } else {
clientCodeJsonWriter.name("format"); clientCodeJsonWriter.name("format");
clientCodeJsonWriter.nullValue(); clientCodeJsonWriter.nullValue();

View File

@ -98,6 +98,17 @@
to build correctly on JDK 9.0. Currently building is supported on to build correctly on JDK 9.0. Currently building is supported on
JDK 8.x and 9.x only. JDK 8.x and 9.x only.
</action> </action>
<action type="fix" issue="837">
Client requests with an
<![CDATA[<code>Accept</code>]]>
header value of
<![CDATA[<code>application/json</code>]]>
will now be served with the non-legacy content type of
<![CDATA[<code>application/fhir+json</code>]]>
instead of the legacy
<![CDATA[<code>application/json+fhir</code>]]>.
Thanks to John Grimes for reporting!
</action>
</release> </release>
<release version="3.2.0" date="2018-01-13"> <release version="3.2.0" date="2018-01-13">
<action type="add"> <action type="add">