From 351a2fc2f143612d2f2a0ce36f9f89bbf40fbaa5 Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Fri, 2 Feb 2018 06:43:19 -0500 Subject: [PATCH] Fix #837 - Use non-legacy content-type for plain json and xml accept header --- .../ca/uhn/fhir/rest/api/EncodingEnum.java | 65 +-- .../fhir/rest/server/RestfulServerUtils.java | 7 +- .../rest/server/ServerMimetypeR4Test.java | 449 ++++++++++-------- .../main/java/ca/uhn/fhir/to/Controller.java | 2 +- src/changes/changes.xml | 11 + 5 files changed, 291 insertions(+), 243 deletions(-) diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/EncodingEnum.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/EncodingEnum.java index 8e82409d8a1..6b80981e725 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/EncodingEnum.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/EncodingEnum.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.rest.api; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -19,12 +19,14 @@ package ca.uhn.fhir.rest.api; * limitations under the License. * #L% */ -import java.util.*; - -import org.apache.commons.lang3.ObjectUtils; import ca.uhn.fhir.context.FhirContext; 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 { @@ -40,39 +42,40 @@ public enum EncodingEnum { public IParser newParser(FhirContext theContext) { return theContext.newXmlParser(); } - } + }; - ; - - /** "json" */ - public static final String JSON_PLAIN_STRING = "json"; - private static Map ourContentTypeToEncoding; - - private static Map ourContentTypeToEncodingNonLegacy; - private static Map ourContentTypeToEncodingStrict; - /** "xml" */ + /** + * "json" + */ + public static final String JSON_PLAIN_STRING = "json"; + /** + * "xml" + */ public static final String XML_PLAIN_STRING = "xml"; + private static Map ourContentTypeToEncoding; + private static Map ourContentTypeToEncodingLegacy; + private static Map ourContentTypeToEncodingStrict; static { - ourContentTypeToEncoding = new HashMap(); - ourContentTypeToEncodingNonLegacy = new HashMap(); - + ourContentTypeToEncoding = new HashMap<>(); + ourContentTypeToEncodingLegacy = new HashMap<>(); + for (EncodingEnum next : values()) { ourContentTypeToEncoding.put(next.myResourceContentTypeNonLegacy, next); ourContentTypeToEncoding.put(next.myResourceContentTypeLegacy, next); - ourContentTypeToEncodingNonLegacy.put(next.myResourceContentTypeNonLegacy, next); + ourContentTypeToEncodingLegacy.put(next.myResourceContentTypeLegacy, next); /* * See #346 */ ourContentTypeToEncoding.put(next.myResourceContentTypeNonLegacy.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 - ourContentTypeToEncodingStrict = Collections.unmodifiableMap(new HashMap(ourContentTypeToEncoding)); + ourContentTypeToEncodingStrict = Collections.unmodifiableMap(new HashMap<>(ourContentTypeToEncoding)); /* * 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(XML_PLAIN_STRING, XML); - ourContentTypeToEncodingNonLegacy = Collections.unmodifiableMap(ourContentTypeToEncodingNonLegacy); + ourContentTypeToEncodingLegacy = Collections.unmodifiableMap(ourContentTypeToEncodingLegacy); } @@ -107,10 +110,6 @@ public enum EncodingEnum { return myFormatContentType; } - public String getRequestContentType() { - return myFormatContentType; - } - /** * Will return application/xml+fhir style */ @@ -150,7 +149,7 @@ public enum EncodingEnum { /** * Returns the encoding for a given content type, or null if no encoding - * is found. + * is found. *

* This method is lenient! Things like "application/xml" will return {@link EncodingEnum#XML} * even if the "+fhir" part is missing from the expected content type. @@ -163,19 +162,23 @@ public enum EncodingEnum { /** * Returns the encoding for a given content type, or null if no encoding - * is found. + * is found. *

* This method is NOT lenient! Things like "application/xml" will return null *

+ * * @see #forContentType(String) */ public static EncodingEnum forContentTypeStrict(String 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); } - + } diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java index c79de493441..195ef56bc93 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java @@ -764,12 +764,11 @@ public class RestfulServerUtils { super(); myEncoding = theEncoding; if (theContentType != null) { + FhirVersionEnum ctxtEnum = theCtx.getVersion().getVersion(); if (theContentType.equals(EncodingEnum.JSON_PLAIN_STRING) || theContentType.equals(EncodingEnum.XML_PLAIN_STRING)) { - FhirVersionEnum ctxtEnum = theCtx.getVersion().getVersion(); - myNonLegacy = ctxtEnum.isNewerThan(FhirVersionEnum.DSTU3) - || (ctxtEnum.isEquivalentTo(FhirVersionEnum.DSTU3) && !"1.4.0".equals(theCtx.getVersion().getVersion().getFhirVersionString())); + myNonLegacy = ctxtEnum.isNewerThan(FhirVersionEnum.DSTU2); } else { - myNonLegacy = EncodingEnum.isNonLegacy(theContentType); + myNonLegacy = ctxtEnum.isNewerThan(FhirVersionEnum.DSTU2) && !EncodingEnum.isLegacy(theContentType); } } else { FhirVersionEnum ctxtEnum = theCtx.getVersion().getVersion(); diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/ServerMimetypeR4Test.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/ServerMimetypeR4Test.java index 6572bc3a3ed..98768af1279 100644 --- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/ServerMimetypeR4Test.java +++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/ServerMimetypeR4Test.java @@ -1,18 +1,13 @@ package ca.uhn.fhir.rest.server; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.not; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; - -import java.io.IOException; -import java.net.URI; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; - +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.rest.annotation.*; +import ca.uhn.fhir.rest.api.Constants; +import ca.uhn.fhir.rest.api.EncodingEnum; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.client.MyPatientWithExtensions; +import ca.uhn.fhir.util.PortUtil; +import ca.uhn.fhir.util.TestUtil; import org.apache.commons.io.IOUtils; import org.apache.http.HttpResponse; import org.apache.http.client.methods.*; @@ -26,23 +21,45 @@ import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.hl7.fhir.instance.model.api.IBaseResource; 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 ca.uhn.fhir.rest.annotation.*; -import ca.uhn.fhir.rest.api.Constants; -import ca.uhn.fhir.rest.api.MethodOutcome; -import ca.uhn.fhir.rest.client.MyPatientWithExtensions; -import ca.uhn.fhir.util.PortUtil; -import ca.uhn.fhir.util.TestUtil; +import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; 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 CloseableHttpClient ourClient; + private static FhirContext ourCtx = FhirContext.forR4(); private static int ourPort; 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 public void testConformanceMetadataUsesNewMimetypes() throws Exception { @@ -57,25 +74,74 @@ public class ServerMimetypeR4Test { status.close(); } } - - - - private List toStrings(List theFormat) { - ArrayList retVal = new ArrayList(); - for (CodeType next : theFormat) { - retVal.add(next.asStringValue()); - } - return retVal; + + @Test + public void testCreateWithJsonLegacyNoAcceptHeader() throws Exception { + Patient p = new Patient(); + p.addName().setFamily("FAMILY"); + String enc = ourCtx.newJsonParser().encodeResourceToString(p); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); + httpPost.setEntity(new StringEntity(enc, ContentType.parse(Constants.CT_FHIR_JSON + "; 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_JSON, status.getFirstHeader("content-type").getValue().replaceAll(";.*", "")); + assertEquals("{\"resourceType\":\"OperationOutcome\",\"issue\":[{\"diagnostics\":\"FAMILY\"}]}", responseContent); } + @Test + public void testCreateWithJsonNewNoAcceptHeader() throws Exception { + Patient p = new Patient(); + p.addName().setFamily("FAMILY"); + String enc = ourCtx.newJsonParser().encodeResourceToString(p); + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); + httpPost.setEntity(new StringEntity(enc, ContentType.parse(Constants.CT_FHIR_JSON_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_JSON_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", "")); + assertEquals("{\"resourceType\":\"OperationOutcome\",\"issue\":[{\"diagnostics\":\"FAMILY\"}]}", responseContent); + } + + @Test + public void testCreateWithJsonNewWithAcceptHeader() throws Exception { + Patient p = new Patient(); + p.addName().setFamily("FAMILY"); + String enc = ourCtx.newJsonParser().encodeResourceToString(p); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); + httpPost.setEntity(new StringEntity(enc, ContentType.parse(Constants.CT_FHIR_JSON + "; charset=utf-8"))); + httpPost.addHeader(Constants.HEADER_ACCEPT, Constants.CT_FHIR_JSON_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_JSON_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", "")); + assertEquals("{\"resourceType\":\"OperationOutcome\",\"issue\":[{\"diagnostics\":\"FAMILY\"}]}", responseContent); + } @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); @@ -90,6 +156,47 @@ public class ServerMimetypeR4Test { assertEquals("", 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("", 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("", responseContent); + } + @Test public void testHttpTraceNotEnabled() throws Exception { HttpTrace req = new HttpTrace("http://localhost:" + ourPort + "/Patient"); @@ -108,9 +215,10 @@ public class ServerMimetypeR4Test { @Override public String getMethod() { return "TRACK"; - }}; + } + }; req.setURI(new URI("http://localhost:" + ourPort + "/Patient")); - + CloseableHttpResponse status = ourClient.execute(req); try { ourLog.info(status.toString()); @@ -120,112 +228,56 @@ public class ServerMimetypeR4Test { } } + /** + * See #837 + */ @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); + public void testResponseContentTypesJson() throws IOException { + ourServlet.setDefaultResponseEncoding(EncodingEnum.XML); - String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); - IOUtils.closeQuietly(status.getEntity().getContent()); + // None given + assertEquals("application/fhir+xml", readAndReturnContentType(null)); - ourLog.info("Response was:\n{}", responseContent); + // Legacy given + assertEquals("application/json+fhir", readAndReturnContentType("application/json+fhir")); - assertEquals(201, status.getStatusLine().getStatusCode()); - assertEquals(Constants.CT_FHIR_XML_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", "")); - assertEquals("", responseContent); + // 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 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); + public void testSearchWithFormatJsonLegacy() throws Exception { - 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("", responseContent); - } - - @Test - public void testCreateWithJsonLegacyNoAcceptHeader() throws Exception { - Patient p = new Patient(); - p.addName().setFamily("FAMILY"); - String enc = ourCtx.newJsonParser().encodeResourceToString(p); - - HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); - httpPost.setEntity(new StringEntity(enc, ContentType.parse(Constants.CT_FHIR_JSON + "; 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_JSON, status.getFirstHeader("content-type").getValue().replaceAll(";.*", "")); - assertEquals("{\"resourceType\":\"OperationOutcome\",\"issue\":[{\"diagnostics\":\"FAMILY\"}]}", responseContent); - } - - @Test - public void testCreateWithJsonNewNoAcceptHeader() throws Exception { - Patient p = new Patient(); - p.addName().setFamily("FAMILY"); - String enc = ourCtx.newJsonParser().encodeResourceToString(p); - - HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); - httpPost.setEntity(new StringEntity(enc, ContentType.parse(Constants.CT_FHIR_JSON_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_JSON_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", "")); - assertEquals("{\"resourceType\":\"OperationOutcome\",\"issue\":[{\"diagnostics\":\"FAMILY\"}]}", responseContent); - } - - @Test - public void testCreateWithJsonNewWithAcceptHeader() throws Exception { - Patient p = new Patient(); - p.addName().setFamily("FAMILY"); - String enc = ourCtx.newJsonParser().encodeResourceToString(p); - - HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); - httpPost.setEntity(new StringEntity(enc, ContentType.parse(Constants.CT_FHIR_JSON + "; charset=utf-8"))); - httpPost.addHeader(Constants.HEADER_ACCEPT, Constants.CT_FHIR_JSON_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_JSON_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", "")); - assertEquals("{\"resourceType\":\"OperationOutcome\",\"issue\":[{\"diagnostics\":\"FAMILY\"}]}", responseContent); - } - - @Test - public void testSearchWithFormatXmlSimple() throws Exception { - - HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=xml"); + 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); @@ -234,9 +286,40 @@ public class ServerMimetypeR4Test { ourLog.info("Response was:\n{}", responseContent); assertEquals(200, status.getStatusLine().getStatusCode()); - assertThat(responseContent, containsString("")); - assertThat(responseContent, not(containsString("http://hl7.org/fhir/"))); - assertEquals(Constants.CT_FHIR_XML_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", "")); + 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(";.*", "")); + } + + @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 @@ -273,77 +356,29 @@ public class ServerMimetypeR4Test { assertEquals(Constants.CT_FHIR_XML_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", "")); } - /** - * See #837 - */ @Test - public void testResponseContentTypes() throws IOException { - assertEquals("application/fhir+json", readAndReturnContentType("application/fhir+json")); - assertEquals("application/fhir+xml", readAndReturnContentType(null)); - assertEquals("application/json+fhir", readAndReturnContentType("application/json+fhir")); - assertEquals("application/json+fhir", readAndReturnContentType("application/json")); - assertEquals("application/fhir+json", readAndReturnContentType("application/fhir+json,application/json;q=0.9")); + public void testSearchWithFormatXmlSimple() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=xml"); + 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("")); + 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 { - HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient"); - if (theAccept != null) { - httpGet.addHeader(Constants.HEADER_ACCEPT, theAccept); + private List toStrings(List theFormat) { + ArrayList retVal = new ArrayList(); + for (CodeType next : theFormat) { + retVal.add(next.asStringValue()); } - HttpResponse status = ourClient.execute(httpGet); - 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(";.*", "")); + return retVal; } @AfterClass @@ -360,10 +395,10 @@ public class ServerMimetypeR4Test { PatientProvider patientProvider = new PatientProvider(); ServletHandler proxyHandler = new ServletHandler(); - RestfulServer servlet = new RestfulServer(ourCtx); + ourServlet = new RestfulServer(ourCtx); - servlet.setResourceProviders(patientProvider); - ServletHolder servletHolder = new ServletHolder(servlet); + ourServlet.setResourceProviders(patientProvider); + ServletHolder servletHolder = new ServletHolder(ourServlet); proxyHandler.addServletWithMapping(servletHolder, "/*"); ourServer.setHandler(proxyHandler); ourServer.start(); diff --git a/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/Controller.java b/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/Controller.java index 26f3e0c2aa9..bddc2103bff 100644 --- a/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/Controller.java +++ b/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/Controller.java @@ -334,7 +334,7 @@ public class Controller extends BaseController { if (client.getEncoding() != null) { clientCodeJsonWriter.name("format"); - clientCodeJsonWriter.value(client.getEncoding().getRequestContentType()); + clientCodeJsonWriter.value(client.getEncoding().getFormatContentType()); } else { clientCodeJsonWriter.name("format"); clientCodeJsonWriter.nullValue(); diff --git a/src/changes/changes.xml b/src/changes/changes.xml index d7eba0a841e..aef584b73b2 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -98,6 +98,17 @@ to build correctly on JDK 9.0. Currently building is supported on JDK 8.x and 9.x only. + + Client requests with an + Accept]]> + header value of + application/json]]> + will now be served with the non-legacy content type of + application/fhir+json]]> + instead of the legacy + application/json+fhir]]>. + Thanks to John Grimes for reporting! +