In the client, the create/update operations on a Binary resource (which
use the raw binary's content type as opposed to the FHIR content type) were not including any request headers (Content-Type, User-Agent, etc.) Thanks to Peter Van Houte of Agfa Healthcare for reporting!
This commit is contained in:
parent
d11cbab15c
commit
4a26064cd6
|
@ -93,12 +93,13 @@ public abstract class BaseHttpClientInvocation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
theHttpRequest.addHeader("User-Agent", "HAPI-FHIR/" + VersionUtil.getVersion() + " (FHIR Client)");
|
String versionString = VersionUtil.getVersion();
|
||||||
|
theHttpRequest.addHeader("User-Agent", "HAPI-FHIR/" + versionString + " (FHIR Client)");
|
||||||
theHttpRequest.addHeader("Accept-Charset", "utf-8");
|
theHttpRequest.addHeader("Accept-Charset", "utf-8");
|
||||||
theHttpRequest.addHeader("Accept-Encoding", "gzip");
|
theHttpRequest.addHeader("Accept-Encoding", "gzip");
|
||||||
|
|
||||||
if (theEncoding == null) {
|
if (theEncoding == null) {
|
||||||
theHttpRequest.addHeader(Constants.HEADER_ACCEPT, Constants.HEADER_ACCEPT_VALUE_ALL);
|
theHttpRequest.addHeader(Constants.HEADER_ACCEPT, Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON);
|
||||||
} else if (theEncoding == EncodingEnum.JSON) {
|
} else if (theEncoding == EncodingEnum.JSON) {
|
||||||
theHttpRequest.addHeader(Constants.HEADER_ACCEPT, Constants.CT_FHIR_JSON);
|
theHttpRequest.addHeader(Constants.HEADER_ACCEPT, Constants.CT_FHIR_JSON);
|
||||||
} else if (theEncoding == EncodingEnum.XML) {
|
} else if (theEncoding == EncodingEnum.XML) {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package ca.uhn.fhir.rest.method;
|
package ca.uhn.fhir.rest.method;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* #%L
|
* #%L
|
||||||
* HAPI FHIR - Core Library
|
* HAPI FHIR - Core Library
|
||||||
|
@ -213,9 +215,13 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
|
||||||
* whatever reason.
|
* whatever reason.
|
||||||
*/
|
*/
|
||||||
ByteArrayEntity entity = new ByteArrayEntity(binary.getContent());
|
ByteArrayEntity entity = new ByteArrayEntity(binary.getContent());
|
||||||
entity.setContentType(binary.getContentType());
|
|
||||||
HttpRequestBase retVal = createRequest(url, entity);
|
HttpRequestBase retVal = createRequest(url, entity);
|
||||||
addMatchHeaders(retVal, url);
|
addMatchHeaders(retVal, url);
|
||||||
|
super.addHeadersToRequest(retVal, null);
|
||||||
|
if (isNotBlank(binary.getContentType())) {
|
||||||
|
retVal.addHeader(Constants.HEADER_CONTENT_TYPE, binary.getContentType());
|
||||||
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ public class Constants {
|
||||||
public static final String FORMAT_XML = "xml";
|
public static final String FORMAT_XML = "xml";
|
||||||
public static final String HEADER_ACCEPT = "Accept";
|
public static final String HEADER_ACCEPT = "Accept";
|
||||||
public static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
|
public static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
|
||||||
public static final String HEADER_ACCEPT_VALUE_ALL = CT_FHIR_XML + ";q=1.0, " + CT_FHIR_JSON + ";q=1.0";
|
public static final String HEADER_ACCEPT_VALUE_XML_OR_JSON = CT_FHIR_XML + ";q=1.0, " + CT_FHIR_JSON + ";q=1.0";
|
||||||
public static final String HEADER_ALLOW = "Allow";
|
public static final String HEADER_ALLOW = "Allow";
|
||||||
public static final String HEADER_AUTHORIZATION = "Authorization";
|
public static final String HEADER_AUTHORIZATION = "Authorization";
|
||||||
public static final String HEADER_AUTHORIZATION_VALPREFIX_BASIC = "Basic ";
|
public static final String HEADER_AUTHORIZATION_VALPREFIX_BASIC = "Basic ";
|
||||||
|
|
|
@ -143,7 +143,7 @@ public class GenericClientDstu2Test {
|
||||||
client.fetchConformance().ofType(Conformance.class).execute();
|
client.fetchConformance().ofType(Conformance.class).execute();
|
||||||
assertEquals("http://example.com/fhir/metadata", capt.getAllValues().get(idx).getURI().toASCIIString());
|
assertEquals("http://example.com/fhir/metadata", capt.getAllValues().get(idx).getURI().toASCIIString());
|
||||||
assertEquals(1, capt.getAllValues().get(idx).getHeaders("Accept").length);
|
assertEquals(1, capt.getAllValues().get(idx).getHeaders("Accept").length);
|
||||||
assertThat(capt.getAllValues().get(idx).getHeaders("Accept")[0].getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_ALL));
|
assertThat(capt.getAllValues().get(idx).getHeaders("Accept")[0].getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON));
|
||||||
idx++;
|
idx++;
|
||||||
|
|
||||||
client.fetchConformance().ofType(Conformance.class).encodedJson().execute();
|
client.fetchConformance().ofType(Conformance.class).encodedJson().execute();
|
||||||
|
@ -192,12 +192,12 @@ public class GenericClientDstu2Test {
|
||||||
assertEquals("FAMILY", resp.getName().get(0).getFamily().get(0).getValue());
|
assertEquals("FAMILY", resp.getName().get(0).getFamily().get(0).getValue());
|
||||||
assertEquals("http://" + methodName + ".example.com/fhir/metadata", capt.getAllValues().get(0).getURI().toASCIIString());
|
assertEquals("http://" + methodName + ".example.com/fhir/metadata", capt.getAllValues().get(0).getURI().toASCIIString());
|
||||||
assertEquals(1, capt.getAllValues().get(0).getHeaders("Accept").length);
|
assertEquals(1, capt.getAllValues().get(0).getHeaders("Accept").length);
|
||||||
assertThat(capt.getAllValues().get(0).getHeaders("Accept")[0].getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_ALL));
|
assertThat(capt.getAllValues().get(0).getHeaders("Accept")[0].getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON));
|
||||||
assertThat(capt.getAllValues().get(0).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_XML));
|
assertThat(capt.getAllValues().get(0).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_XML));
|
||||||
assertThat(capt.getAllValues().get(0).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_JSON));
|
assertThat(capt.getAllValues().get(0).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_JSON));
|
||||||
assertEquals("http://" + methodName + ".example.com/fhir/Patient/123", capt.getAllValues().get(1).getURI().toASCIIString());
|
assertEquals("http://" + methodName + ".example.com/fhir/Patient/123", capt.getAllValues().get(1).getURI().toASCIIString());
|
||||||
assertEquals(1, capt.getAllValues().get(1).getHeaders("Accept").length);
|
assertEquals(1, capt.getAllValues().get(1).getHeaders("Accept").length);
|
||||||
assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_ALL));
|
assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON));
|
||||||
assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_XML));
|
assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_XML));
|
||||||
assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_JSON));
|
assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_JSON));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
package ca.uhn.fhir.rest.client;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.commons.io.input.ReaderInputStream;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.ProtocolVersion;
|
||||||
|
import org.apache.http.client.HttpClient;
|
||||||
|
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
|
||||||
|
import org.apache.http.client.methods.HttpUriRequest;
|
||||||
|
import org.apache.http.message.BasicHeader;
|
||||||
|
import org.apache.http.message.BasicStatusLine;
|
||||||
|
import org.hl7.fhir.dstu3.model.Binary;
|
||||||
|
import org.hl7.fhir.dstu3.model.Conformance;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
|
||||||
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
|
import org.mockito.stubbing.Answer;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.parser.IParser;
|
||||||
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
|
import ca.uhn.fhir.util.VersionUtil;
|
||||||
|
|
||||||
|
public class GenericClientDstu3Test {
|
||||||
|
private static FhirContext ourCtx;
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(GenericClientDstu3Test.class);
|
||||||
|
|
||||||
|
private HttpClient myHttpClient;
|
||||||
|
|
||||||
|
private HttpResponse myHttpResponse;
|
||||||
|
|
||||||
|
private int myResponseCount = 0;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
|
||||||
|
ourCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
|
||||||
|
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||||
|
myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
|
||||||
|
myResponseCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] extractBodyAsByteArray(ArgumentCaptor<HttpUriRequest> capt) throws IOException {
|
||||||
|
byte[] body = IOUtils.toByteArray(((HttpEntityEnclosingRequestBase) capt.getAllValues().get(0)).getEntity().getContent());
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUserAgentForConformance() throws Exception {
|
||||||
|
IParser p = ourCtx.newXmlParser();
|
||||||
|
|
||||||
|
Conformance conf = new Conformance();
|
||||||
|
conf.setCopyright("COPY");
|
||||||
|
|
||||||
|
final String respString = p.encodeResourceToString(conf);
|
||||||
|
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||||
|
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||||
|
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||||
|
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||||
|
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
|
||||||
|
@Override
|
||||||
|
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
|
||||||
|
return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||||
|
|
||||||
|
client.fetchConformance().ofType(Conformance.class).execute();
|
||||||
|
assertEquals("http://example.com/fhir/metadata", capt.getAllValues().get(0).getURI().toASCIIString());
|
||||||
|
validateUserAgent(capt);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUserAgentForBinary() throws Exception {
|
||||||
|
IParser p = ourCtx.newXmlParser();
|
||||||
|
|
||||||
|
Conformance conf = new Conformance();
|
||||||
|
conf.setCopyright("COPY");
|
||||||
|
|
||||||
|
final String respString = p.encodeResourceToString(conf);
|
||||||
|
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||||
|
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||||
|
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||||
|
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||||
|
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
|
||||||
|
@Override
|
||||||
|
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
|
||||||
|
return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||||
|
|
||||||
|
Binary bin = new Binary();
|
||||||
|
bin.setContentType("application/foo");
|
||||||
|
bin.setContent(new byte[] {0, 1, 2, 3, 4});
|
||||||
|
client.create().resource(bin).execute();
|
||||||
|
|
||||||
|
ourLog.info(Arrays.asList(capt.getAllValues().get(0).getAllHeaders()).toString());
|
||||||
|
|
||||||
|
assertEquals("http://example.com/fhir/Binary", capt.getAllValues().get(0).getURI().toASCIIString());
|
||||||
|
validateUserAgent(capt);
|
||||||
|
|
||||||
|
assertEquals("application/foo", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue());
|
||||||
|
assertEquals(Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
|
||||||
|
assertArrayEquals(new byte[] {0,1,2,3,4}, extractBodyAsByteArray(capt));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateUserAgent(ArgumentCaptor<HttpUriRequest> capt) {
|
||||||
|
assertEquals(1, capt.getAllValues().get(0).getHeaders("User-Agent").length);
|
||||||
|
assertEquals(expectedUserAgent(), capt.getAllValues().get(0).getHeaders("User-Agent")[0].getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String expectedUserAgent() {
|
||||||
|
return "HAPI-FHIR/" + VersionUtil.getVersion() + " (FHIR Client)";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void beforeClass() {
|
||||||
|
ourCtx = FhirContext.forDstu3();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -77,6 +77,13 @@
|
||||||
know if you need the ability to add this header automatically. Thanks
|
know if you need the ability to add this header automatically. Thanks
|
||||||
to Lars Kristian Roland for pointing this out.
|
to Lars Kristian Roland for pointing this out.
|
||||||
</action>
|
</action>
|
||||||
|
<action type="fix">
|
||||||
|
In the client, the create/update operations on a Binary resource
|
||||||
|
(which use the raw binary's content type as opposed to the FHIR
|
||||||
|
content type) were not including any request headers (Content-Type,
|
||||||
|
User-Agent, etc.) Thanks to Peter Van Houte of Agfa Healthcare for
|
||||||
|
reporting!
|
||||||
|
</action>
|
||||||
</release>
|
</release>
|
||||||
<release version="1.4" date="2016-02-04">
|
<release version="1.4" date="2016-02-04">
|
||||||
<action type="add">
|
<action type="add">
|
||||||
|
|
Loading…
Reference in New Issue