Fix #345 - ResponseValidatingInterceptor throws an exception with response has no content

This commit is contained in:
jamesagnew 2016-04-22 07:04:14 -04:00
parent 246a7c5e16
commit dd3f1dd33c
5 changed files with 134 additions and 52 deletions

View File

@ -244,6 +244,10 @@ abstract class BaseValidatingInterceptor<T> extends InterceptorAdapter {
} }
} }
if (theRequest == null) {
return;
}
ValidationResult validationResult = doValidate(validator, theRequest); ValidationResult validationResult = doValidate(validator, theRequest);
if (myAddResponseIssueHeaderOnSeverity != null) { if (myAddResponseIssueHeaderOnSeverity != null) {

View File

@ -120,7 +120,6 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
TestUtil.clearAllStaticFieldsForUnitTest(); TestUtil.clearAllStaticFieldsForUnitTest();
} }
@Override @Override
public void before() throws Exception { public void before() throws Exception {
super.before(); super.before();
@ -295,7 +294,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
cs.setUrl("http://urn/system"); cs.setUrl("http://urn/system");
cs.addConcept().setCode("code0"); cs.addConcept().setCode("code0");
ourClient.create().resource(cs).execute(); ourClient.create().resource(cs).execute();
ValueSet options = new ValueSet(); ValueSet options = new ValueSet();
options.getCompose().addInclude().setSystem("http://urn/system"); options.getCompose().addInclude().setSystem("http://urn/system");
IIdType optId = ourClient.create().resource(options).execute().getId(); IIdType optId = ourClient.create().resource(options).execute().getId();
@ -438,8 +437,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
ourLog.info(responseString); ourLog.info(responseString);
assertEquals(400, response.getStatusLine().getStatusCode()); assertEquals(400, response.getStatusLine().getStatusCode());
OperationOutcome oo = myFhirCtx.newXmlParser().parseResource(OperationOutcome.class, responseString); OperationOutcome oo = myFhirCtx.newXmlParser().parseResource(OperationOutcome.class, responseString);
assertEquals("Can not create resource with ID \"2\", ID must not be supplied on a create (POST) operation (use an HTTP PUT / update operation if you wish to supply an ID)", assertEquals("Can not create resource with ID \"2\", ID must not be supplied on a create (POST) operation (use an HTTP PUT / update operation if you wish to supply an ID)", oo.getIssue().get(0).getDiagnostics());
oo.getIssue().get(0).getDiagnostics());
} finally { } finally {
response.getEntity().getContent().close(); response.getEntity().getContent().close();
@ -522,8 +520,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
//@formatter:on //@formatter:on
fail(); fail();
} catch (PreconditionFailedException e) { } catch (PreconditionFailedException e) {
assertEquals("HTTP 412 Precondition Failed: Failed to DELETE resource with match URL \"Patient?identifier=testDeleteConditionalMultiple\" because this search matched 2 resources", assertEquals("HTTP 412 Precondition Failed: Failed to DELETE resource with match URL \"Patient?identifier=testDeleteConditionalMultiple\" because this search matched 2 resources", e.getMessage());
e.getMessage());
} }
// Not deleted yet.. // Not deleted yet..
@ -568,6 +565,27 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
} }
} }
/**
* Test for #345
*/
@Test
public void testDeleteNormal() throws IOException {
Patient p = new Patient();
p.addName().addFamily("FAM");
IIdType id = ourClient.create().resource(p).execute().getId().toUnqualifiedVersionless();
ourClient.read().resource(Patient.class).withId(id).execute();
ourClient.delete().resourceById(id).execute();
try {
ourClient.read().resource(Patient.class).withId(id).execute();
fail();
} catch (ResourceGoneException e) {
// good
}
}
@Test @Test
public void testDeleteResourceConditional1() throws IOException { public void testDeleteResourceConditional1() throws IOException {
String methodName = "testDeleteResourceConditional1"; String methodName = "testDeleteResourceConditional1";
@ -634,7 +652,8 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
} }
/* /*
* Try it with a raw socket call. The Apache client won't let us use the unescaped "|" in the URL but we want to make sure that works too.. * Try it with a raw socket call. The Apache client won't let us use the unescaped "|" in the URL but we want to
* make sure that works too..
*/ */
Socket sock = new Socket(); Socket sock = new Socket();
sock.setSoTimeout(3000); sock.setSoTimeout(3000);
@ -1168,8 +1187,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
response.close(); response.close();
} }
get = new HttpGet(ourServerBase + "/Patient/" + pId.getIdPart() + "/$everything?_lastUpdated=%3E" + new InstantType(new Date(time2)).getValueAsString() + "&_lastUpdated=%3C" get = new HttpGet(ourServerBase + "/Patient/" + pId.getIdPart() + "/$everything?_lastUpdated=%3E" + new InstantType(new Date(time2)).getValueAsString() + "&_lastUpdated=%3C" + new InstantType(new Date(time3)).getValueAsString());
+ new InstantType(new Date(time3)).getValueAsString());
response = ourHttpClient.execute(get); response = ourHttpClient.execute(get);
try { try {
assertEquals(200, response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode());
@ -1761,8 +1779,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
Patient patient = new Patient(); Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("testSearchTokenParam001"); patient.addIdentifier().setSystem("urn:system").setValue("testSearchTokenParam001");
patient.addName().addFamily("Tester").addGiven("testSearchTokenParam1"); patient.addName().addFamily("Tester").addGiven("testSearchTokenParam1");
patient.addCommunication().getLanguage().setText("testSearchTokenParamComText").addCoding().setCode("testSearchTokenParamCode").setSystem("testSearchTokenParamSystem") patient.addCommunication().getLanguage().setText("testSearchTokenParamComText").addCoding().setCode("testSearchTokenParamCode").setSystem("testSearchTokenParamSystem").setDisplay("testSearchTokenParamDisplay");
.setDisplay("testSearchTokenParamDisplay");
myPatientDao.create(patient, mySrd); myPatientDao.create(patient, mySrd);
patient = new Patient(); patient = new Patient();
@ -2474,8 +2491,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
ourLog.info(responseString); ourLog.info(responseString);
assertEquals(400, response.getStatusLine().getStatusCode()); assertEquals(400, response.getStatusLine().getStatusCode());
OperationOutcome oo = myFhirCtx.newXmlParser().parseResource(OperationOutcome.class, responseString); OperationOutcome oo = myFhirCtx.newXmlParser().parseResource(OperationOutcome.class, responseString);
assertThat(oo.getIssue().get(0).getDiagnostics(), containsString( assertThat(oo.getIssue().get(0).getDiagnostics(), containsString("Can not update resource, resource body must contain an ID element which matches the request URL for update (PUT) operation - Resource body ID of \"333\" does not match URL ID of \"2\""));
"Can not update resource, resource body must contain an ID element which matches the request URL for update (PUT) operation - Resource body ID of \"333\" does not match URL ID of \"2\""));
} finally { } finally {
response.close(); response.close();
} }
@ -2499,10 +2515,8 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
ourLog.info(resp); ourLog.info(resp);
assertEquals(412, response.getStatusLine().getStatusCode()); assertEquals(412, response.getStatusLine().getStatusCode());
assertThat(resp, not(containsString("Resource has no id"))); assertThat(resp, not(containsString("Resource has no id")));
assertThat(resp, assertThat(resp, stringContainsInOrder(">ERROR<", "/f:Patient/f:contact", "<pre>SHALL at least contain a contact's details or a reference to an organization</pre>", "<issue><severity value=\"error\"/>", "<code value=\"processing\"/>",
stringContainsInOrder(">ERROR<", "/f:Patient/f:contact", "<pre>SHALL at least contain a contact's details or a reference to an organization</pre>", "<issue><severity value=\"error\"/>", "<diagnostics value=\"SHALL at least contain a contact's details or a reference to an organization\"/>", "<location value=\"/f:Patient/f:contact\"/>"));
"<code value=\"processing\"/>", "<diagnostics value=\"SHALL at least contain a contact's details or a reference to an organization\"/>",
"<location value=\"/f:Patient/f:contact\"/>"));
} finally { } finally {
IOUtils.closeQuietly(response.getEntity().getContent()); IOUtils.closeQuietly(response.getEntity().getContent());
response.close(); response.close();
@ -2585,8 +2599,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
assertEquals(200, response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode());
assertThat(resp, not(containsString("Resource has no id"))); assertThat(resp, not(containsString("Resource has no id")));
assertThat(resp, containsString("<pre>No issues detected during validation</pre>")); assertThat(resp, containsString("<pre>No issues detected during validation</pre>"));
assertThat(resp, assertThat(resp, stringContainsInOrder("<issue>", "<severity value=\"information\"/>", "<code value=\"informational\"/>", "<diagnostics value=\"No issues detected during validation\"/>", "</issue>"));
stringContainsInOrder("<issue>", "<severity value=\"information\"/>", "<code value=\"informational\"/>", "<diagnostics value=\"No issues detected during validation\"/>", "</issue>"));
} finally { } finally {
IOUtils.closeQuietly(response.getEntity().getContent()); IOUtils.closeQuietly(response.getEntity().getContent());
response.close(); response.close();
@ -2611,8 +2624,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
assertEquals(200, response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode());
assertThat(resp, not(containsString("Resource has no id"))); assertThat(resp, not(containsString("Resource has no id")));
assertThat(resp, containsString("<pre>No issues detected during validation</pre>")); assertThat(resp, containsString("<pre>No issues detected during validation</pre>"));
assertThat(resp, assertThat(resp, stringContainsInOrder("<issue>", "<severity value=\"information\"/>", "<code value=\"informational\"/>", "<diagnostics value=\"No issues detected during validation\"/>", "</issue>"));
stringContainsInOrder("<issue>", "<severity value=\"information\"/>", "<code value=\"informational\"/>", "<diagnostics value=\"No issues detected during validation\"/>", "</issue>"));
} finally { } finally {
IOUtils.closeQuietly(response.getEntity().getContent()); IOUtils.closeQuietly(response.getEntity().getContent());
response.close(); response.close();

View File

@ -11,6 +11,8 @@ 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.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
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.client.methods.HttpPost;
import org.apache.http.entity.ContentType; import org.apache.http.entity.ContentType;
@ -22,9 +24,9 @@ import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator; import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator;
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
import org.hl7.fhir.dstu3.model.IdType; import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.Patient; import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Before; import org.junit.Before;
@ -35,6 +37,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.Create; import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.Delete;
import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.OptionalParam; import ca.uhn.fhir.rest.annotation.OptionalParam;
import ca.uhn.fhir.rest.annotation.ResourceParam; import ca.uhn.fhir.rest.annotation.ResourceParam;
@ -49,7 +52,7 @@ import ca.uhn.fhir.validation.ResultSeverityEnum;
public class RequestValidatingInterceptorDstu3Test { public class RequestValidatingInterceptorDstu3Test {
private static CloseableHttpClient ourClient; private static CloseableHttpClient ourClient;
private static FhirContext ourCtx = FhirContext.forDstu3(); private static FhirContext ourCtx = FhirContext.forDstu3();
private static boolean ourLastRequestWasSearch; private static boolean ourLastRequestWasSearch;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RequestValidatingInterceptorDstu3Test.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RequestValidatingInterceptorDstu3Test.class);
@ -58,23 +61,22 @@ public class RequestValidatingInterceptorDstu3Test {
private static Server ourServer; private static Server ourServer;
private static RestfulServer ourServlet; private static RestfulServer ourServlet;
private RequestValidatingInterceptor myInterceptor; private RequestValidatingInterceptor myInterceptor;
@Before @Before
public void before() { public void before() {
ourLastRequestWasSearch = false; ourLastRequestWasSearch = false;
while (ourServlet.getInterceptors().size() > 0) { while (ourServlet.getInterceptors().size() > 0) {
ourServlet.unregisterInterceptor(ourServlet.getInterceptors().get(0)); ourServlet.unregisterInterceptor(ourServlet.getInterceptors().get(0));
} }
myInterceptor = new RequestValidatingInterceptor(); myInterceptor = new RequestValidatingInterceptor();
// myInterceptor.setFailOnSeverity(ResultSeverityEnum.ERROR); // myInterceptor.setFailOnSeverity(ResultSeverityEnum.ERROR);
// myInterceptor.setAddResponseHeaderOnSeverity(ResultSeverityEnum.INFORMATION); // myInterceptor.setAddResponseHeaderOnSeverity(ResultSeverityEnum.INFORMATION);
// myInterceptor.setResponseHeaderName("X-RESP"); // myInterceptor.setResponseHeaderName("X-RESP");
// myInterceptor.setResponseHeaderValue(RequestValidatingInterceptor.DEFAULT_RESPONSE_HEADER_VALUE); // myInterceptor.setResponseHeaderValue(RequestValidatingInterceptor.DEFAULT_RESPONSE_HEADER_VALUE);
ourServlet.registerInterceptor(myInterceptor); ourServlet.registerInterceptor(myInterceptor);
} }
@ -88,7 +90,7 @@ public class RequestValidatingInterceptorDstu3Test {
patient.setGender(AdministrativeGender.MALE); patient.setGender(AdministrativeGender.MALE);
patient.addContact().addRelationship().setText("FOO"); patient.addContact().addRelationship().setText("FOO");
String encoded = ourCtx.newJsonParser().encodeResourceToString(patient); String encoded = ourCtx.newJsonParser().encodeResourceToString(patient);
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8"))); httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8")));
@ -108,13 +110,13 @@ public class RequestValidatingInterceptorDstu3Test {
@Test @Test
public void testCreateJsonInvalidNoValidatorsSpecified() throws Exception { public void testCreateJsonInvalidNoValidatorsSpecified() throws Exception {
myInterceptor.setAddResponseHeaderOnSeverity(ResultSeverityEnum.INFORMATION); myInterceptor.setAddResponseHeaderOnSeverity(ResultSeverityEnum.INFORMATION);
Patient patient = new Patient(); Patient patient = new Patient();
patient.addIdentifier().setValue("002"); patient.addIdentifier().setValue("002");
patient.setGender(AdministrativeGender.MALE); patient.setGender(AdministrativeGender.MALE);
patient.addContact().addRelationship().setText("FOO"); patient.addContact().addRelationship().setText("FOO");
String encoded = ourCtx.newJsonParser().encodeResourceToString(patient); String encoded = ourCtx.newJsonParser().encodeResourceToString(patient);
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8"))); httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8")));
@ -137,7 +139,7 @@ public class RequestValidatingInterceptorDstu3Test {
patient.addIdentifier().setValue("002"); patient.addIdentifier().setValue("002");
patient.setGender(AdministrativeGender.MALE); patient.setGender(AdministrativeGender.MALE);
String encoded = ourCtx.newJsonParser().encodeResourceToString(patient); String encoded = ourCtx.newJsonParser().encodeResourceToString(patient);
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8"))); httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8")));
@ -162,7 +164,7 @@ public class RequestValidatingInterceptorDstu3Test {
patient.addIdentifier().setValue("002"); patient.addIdentifier().setValue("002");
patient.setGender(AdministrativeGender.MALE); patient.setGender(AdministrativeGender.MALE);
String encoded = ourCtx.newJsonParser().encodeResourceToString(patient); String encoded = ourCtx.newJsonParser().encodeResourceToString(patient);
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8"))); httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8")));
@ -177,7 +179,7 @@ public class RequestValidatingInterceptorDstu3Test {
assertEquals(201, status.getStatusLine().getStatusCode()); assertEquals(201, status.getStatusLine().getStatusCode());
assertThat(status.toString(), (containsString("X-FHIR-Request-Validation: NO ISSUES"))); assertThat(status.toString(), (containsString("X-FHIR-Request-Validation: NO ISSUES")));
} }
@Test @Test
public void testCreateXmlInvalidInstanceValidator() throws Exception { public void testCreateXmlInvalidInstanceValidator() throws Exception {
IValidatorModule module = new FhirInstanceValidator(); IValidatorModule module = new FhirInstanceValidator();
@ -190,7 +192,7 @@ public class RequestValidatingInterceptorDstu3Test {
patient.setGender(AdministrativeGender.MALE); patient.setGender(AdministrativeGender.MALE);
patient.addContact().addRelationship().setText("FOO"); patient.addContact().addRelationship().setText("FOO");
String encoded = ourCtx.newXmlParser().encodeResourceToString(patient); String encoded = ourCtx.newXmlParser().encodeResourceToString(patient);
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
@ -215,7 +217,7 @@ public class RequestValidatingInterceptorDstu3Test {
patient.setGender(AdministrativeGender.MALE); patient.setGender(AdministrativeGender.MALE);
patient.addContact().addRelationship().setText("FOO"); patient.addContact().addRelationship().setText("FOO");
String encoded = ourCtx.newXmlParser().encodeResourceToString(patient); String encoded = ourCtx.newXmlParser().encodeResourceToString(patient);
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
@ -230,7 +232,7 @@ public class RequestValidatingInterceptorDstu3Test {
assertEquals(422, status.getStatusLine().getStatusCode()); assertEquals(422, status.getStatusLine().getStatusCode());
assertThat(status.toString(), containsString("X-FHIR-Request-Validation")); assertThat(status.toString(), containsString("X-FHIR-Request-Validation"));
} }
@Test @Test
public void testCreateXmlInvalidNoValidatorsSpecifiedOutcomeHeader() throws Exception { public void testCreateXmlInvalidNoValidatorsSpecifiedOutcomeHeader() throws Exception {
myInterceptor.setAddResponseHeaderOnSeverity(null); myInterceptor.setAddResponseHeaderOnSeverity(null);
@ -242,7 +244,7 @@ public class RequestValidatingInterceptorDstu3Test {
patient.setGender(AdministrativeGender.MALE); patient.setGender(AdministrativeGender.MALE);
patient.addContact().addRelationship().setText("FOO"); patient.addContact().addRelationship().setText("FOO");
String encoded = ourCtx.newXmlParser().encodeResourceToString(patient); String encoded = ourCtx.newXmlParser().encodeResourceToString(patient);
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
@ -258,14 +260,13 @@ public class RequestValidatingInterceptorDstu3Test {
assertThat(status.toString(), containsString("X-FHIR-Request-Validation: {\"resourceType\":\"OperationOutcome")); assertThat(status.toString(), containsString("X-FHIR-Request-Validation: {\"resourceType\":\"OperationOutcome"));
} }
@Test @Test
public void testCreateXmlValidNoValidatorsSpecified() throws Exception { public void testCreateXmlValidNoValidatorsSpecified() throws Exception {
Patient patient = new Patient(); Patient patient = new Patient();
patient.addIdentifier().setValue("002"); patient.addIdentifier().setValue("002");
patient.setGender(AdministrativeGender.MALE); patient.setGender(AdministrativeGender.MALE);
String encoded = ourCtx.newXmlParser().encodeResourceToString(patient); String encoded = ourCtx.newXmlParser().encodeResourceToString(patient);
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
@ -281,12 +282,33 @@ public class RequestValidatingInterceptorDstu3Test {
assertThat(status.toString(), not(containsString("X-FHIR-Request-Validation"))); assertThat(status.toString(), not(containsString("X-FHIR-Request-Validation")));
} }
/**
* Test for #345
*/
@Test
public void testDelete() throws Exception {
myInterceptor.setFailOnSeverity(null);
myInterceptor.setAddResponseHeaderOnSeverity(ResultSeverityEnum.INFORMATION);
HttpDelete httpDelete = new HttpDelete("http://localhost:" + ourPort + "/Patient/123");
CloseableHttpResponse status = ourClient.execute(httpDelete);
try {
ourLog.info("Response was:\n{}", status);
assertEquals(204, status.getStatusLine().getStatusCode());
assertThat(status.toString(), not(containsString("X-FHIR-Request-Validation")));
} finally {
IOUtils.closeQuietly(status);
}
}
@Test @Test
public void testFetchMetadata() throws Exception { public void testFetchMetadata() throws Exception {
myInterceptor.setAddResponseHeaderOnSeverity(ResultSeverityEnum.INFORMATION); myInterceptor.setAddResponseHeaderOnSeverity(ResultSeverityEnum.INFORMATION);
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/metadata"); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/metadata");
// This header caused a crash // This header caused a crash
httpGet.addHeader("Content-Type", "application/xml+fhir"); httpGet.addHeader("Content-Type", "application/xml+fhir");
@ -301,7 +323,7 @@ public class RequestValidatingInterceptorDstu3Test {
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("Conformance")); assertThat(responseContent, containsString("Conformance"));
} }
@Test @Test
public void testSearch() throws Exception { public void testSearch() throws Exception {
HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar"); HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar");
@ -318,13 +340,13 @@ public class RequestValidatingInterceptorDstu3Test {
assertThat(status.toString(), not(containsString("X-FHIR-Request-Validation"))); assertThat(status.toString(), not(containsString("X-FHIR-Request-Validation")));
assertEquals(true, ourLastRequestWasSearch); assertEquals(true, ourLastRequestWasSearch);
} }
@AfterClass @AfterClass
public static void afterClassClearContext() throws Exception { public static void afterClassClearContext() throws Exception {
ourServer.stop(); ourServer.stop();
TestUtil.clearAllStaticFieldsForUnitTest(); TestUtil.clearAllStaticFieldsForUnitTest();
} }
@BeforeClass @BeforeClass
public static void beforeClass() throws Exception { public static void beforeClass() throws Exception {
ourPort = PortUtil.findFreePort(); ourPort = PortUtil.findFreePort();
@ -346,21 +368,26 @@ public class RequestValidatingInterceptorDstu3Test {
ourClient = builder.build(); ourClient = builder.build();
} }
public static class PatientProvider implements IResourceProvider {
public static class PatientProvider implements IResourceProvider {
@Create() @Create()
public MethodOutcome createPatient(@ResourceParam Patient thePatient, @IdParam IdType theIdParam) { public MethodOutcome createPatient(@ResourceParam Patient thePatient, @IdParam IdType theIdParam) {
return new MethodOutcome(new IdDt("Patient/001/_history/002")); return new MethodOutcome(new IdDt("Patient/001/_history/002"));
} }
@Delete
public MethodOutcome delete(@IdParam IdType theId) {
return new MethodOutcome(theId.withVersion("2"));
}
@Override @Override
public Class<? extends IBaseResource> getResourceType() { public Class<? extends IBaseResource> getResourceType() {
return Patient.class; return Patient.class;
} }
@Search @Search
public List<IResource> search(@OptionalParam(name="foo") StringParam theString) { public List<IResource> search(@OptionalParam(name = "foo") StringParam theString) {
ourLastRequestWasSearch = true; ourLastRequestWasSearch = true;
return new ArrayList<IResource>(); return new ArrayList<IResource>();
} }

View File

@ -12,6 +12,8 @@ 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.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
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;
@ -20,6 +22,7 @@ import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator; import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.Patient; import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender; import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
import org.hl7.fhir.dstu3.model.Identifier.IdentifierUse; import org.hl7.fhir.dstu3.model.Identifier.IdentifierUse;
@ -31,8 +34,11 @@ import org.junit.Ignore;
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.Delete;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.OptionalParam; import ca.uhn.fhir.rest.annotation.OptionalParam;
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.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.interceptor.ResponseValidatingInterceptor; import ca.uhn.fhir.rest.server.interceptor.ResponseValidatingInterceptor;
@ -67,6 +73,28 @@ public class ResponseValidatingInterceptorDstu3Test {
ourServlet.registerInterceptor(myInterceptor); ourServlet.registerInterceptor(myInterceptor);
} }
/**
* Test for #345
*/
@Test
public void testDelete() throws Exception {
myInterceptor.setFailOnSeverity(null);
myInterceptor.setAddResponseHeaderOnSeverity(ResultSeverityEnum.INFORMATION);
HttpDelete httpDelete = new HttpDelete("http://localhost:" + ourPort + "/Patient/123");
CloseableHttpResponse status = ourClient.execute(httpDelete);
try {
ourLog.info("Response was:\n{}", status);
assertEquals(204, status.getStatusLine().getStatusCode());
assertThat(status.toString(), not(containsString("X-FHIR-Request-Validation")));
} finally {
IOUtils.closeQuietly(status);
}
}
@Test @Test
public void testLongHeaderTruncated() throws Exception { public void testLongHeaderTruncated() throws Exception {
@ -351,6 +379,11 @@ public class ResponseValidatingInterceptorDstu3Test {
public static class PatientProvider implements IResourceProvider { public static class PatientProvider implements IResourceProvider {
@Delete
public MethodOutcome delete(@IdParam IdType theId) {
return new MethodOutcome(theId.withVersion("2"));
}
@Override @Override
public Class<? extends IBaseResource> getResourceType() { public Class<? extends IBaseResource> getResourceType() {
return Patient.class; return Patient.class;

View File

@ -6,7 +6,13 @@
<title>HAPI FHIR Changelog</title> <title>HAPI FHIR Changelog</title>
</properties> </properties>
<body> <body>
<release version="1.5" date="TBD"> <release version="1.6" date="TBD">
<action type="fix" issue="345">
ResponseValidatingInterceptor threw an InternalErrorException (HTTP 500) for operations
that do not return any content (e.g. delete). Thanks to Mohammad Jafari for reporting!
</action>
</release>
<release version="1.5" date="2016-04-20">
<action type="fix" issue="339"> <action type="fix" issue="339">
Security Fix: XML parser was vulnerable to XXE (XML External Entity) Security Fix: XML parser was vulnerable to XXE (XML External Entity)
processing, which could result in local files on disk being disclosed. processing, which could result in local files on disk being disclosed.