From 82ec721c99cfc25f98835e4fb9b2aa2746175406 Mon Sep 17 00:00:00 2001 From: James Agnew Date: Thu, 8 Nov 2018 15:27:35 -0500 Subject: [PATCH] Allow client defined parameter style for _format param --- .../rest/api/RequestFormatParamStyleEnum.java | 14 ++ .../fhir/rest/client/api/IRestfulClient.java | 56 +++--- .../uhn/fhir/rest/client/impl/BaseClient.java | 181 ++++++++---------- .../fhir/rest/client/ClientHeadersR4Test.java | 160 +++++++++++----- src/changes/changes.xml | 7 +- 5 files changed, 241 insertions(+), 177 deletions(-) create mode 100644 hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/RequestFormatParamStyleEnum.java diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/RequestFormatParamStyleEnum.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/RequestFormatParamStyleEnum.java new file mode 100644 index 00000000000..53d05ea2e31 --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/RequestFormatParamStyleEnum.java @@ -0,0 +1,14 @@ +package ca.uhn.fhir.rest.api; + +public enum RequestFormatParamStyleEnum { + /** + * Do not include a _format parameter on requests + */ + NONE, + + /** + * "xml" or "json" + */ + SHORT + +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/api/IRestfulClient.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/api/IRestfulClient.java index 36fd4fea5b0..f3f961edd64 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/api/IRestfulClient.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/api/IRestfulClient.java @@ -1,5 +1,11 @@ package ca.uhn.fhir.rest.client.api; +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.rest.api.EncodingEnum; +import ca.uhn.fhir.rest.api.RequestFormatParamStyleEnum; +import ca.uhn.fhir.rest.api.SummaryEnum; +import org.hl7.fhir.instance.model.api.IBaseResource; + import java.util.List; /* @@ -11,9 +17,9 @@ import java.util.List; * 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. @@ -22,23 +28,15 @@ import java.util.List; * #L% */ -import org.hl7.fhir.instance.model.api.IBaseResource; - -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.rest.api.EncodingEnum; -import ca.uhn.fhir.rest.api.SummaryEnum; - public interface IRestfulClient { /** * Retrieve the contents at the given URL and parse them as a resource. This * method could be used as a low level implementation of a read/vread/search * operation. - * - * @param theResourceType - * The resource type to parse - * @param theUrl - * The URL to load + * + * @param theResourceType The resource type to parse + * @param theUrl The URL to load * @return The parsed resource */ T fetchResourceFromUrl(Class theResourceType, String theUrl); @@ -49,6 +47,17 @@ public interface IRestfulClient { */ EncodingEnum getEncoding(); + /** + * Specifies that the client should use the given encoding to do its + * queries. This means that the client will append the "_format" param + * to GET methods (read/search/etc), and will add an appropriate header for + * write methods. + * + * @param theEncoding The encoding to use in the request, or null not specify + * an encoding (which generally implies the use of XML). The default is null. + */ + void setEncoding(EncodingEnum theEncoding); + /** * Returns the FHIR context associated with this client */ @@ -76,25 +85,12 @@ public interface IRestfulClient { */ void registerInterceptor(IClientInterceptor theInterceptor); - /** - * Specifies that the client should use the given encoding to do its - * queries. This means that the client will append the "_format" param - * to GET methods (read/search/etc), and will add an appropriate header for - * write methods. - * - * @param theEncoding - * The encoding to use in the request, or null not specify - * an encoding (which generally implies the use of XML). The default is null. - */ - void setEncoding(EncodingEnum theEncoding); - /** * Specifies that the client should request that the server respond with "pretty printing" * enabled. Note that this is a non-standard parameter, not all servers will * support it. - * - * @param thePrettyPrint - * The pretty print flag to use in the request (default is false) + * + * @param thePrettyPrint The pretty print flag to use in the request (default is false) */ void setPrettyPrint(Boolean thePrettyPrint); @@ -109,4 +105,8 @@ public interface IRestfulClient { */ void unregisterInterceptor(IClientInterceptor theInterceptor); + /** + * Configures what style of _format parameter should be used in requests + */ + void setFormatParamStyle(RequestFormatParamStyleEnum theRequestFormatParamStyle); } diff --git a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/BaseClient.java b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/BaseClient.java index 0b447575917..3b1f404075a 100644 --- a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/BaseClient.java +++ b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/BaseClient.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.rest.client.impl; * 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. @@ -20,49 +20,11 @@ package ca.uhn.fhir.rest.client.impl; * #L% */ -import static org.apache.commons.lang3.StringUtils.isNotBlank; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.io.StringReader; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import ca.uhn.fhir.rest.api.CacheControlDirective; -import ca.uhn.fhir.util.XmlDetectionUtil; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.Validate; -import org.hl7.fhir.instance.model.api.IBase; -import org.hl7.fhir.instance.model.api.IBaseOperationOutcome; -import org.hl7.fhir.instance.model.api.IBaseResource; -import org.hl7.fhir.instance.model.api.IIdType; -import org.hl7.fhir.instance.model.api.IPrimitiveType; - -import ca.uhn.fhir.context.BaseRuntimeChildDefinition; -import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition; -import ca.uhn.fhir.context.BaseRuntimeElementDefinition; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.context.RuntimeResourceDefinition; +import ca.uhn.fhir.context.*; import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.parser.IParser; -import ca.uhn.fhir.rest.api.Constants; -import ca.uhn.fhir.rest.api.EncodingEnum; -import ca.uhn.fhir.rest.api.SummaryEnum; -import ca.uhn.fhir.rest.client.api.IClientInterceptor; -import ca.uhn.fhir.rest.client.api.IHttpClient; -import ca.uhn.fhir.rest.client.api.IHttpRequest; -import ca.uhn.fhir.rest.client.api.IHttpResponse; -import ca.uhn.fhir.rest.client.api.IRestfulClient; -import ca.uhn.fhir.rest.client.api.IRestfulClientFactory; -import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; +import ca.uhn.fhir.rest.api.*; +import ca.uhn.fhir.rest.client.api.*; import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException; import ca.uhn.fhir.rest.client.exceptions.InvalidResponseException; import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException; @@ -72,7 +34,19 @@ import ca.uhn.fhir.rest.client.method.IClientResponseHandlerHandlesBinary; import ca.uhn.fhir.rest.client.method.MethodUtil; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.util.OperationOutcomeUtil; -import ca.uhn.fhir.util.XmlUtil; +import ca.uhn.fhir.util.XmlDetectionUtil; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; +import org.hl7.fhir.instance.model.api.*; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.io.StringReader; +import java.util.*; + +import static org.apache.commons.lang3.StringUtils.isNotBlank; public abstract class BaseClient implements IRestfulClient { @@ -86,16 +60,17 @@ public abstract class BaseClient implements IRestfulClient { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseClient.class); private final IHttpClient myClient; + private final RestfulClientFactory myFactory; + private final String myUrlBase; private boolean myDontValidateConformance; private EncodingEnum myEncoding = null; // default unspecified (will be XML) - private final RestfulClientFactory myFactory; private List myInterceptors = new ArrayList(); private boolean myKeepResponses = false; private IHttpResponse myLastResponse; private String myLastResponseBody; private Boolean myPrettyPrint = false; private SummaryEnum mySummary; - private final String myUrlBase; + private RequestFormatParamStyleEnum myRequestFormatParamStyle = RequestFormatParamStyleEnum.SHORT; BaseClient(IHttpClient theClient, String theUrlBase, RestfulClientFactory theFactory) { super(); @@ -121,10 +96,12 @@ public abstract class BaseClient implements IRestfulClient { protected Map> createExtraParams() { HashMap> retVal = new LinkedHashMap>(); - if (getEncoding() == EncodingEnum.XML) { - retVal.put(Constants.PARAM_FORMAT, Collections.singletonList("xml")); - } else if (getEncoding() == EncodingEnum.JSON) { - retVal.put(Constants.PARAM_FORMAT, Collections.singletonList("json")); + if (myRequestFormatParamStyle == RequestFormatParamStyleEnum.SHORT) { + if (getEncoding() == EncodingEnum.XML) { + retVal.put(Constants.PARAM_FORMAT, Collections.singletonList("xml")); + } else if (getEncoding() == EncodingEnum.JSON) { + retVal.put(Constants.PARAM_FORMAT, Collections.singletonList("json")); + } } if (isPrettyPrint()) { @@ -150,6 +127,17 @@ public abstract class BaseClient implements IRestfulClient { return myEncoding; } + /** + * Sets the encoding that will be used on requests. Default is null, which means the client will not + * explicitly request an encoding. (This is perfectly acceptable behaviour according to the FHIR specification. In + * this case, the server will choose which encoding to return, and the client can handle either XML or JSON) + */ + @Override + public void setEncoding(EncodingEnum theEncoding) { + myEncoding = theEncoding; + // return this; + } + /** * {@inheritDoc} */ @@ -192,10 +180,21 @@ public abstract class BaseClient implements IRestfulClient { return mySummary; } + @Override + public void setSummary(SummaryEnum theSummary) { + mySummary = theSummary; + } + public String getUrlBase() { return myUrlBase; } + @Override + public void setFormatParamStyle(RequestFormatParamStyleEnum theRequestFormatParamStyle) { + Validate.notNull(theRequestFormatParamStyle, "theRequestFormatParamStyle must not be null"); + myRequestFormatParamStyle = theRequestFormatParamStyle; + } + T invokeClient(FhirContext theContext, IClientResponseHandler binding, BaseHttpClientInvocation clientInvocation) { return invokeClient(theContext, binding, clientInvocation, false); } @@ -219,10 +218,12 @@ public abstract class BaseClient implements IRestfulClient { Map> params = createExtraParams(); if (clientInvocation instanceof HttpGetClientInvocation) { - if (theEncoding == EncodingEnum.XML) { - params.put(Constants.PARAM_FORMAT, Collections.singletonList("xml")); - } else if (theEncoding == EncodingEnum.JSON) { - params.put(Constants.PARAM_FORMAT, Collections.singletonList("json")); + if (myRequestFormatParamStyle == RequestFormatParamStyleEnum.SHORT) { + if (theEncoding == EncodingEnum.XML) { + params.put(Constants.PARAM_FORMAT, Collections.singletonList("xml")); + } else if (theEncoding == EncodingEnum.JSON) { + params.put(Constants.PARAM_FORMAT, Collections.singletonList("json")); + } } } @@ -252,7 +253,7 @@ public abstract class BaseClient implements IRestfulClient { addToCacheControlHeader(b, Constants.CACHE_CONTROL_NO_CACHE, theCacheControlDirective.isNoCache()); addToCacheControlHeader(b, Constants.CACHE_CONTROL_NO_STORE, theCacheControlDirective.isNoStore()); if (theCacheControlDirective.getMaxResults() != null) { - addToCacheControlHeader(b, Constants.CACHE_CONTROL_MAX_RESULTS+"="+ Integer.toString(theCacheControlDirective.getMaxResults().intValue()), true); + addToCacheControlHeader(b, Constants.CACHE_CONTROL_MAX_RESULTS + "=" + Integer.toString(theCacheControlDirective.getMaxResults().intValue()), true); } if (b.length() > 0) { httpRequest.addHeader(Constants.HEADER_CACHE_CONTROL, b.toString()); @@ -397,6 +398,13 @@ public abstract class BaseClient implements IRestfulClient { return myKeepResponses; } + /** + * For now, this is a part of the internal API of HAPI - Use with caution as this method may change! + */ + public void setKeepResponses(boolean theKeepResponses) { + myKeepResponses = theKeepResponses; + } + /** * Returns the pretty print flag, which is a request to the server for it to return "pretty printed" responses. Note * that this is currently a non-standard flag (_pretty) which is supported only by HAPI based servers (and any other @@ -406,6 +414,17 @@ public abstract class BaseClient implements IRestfulClient { return Boolean.TRUE.equals(myPrettyPrint); } + /** + * Sets the pretty print flag, which is a request to the server for it to return "pretty printed" responses. Note + * that this is currently a non-standard flag (_pretty) which is supported only by HAPI based servers (and any other + * servers which might implement it). + */ + @Override + public void setPrettyPrint(Boolean thePrettyPrint) { + myPrettyPrint = thePrettyPrint; + // return this; + } + private void keepResponseAndLogIt(boolean theLogRequestAndResponse, IHttpResponse response, String responseString) { if (myKeepResponses) { myLastResponse = response; @@ -438,55 +457,12 @@ public abstract class BaseClient implements IRestfulClient { myDontValidateConformance = theDontValidateConformance; } - /** - * Sets the encoding that will be used on requests. Default is null, which means the client will not - * explicitly request an encoding. (This is perfectly acceptable behaviour according to the FHIR specification. In - * this case, the server will choose which encoding to return, and the client can handle either XML or JSON) - */ - @Override - public void setEncoding(EncodingEnum theEncoding) { - myEncoding = theEncoding; - // return this; - } - - /** - * For now, this is a part of the internal API of HAPI - Use with caution as this method may change! - */ - public void setKeepResponses(boolean theKeepResponses) { - myKeepResponses = theKeepResponses; - } - - /** - * Sets the pretty print flag, which is a request to the server for it to return "pretty printed" responses. Note - * that this is currently a non-standard flag (_pretty) which is supported only by HAPI based servers (and any other - * servers which might implement it). - */ - @Override - public void setPrettyPrint(Boolean thePrettyPrint) { - myPrettyPrint = thePrettyPrint; - // return this; - } - - @Override - public void setSummary(SummaryEnum theSummary) { - mySummary = theSummary; - } - @Override public void unregisterInterceptor(IClientInterceptor theInterceptor) { Validate.notNull(theInterceptor, "Interceptor can not be null"); myInterceptors.remove(theInterceptor); } - static ArrayList> toTypeList(Class thePreferResponseType) { - ArrayList> preferResponseTypes = null; - if (thePreferResponseType != null) { - preferResponseTypes = new ArrayList>(1); - preferResponseTypes.add(thePreferResponseType); - } - return preferResponseTypes; - } - protected final class ResourceResponseHandler implements IClientResponseHandler { private boolean myAllowHtmlResponse; @@ -568,4 +544,13 @@ public abstract class BaseClient implements IRestfulClient { } } + static ArrayList> toTypeList(Class thePreferResponseType) { + ArrayList> preferResponseTypes = null; + if (thePreferResponseType != null) { + preferResponseTypes = new ArrayList>(1); + preferResponseTypes.add(thePreferResponseType); + } + return preferResponseTypes; + } + } diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/ClientHeadersR4Test.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/ClientHeadersR4Test.java index 9d4fdf78a12..fc690862fdd 100644 --- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/ClientHeadersR4Test.java +++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/ClientHeadersR4Test.java @@ -1,17 +1,13 @@ package ca.uhn.fhir.rest.client; import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.api.RequestFormatParamStyleEnum; import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; import ca.uhn.fhir.util.RandomServerPortProvider; import ca.uhn.fhir.util.TestUtil; -import ca.uhn.fhir.util.VersionUtil; -import org.apache.commons.io.IOUtils; -import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; -import org.apache.http.client.methods.HttpUriRequest; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; @@ -20,9 +16,7 @@ import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import org.mockito.ArgumentCaptor; -import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -40,8 +34,9 @@ public class ClientHeadersR4Test { private static Server ourServer; private static String ourServerBase; private static HashMap> ourHeaders; - private static IGenericClient ourClient; + private static HashMap ourParams; private static String ourMethod; + private IGenericClient myClient; @Before public void before() { @@ -49,34 +44,125 @@ public class ClientHeadersR4Test { ourMethod = null; } - private String expectedUserAgent() { - return "HAPI-FHIR/" + VersionUtil.getVersion() + " (FHIR Client; FHIR " + FhirVersionEnum.R4.getFhirVersionString() + "/R4; apache)"; - } - - private byte[] extractBodyAsByteArray(ArgumentCaptor capt) throws IOException { - byte[] body = IOUtils.toByteArray(((HttpEntityEnclosingRequestBase) capt.getAllValues().get(0)).getEntity().getContent()); - return body; - } - - private String extractBodyAsString(ArgumentCaptor capt) throws IOException { - String body = IOUtils.toString(((HttpEntityEnclosingRequestBase) capt.getAllValues().get(0)).getEntity().getContent(), "UTF-8"); - return body; - } - @Test - public void testCreateWithPreferRepresentationServerReturnsResource() throws Exception { + public void testReadXml() { + myClient + .read() + .resource("Patient") + .withId(123L) + .encodedXml() + .execute(); + + assertEquals("application/fhir+xml;q=1.0, application/xml+fhir;q=0.9", ourHeaders.get(Constants.HEADER_ACCEPT).get(0)); + assertEquals("xml", ourParams.get(Constants.PARAM_FORMAT)[0]); + } + + @Test + public void testReadXmlNoParam() { + myClient.setFormatParamStyle(RequestFormatParamStyleEnum.NONE); + myClient + .read() + .resource("Patient") + .withId(123L) + .encodedXml() + .execute(); + + assertEquals("application/fhir+xml;q=1.0, application/xml+fhir;q=0.9", ourHeaders.get(Constants.HEADER_ACCEPT).get(0)); + assertEquals(null, ourParams.get(Constants.PARAM_FORMAT)); + } + + @Test + public void testReadJson() { + myClient + .read() + .resource("Patient") + .withId(123L) + .encodedJson() + .execute(); + + assertEquals("application/fhir+json;q=1.0, application/json+fhir;q=0.9", ourHeaders.get(Constants.HEADER_ACCEPT).get(0)); + assertEquals("json", ourParams.get(Constants.PARAM_FORMAT)[0]); + } + + @Test + public void testReadJsonNoParam() { + myClient.setFormatParamStyle(RequestFormatParamStyleEnum.NONE); + myClient + .read() + .resource("Patient") + .withId(123L) + .encodedJson() + .execute(); + + assertEquals("application/fhir+json;q=1.0, application/json+fhir;q=0.9", ourHeaders.get(Constants.HEADER_ACCEPT).get(0)); + assertEquals(null, ourParams.get(Constants.PARAM_FORMAT)); + } + + @Test + public void testReadXmlDisable() { + myClient + .read() + .resource("Patient") + .withId(123L) + .encodedXml() + .execute(); + + assertEquals("application/fhir+xml;q=1.0, application/xml+fhir;q=0.9", ourHeaders.get(Constants.HEADER_ACCEPT).get(0)); + assertEquals("xml", ourParams.get(Constants.PARAM_FORMAT)[0]); + } + + @Test + public void testCreateWithPreferRepresentationServerReturnsResource() { final Patient resp1 = new Patient(); resp1.setActive(true); - MethodOutcome resp = ourClient.create().resource(resp1).execute(); + MethodOutcome resp = myClient.create().resource(resp1).execute(); assertNotNull(resp); assertEquals(1, ourHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); assertEquals("application/fhir+xml; charset=UTF-8", ourHeaders.get(Constants.HEADER_CONTENT_TYPE).get(0)); } + @Before + public void beforeCreateClient() { + myClient = ourCtx.newRestfulGenericClient(ourServerBase); + } + + private static class TestServlet extends HttpServlet { + + @Override + protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException { + + if (ourHeaders != null) { + fail(); + } + ourHeaders = new HashMap<>(); + ourParams = new HashMap<>(req.getParameterMap()); + ourMethod = req.getMethod(); + Enumeration names = req.getHeaderNames(); + while (names.hasMoreElements()) { + String nextName = names.nextElement(); + ourHeaders.put(nextName, new ArrayList<>()); + Enumeration values = req.getHeaders(nextName); + while (values.hasMoreElements()) { + ourHeaders.get(nextName).add(values.nextElement()); + } + } + + resp.setStatus(200); + + if (req.getMethod().equals("GET")) { + resp.setContentType("application/json"); + resp.getWriter().append("{\"resourceType\":\"Patient\"}"); + resp.getWriter().close(); + } + + } + + } + @AfterClass public static void afterClassClearContext() { TestUtil.clearAllStaticFieldsForUnitTest(); @@ -94,7 +180,6 @@ public class ClientHeadersR4Test { ourServerBase = "http://localhost:" + myPort + "/fhir/context"; ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); - ourClient = ourCtx.newRestfulGenericClient(ourServerBase); ServletHolder servletHolder = new ServletHolder(); servletHolder.setServlet(new TestServlet()); @@ -105,29 +190,4 @@ public class ClientHeadersR4Test { } - private static class TestServlet extends HttpServlet { - - @Override - protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - - if (ourHeaders != null) { - fail(); - } - ourHeaders = new HashMap<>(); - ourMethod = req.getMethod(); - Enumeration names = req.getHeaderNames(); - while (names.hasMoreElements()) { - String nextName = names.nextElement(); - ourHeaders.put(nextName, new ArrayList()); - Enumeration values = req.getHeaders(nextName); - while (values.hasMoreElements()) { - ourHeaders.get(nextName).add(values.nextElement()); - } - } - - resp.setStatus(200); - } - - } - } diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 8d7249421d2..560889f4481 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -171,7 +171,12 @@ When restful reponses tried to return multiple instances of the same response header, some instances were discarded. Thanks to Volker Schmidt for the pull request! - " + + + The REST client now allows for configurable behaviour as to whether a + _format]]> + parameter should be included in requests. +