Fix #342 - The HTTP 400 if request fail to parse

This commit is contained in:
jamesagnew 2016-04-22 07:19:57 -04:00
parent 38e80531bb
commit d76e0008ac
6 changed files with 78 additions and 20 deletions

View File

@ -42,6 +42,7 @@ import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.method.BaseMethodBinding; import ca.uhn.fhir.rest.method.BaseMethodBinding;
@ -180,12 +181,17 @@ public class ResourceParameter implements IParameter {
IParser parser = encoding.newParser(ctx); IParser parser = encoding.newParser(ctx);
T retVal; T retVal;
if (theResourceType != null) { try {
retVal = parser.parseResource(theResourceType, requestReader); if (theResourceType != null) {
} else { retVal = parser.parseResource(theResourceType, requestReader);
retVal = (T) parser.parseResource(requestReader); } else {
retVal = (T) parser.parseResource(requestReader);
}
} catch (DataFormatException e) {
String msg = ctx.getLocalizer().getMessage(ResourceParameter.class, "failedToParseRequest", encoding.name(), e.getMessage());
throw new InvalidRequestException(msg);
} }
if (theRequest.getServer().getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU1)) { if (theRequest.getServer().getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU1)) {
TagList tagList = new TagList(); TagList tagList = new TagList();
for (String nextTagComplete : theRequest.getHeaders(Constants.HEADER_CATEGORY)) { for (String nextTagComplete : theRequest.getHeaders(Constants.HEADER_CATEGORY)) {

View File

@ -33,6 +33,7 @@ ca.uhn.fhir.rest.method.SummaryEnumParameter.cantCombineText=Can not combine _su
ca.uhn.fhir.rest.param.ResourceParameter.invalidContentTypeInRequest=Incorrect Content-Type header value of "{0}" was provided in the request. A FHIR Content-Type is required for "{1}" operation ca.uhn.fhir.rest.param.ResourceParameter.invalidContentTypeInRequest=Incorrect Content-Type header value of "{0}" was provided in the request. A FHIR Content-Type is required for "{1}" operation
ca.uhn.fhir.rest.param.ResourceParameter.noContentTypeInRequest=No Content-Type header was provided in the request. This is required for "{0}" operation ca.uhn.fhir.rest.param.ResourceParameter.noContentTypeInRequest=No Content-Type header was provided in the request. This is required for "{0}" operation
ca.uhn.fhir.rest.param.ResourceParameter.failedToParseRequest=Failed to parse request body as {0} resource. Error was: {1}
ca.uhn.fhir.parser.ParserState.wrongResourceTypeFound=Incorrect resource type found, expected "{0}" but found "{1}" ca.uhn.fhir.parser.ParserState.wrongResourceTypeFound=Incorrect resource type found, expected "{0}" but found "{1}"

View File

@ -166,7 +166,6 @@ public class JsonParserDstu3Test {
assertEquals("CHILD", ((StringType) given2ext2.getValue()).getValue()); assertEquals("CHILD", ((StringType) given2ext2.getValue()).getValue());
} }
@Test @Test
public void testEncodeAndParseMetaProfileAndTags() { public void testEncodeAndParseMetaProfileAndTags() {
@ -245,6 +244,7 @@ public class JsonParserDstu3Test {
assertEquals("sec_term2", tagList.get(1).getCode()); assertEquals("sec_term2", tagList.get(1).getCode());
assertEquals("sec_label2", tagList.get(1).getDisplay()); assertEquals("sec_label2", tagList.get(1).getDisplay());
} }
/** /**
* See #336 * See #336
@ -359,7 +359,6 @@ public class JsonParserDstu3Test {
assertEquals("DISPLAY2", label.getDisplay()); assertEquals("DISPLAY2", label.getDisplay());
assertEquals("VERSION2", label.getVersion()); assertEquals("VERSION2", label.getVersion());
} }
@Test @Test
public void testEncodeBundleNewBundleNoText() { public void testEncodeBundleNewBundleNoText() {
@ -379,6 +378,7 @@ public class JsonParserDstu3Test {
} }
/** /**
* See #326 * See #326
*/ */
@ -414,7 +414,6 @@ public class JsonParserDstu3Test {
)); ));
//@formatter:on //@formatter:on
} }
@Test @Test
public void testEncodeDoesntIncludeUuidId() { public void testEncodeDoesntIncludeUuidId() {
@ -426,13 +425,14 @@ public class JsonParserDstu3Test {
assertThat(actual, not(containsString("78ef6f64c2f2"))); assertThat(actual, not(containsString("78ef6f64c2f2")));
} }
@Test @Test
public void testEncodeEmptyBinary() { public void testEncodeEmptyBinary() {
String output = ourCtx.newJsonParser().encodeResourceToString(new Binary()); String output = ourCtx.newJsonParser().encodeResourceToString(new Binary());
assertEquals("{\"resourceType\":\"Binary\"}", output); assertEquals("{\"resourceType\":\"Binary\"}", output);
} }
/** /**
* #158 * #158
*/ */
@ -448,7 +448,6 @@ public class JsonParserDstu3Test {
String encoded = ourCtx.newJsonParser().encodeResourceToString(p); String encoded = ourCtx.newJsonParser().encodeResourceToString(p);
assertThat(encoded, not(containsString("tag"))); assertThat(encoded, not(containsString("tag")));
} }
/** /**
* #158 * #158
@ -467,6 +466,7 @@ public class JsonParserDstu3Test {
assertThat(encoded, containsString("scheme")); assertThat(encoded, containsString("scheme"));
assertThat(encoded, not(containsString("Label"))); assertThat(encoded, not(containsString("Label")));
} }
@Test @Test
public void testEncodeExtensionInPrimitiveElement() { public void testEncodeExtensionInPrimitiveElement() {
@ -496,7 +496,7 @@ public class JsonParserDstu3Test {
assertEquals(encoded, "{\"resourceType\":\"Conformance\",\"acceptUnknown\":\"elements\",\"_acceptUnknown\":{\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"AAA\"}]}}"); assertEquals(encoded, "{\"resourceType\":\"Conformance\",\"acceptUnknown\":\"elements\",\"_acceptUnknown\":{\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"AAA\"}]}}");
} }
@Test @Test
public void testEncodeExtensionUndeclaredNonModifier() { public void testEncodeExtensionUndeclaredNonModifier() {
Observation obs = new Observation(); Observation obs = new Observation();
@ -608,7 +608,7 @@ public class JsonParserDstu3Test {
assertThat(enc, containsString("\"valueId\":\"1\"")); assertThat(enc, containsString("\"valueId\":\"1\""));
} }
@Test @Test
public void testEncodeSummary() { public void testEncodeSummary() {
Patient patient = new Patient(); Patient patient = new Patient();
@ -629,8 +629,7 @@ public class JsonParserDstu3Test {
assertThat(encoded, containsString("family")); assertThat(encoded, containsString("family"));
assertThat(encoded, not(containsString("maritalStatus"))); assertThat(encoded, not(containsString("maritalStatus")));
} }
@Test @Test
public void testEncodeSummary2() { public void testEncodeSummary2() {
Patient patient = new Patient(); Patient patient = new Patient();
@ -651,6 +650,7 @@ public class JsonParserDstu3Test {
assertThat(encoded, not(containsString("maritalStatus"))); assertThat(encoded, not(containsString("maritalStatus")));
} }
/** /**
* See #205 * See #205
*/ */
@ -1249,6 +1249,14 @@ public class JsonParserDstu3Test {
assertEquals("a2", family1.getId()); assertEquals("a2", family1.getId());
} }
/**
* See #342
*/
@Test(expected=DataFormatException.class)
public void testParseInvalid() {
ourCtx.newJsonParser().parseResource("FOO");
}
@Test @Test
public void testParseMetadata() throws Exception { public void testParseMetadata() throws Exception {
//@formatter:off //@formatter:off

View File

@ -168,7 +168,7 @@ public class XmlParserDstu3Test {
o = (Organization) rr.getResource(); o = (Organization) rr.getResource();
assertEquals("ORG", o.getName()); assertEquals("ORG", o.getName());
} }
@Test @Test
public void testDuration() { public void testDuration() {
Encounter enc = new Encounter(); Encounter enc = new Encounter();
@ -1179,8 +1179,6 @@ public class XmlParserDstu3Test {
} }
/** /**
* See #312 * See #312
*/ */
@ -1200,6 +1198,8 @@ public class XmlParserDstu3Test {
assertEquals("<Patient xmlns=\"http://hl7.org/fhir\"><extension url=\"http://hello.world\"><valueString value=\"Hello World\"/></extension></Patient>", xml); assertEquals("<Patient xmlns=\"http://hl7.org/fhir\"><extension url=\"http://hello.world\"><valueString value=\"Hello World\"/></extension></Patient>", xml);
} }
@Test @Test
public void testEncodeReferenceUsingUnqualifiedResourceWorksCorrectly() { public void testEncodeReferenceUsingUnqualifiedResourceWorksCorrectly() {
@ -1254,7 +1254,7 @@ public class XmlParserDstu3Test {
assertThat(encoded, containsString("family")); assertThat(encoded, containsString("family"));
assertThat(encoded, not(containsString("maritalStatus"))); assertThat(encoded, not(containsString("maritalStatus")));
} }
@Test @Test
public void testEncodeSummary2() { public void testEncodeSummary2() {
Patient patient = new Patient(); Patient patient = new Patient();
@ -1275,7 +1275,7 @@ public class XmlParserDstu3Test {
assertThat(encoded, containsString("family")); assertThat(encoded, containsString("family"));
assertThat(encoded, not(containsString("maritalStatus"))); assertThat(encoded, not(containsString("maritalStatus")));
} }
@Test @Test
public void testEncodeUndeclaredExtensionWithEnumerationContent() { public void testEncodeUndeclaredExtensionWithEnumerationContent() {
IParser parser = ourCtx.newXmlParser(); IParser parser = ourCtx.newXmlParser();
@ -2343,6 +2343,14 @@ public class XmlParserDstu3Test {
assertNotNull(((Reference) actual.getContent().get(0).getP()).getResource()); assertNotNull(((Reference) actual.getContent().get(0).getP()).getResource());
} }
/**
* See #342
*/
@Test(expected=DataFormatException.class)
public void testParseInvalid() {
ourCtx.newXmlParser().parseResource("FOO");
}
@Test @Test
public void testParseInvalidTextualNumber() { public void testParseInvalidTextualNumber() {
Observation obs = new Observation(); Observation obs = new Observation();

View File

@ -13,6 +13,9 @@ 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.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
@ -28,9 +31,12 @@ import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read; import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Search; import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.client.MyPatientWithExtensions; import ca.uhn.fhir.rest.client.MyPatientWithExtensions;
import ca.uhn.fhir.util.PortUtil; import ca.uhn.fhir.util.PortUtil;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
@ -70,6 +76,25 @@ public class CreateDstu3Test {
//@formatter:on //@formatter:on
} }
/**
* #342
*/
@Test
public void testCreateWithInvalidContent() throws Exception {
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
httpPost.setEntity(new StringEntity("FOO", ContentType.parse("application/xml+fhir; charset=utf-8")));
HttpResponse status = ourClient.execute(httpPost);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
assertEquals(400, status.getStatusLine().getStatusCode());
String expected = "<OperationOutcome xmlns=\"http://hl7.org/fhir\"><issue><severity value=\"error\"/><code value=\"processing\"/><diagnostics value=\"Failed to parse request body as XML resource. Error was: com.ctc.wstx.exc.WstxUnexpectedCharException: Unexpected character 'F' (code 70) in prolog; expected '&lt;'&#xa; at [row,col {unknown-source}]: [1,1]\"/></issue></OperationOutcome>";
assertEquals(expected, responseContent);
}
@Test @Test
public void testSearch() throws Exception { public void testSearch() throws Exception {
@ -144,6 +169,11 @@ public class CreateDstu3Test {
return p0; return p0;
} }
@Create()
public MethodOutcome read(@ResourceParam Patient theIdParam) {
return new MethodOutcome(new IdType("Patient", "1"), true);
}
@Search @Search
public List<IBaseResource> search() { public List<IBaseResource> search() {
ArrayList<IBaseResource> retVal = new ArrayList<IBaseResource>(); ArrayList<IBaseResource> retVal = new ArrayList<IBaseResource>();

View File

@ -11,6 +11,11 @@
ResponseValidatingInterceptor threw an InternalErrorException (HTTP 500) for operations ResponseValidatingInterceptor threw an InternalErrorException (HTTP 500) for operations
that do not return any content (e.g. delete). Thanks to Mohammad Jafari for reporting! that do not return any content (e.g. delete). Thanks to Mohammad Jafari for reporting!
</action> </action>
<action type="fix" issue="342">
REST server now throws an HTTP 400 instead of an HTTP 500 if an operation which takes
a FHIR resource in the request body (e.g. create, update) contains invalid content that
the parser is unable to parse. Thanks to Jim Steel for the suggestion!
</action>
</release> </release>
<release version="1.5" date="2016-04-20"> <release version="1.5" date="2016-04-20">
<action type="fix" issue="339"> <action type="fix" issue="339">