Add content-disposition header for binary resources

This commit is contained in:
James Agnew 2014-07-22 14:25:33 -04:00
parent fc74cda994
commit e53aaf0950
4 changed files with 66 additions and 2 deletions

View File

@ -8,7 +8,7 @@
<body>
<release version="0.5" date="TBD">
<action type="add">
Allow server methods to return wildcard genrric types (e.g. List&lt;? extends IResource&gt;)
Allow server methods to return wildcard generic types (e.g. List&lt;? extends IResource&gt;)
</action>
<action type="add">
Search parameters are not properly escaped and unescaped. E.g. for a token parameter such as
@ -47,6 +47,12 @@
Fix issue where vread invocations on server incorrectly get routed to instance history method if one is
defined. Thanks to Neal Acharya from UHN for surfacing this one!
</action>
<action type="add">
Binary reads on a server not include the Content-Disposition header, to prevent HTML in binary
blobs from being used for nefarious purposes. See
<![CDATA[<a href="http://gforge.hl7.org/gf/project/fhir/tracker/?action=TrackerItemEdit&tracker_id=677&tracker_item_id=3298">FHIR Tracker Bug 3298</a>]]>
for more information.
</action>
</release>
<release version="0.4" date="2014-Jul-13">
<action type="add">

View File

@ -95,6 +95,7 @@ public class Constants {
public static final String HEADERVALUE_CORS_ALLOW_METHODS_ALL = "GET, POST, PUT, DELETE";
public static final String HEADER_AUTHORIZATION = "Authorization";
public static final String PARAMQUALIFIER_TOKEN_TEXT = ":text";
public static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition";
static {

View File

@ -1099,6 +1099,9 @@ public class RestfulServer extends HttpServlet {
if (bin.getContent() == null || bin.getContent().length == 0) {
return;
}
theHttpResponse.addHeader(Constants.HEADER_CONTENT_DISPOSITION, "Attachment;");
theHttpResponse.setContentLength(bin.getContent().length);
ServletOutputStream oos = theHttpResponse.getOutputStream();
oos.write(bin.getContent());

View File

@ -21,6 +21,7 @@ import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu.resource.Binary;
import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.IdParam;
@ -59,6 +60,36 @@ public class ReadTest {
}
@Test
public void testBinaryRead() throws Exception {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Binary/1");
HttpResponse status = ourClient.execute(httpGet);
byte[] responseContent = IOUtils.toByteArray(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals("application/x-foo", status.getEntity().getContentType().getValue());
Header cl = status.getFirstHeader(Constants.HEADER_CONTENT_LOCATION_LC);
assertNotNull(cl);
assertEquals("http://localhost:" + ourPort + "/Binary/1/_history/1", cl.getValue());
Header cd = status.getFirstHeader("content-disposition");
assertNotNull(cd);
assertEquals("Attachment;", cd.getValue());
assertEquals(4,responseContent.length);
for (int i = 0; i < 4; i++) {
assertEquals(i+1, responseContent[i]); // should be 1,2,3,4
}
}
}
@Test
public void testVRead() throws Exception {
{
@ -93,7 +124,7 @@ public class ReadTest {
ServletHandler proxyHandler = new ServletHandler();
RestfulServer servlet = new RestfulServer();
ourCtx = servlet.getFhirContext();
servlet.setResourceProviders(patientProvider);
servlet.setResourceProviders(patientProvider, new DummyBinaryProvider());
ServletHolder servletHolder = new ServletHolder(servlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
@ -126,4 +157,27 @@ public class ReadTest {
}
/**
* Created by dsotnikov on 2/25/2014.
*/
public static class DummyBinaryProvider implements IResourceProvider {
@Read(version = true)
public Binary findPatient(@IdParam IdDt theId) {
Binary bin = new Binary();
bin.setContentType("application/x-foo");
bin.setContent(new byte[] {1,2,3,4});
bin.setId("Binary/1/_history/1");
return bin;
}
@Override
public Class<? extends IResource> getResourceType() {
return Binary.class;
}
}
}