Fix #411 - Searching by POST with urlencoded parameters doesn't work if

interceptors are accessing the parameters and there is are also
parameters on the URL
This commit is contained in:
James Agnew 2016-10-06 13:23:32 -04:00
parent f5eda76388
commit 11d3ae9447
3 changed files with 168 additions and 26 deletions

View File

@ -528,14 +528,10 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
try { try {
for (IServerInterceptor next : myInterceptors) { /* ***********************************
boolean continueProcessing = next.incomingRequestPreProcessed(theRequest, theResponse); * Parse out the request parameters
if (!continueProcessing) { * ***********************************/
ourLog.debug("Interceptor {} returned false, not continuing processing");
return;
}
}
String requestFullPath = StringUtils.defaultString(theRequest.getRequestURI()); String requestFullPath = StringUtils.defaultString(theRequest.getRequestURI());
String servletPath = StringUtils.defaultString(theRequest.getServletPath()); String servletPath = StringUtils.defaultString(theRequest.getServletPath());
StringBuffer requestUrl = theRequest.getRequestURL(); StringBuffer requestUrl = theRequest.getRequestURL();
@ -551,14 +547,6 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
ourLog.trace("Context Path: {}", servletContextPath); ourLog.trace("Context Path: {}", servletContextPath);
} }
String requestPath = getRequestPath(requestFullPath, servletContextPath, servletPath);
if (requestPath.length() > 0 && requestPath.charAt(0) == '/') {
requestPath = requestPath.substring(1);
}
fhirServerBase = getServerBaseForRequest(theRequest);
String completeUrl; String completeUrl;
Map<String, String[]> params = null; Map<String, String[]> params = null;
if (StringUtils.isNotBlank(theRequest.getQueryString())) { if (StringUtils.isNotBlank(theRequest.getQueryString())) {
@ -572,7 +560,7 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
if (isIgnoreServerParsedRequestParameters()) { if (isIgnoreServerParsedRequestParameters()) {
String contentType = theRequest.getHeader(Constants.HEADER_CONTENT_TYPE); String contentType = theRequest.getHeader(Constants.HEADER_CONTENT_TYPE);
if (theRequestType == RequestTypeEnum.POST && isNotBlank(contentType) && contentType.startsWith(Constants.CT_X_FORM_URLENCODED)) { if (theRequestType == RequestTypeEnum.POST && isNotBlank(contentType) && contentType.startsWith(Constants.CT_X_FORM_URLENCODED)) {
String requestBody = new String(requestDetails.loadRequestContents(), Charsets.UTF_8); String requestBody = new String(requestDetails.loadRequestContents(), Constants.CHARSET_UTF8);
params = UrlUtil.parseQueryStrings(theRequest.getQueryString(), requestBody); params = UrlUtil.parseQueryStrings(theRequest.getQueryString(), requestBody);
} else if (theRequestType == RequestTypeEnum.GET) { } else if (theRequestType == RequestTypeEnum.GET) {
params = UrlUtil.parseQueryString(theRequest.getQueryString()); params = UrlUtil.parseQueryString(theRequest.getQueryString());
@ -588,6 +576,28 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
requestDetails.setParameters(params); requestDetails.setParameters(params);
/* *************************
* Notify interceptors about the incoming request
* *************************/
for (IServerInterceptor next : myInterceptors) {
boolean continueProcessing = next.incomingRequestPreProcessed(theRequest, theResponse);
if (!continueProcessing) {
ourLog.debug("Interceptor {} returned false, not continuing processing");
return;
}
}
String requestPath = getRequestPath(requestFullPath, servletContextPath, servletPath);
if (requestPath.length() > 0 && requestPath.charAt(0) == '/') {
requestPath = requestPath.substring(1);
}
fhirServerBase = getServerBaseForRequest(theRequest);
IIdType id; IIdType id;
populateRequestDetailsFromRequestPath(requestDetails, requestPath); populateRequestDetailsFromRequestPath(requestDetails, requestPath);

View File

@ -50,7 +50,7 @@ public class JaxRsResponseDstu3Test {
boolean theAddContentLocationHeader = false; boolean theAddContentLocationHeader = false;
Response result = (Response) RestfulServerUtils.streamResponseAsResource(request.getServer(), bundle, theSummaryMode, 200, theAddContentLocationHeader, respondGzip, request); Response result = (Response) RestfulServerUtils.streamResponseAsResource(request.getServer(), bundle, theSummaryMode, 200, theAddContentLocationHeader, respondGzip, request);
assertEquals(200, result.getStatus()); assertEquals(200, result.getStatus());
assertEquals(Constants.CT_FHIR_JSON+Constants.CHARSET_UTF8_CTSUFFIX, result.getHeaderString(Constants.HEADER_CONTENT_TYPE)); assertEquals(Constants.CT_FHIR_JSON_NEW+Constants.CHARSET_UTF8_CTSUFFIX, result.getHeaderString(Constants.HEADER_CONTENT_TYPE));
assertTrue(result.getEntity().toString().contains("Patient")); assertTrue(result.getEntity().toString().contains("Patient"));
assertTrue(result.getEntity().toString().contains("15")); assertTrue(result.getEntity().toString().contains("15"));
} }
@ -108,7 +108,7 @@ public class JaxRsResponseDstu3Test {
boolean respondGzip = true; boolean respondGzip = true;
Response result = (Response) RestfulServerUtils.streamResponseAsResource(request.getServer(), createPatient(), theSummaryMode, 200, addContentLocationHeader, respondGzip, this.request); Response result = (Response) RestfulServerUtils.streamResponseAsResource(request.getServer(), createPatient(), theSummaryMode, 200, addContentLocationHeader, respondGzip, this.request);
assertEquals(200, result.getStatus()); assertEquals(200, result.getStatus());
assertEquals("application/json+fhir; charset=UTF-8", result.getHeaderString(Constants.HEADER_CONTENT_TYPE)); assertEquals(Constants.CT_FHIR_JSON_NEW+"; charset=UTF-8", result.getHeaderString(Constants.HEADER_CONTENT_TYPE));
assertTrue(result.getEntity().toString().contains("resourceType\": \"Patient")); assertTrue(result.getEntity().toString().contains("resourceType\": \"Patient"));
assertTrue(result.getEntity().toString().contains("15")); assertTrue(result.getEntity().toString().contains("15"));

View File

@ -2,11 +2,16 @@ package ca.uhn.fhir.rest.server;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.NameValuePair; import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.entity.UrlEncodedFormEntity;
@ -30,16 +35,37 @@ import org.junit.Test;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.TagList;
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.annotation.Sort; import ca.uhn.fhir.rest.annotation.Sort;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.SortSpec; import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.param.StringAndListParam; import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.server.SearchPostDstu3Test.ParamLoggingInterceptor;
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.PortUtil; import ca.uhn.fhir.util.PortUtil;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
public class SearchPostDstu3Test { public class SearchPostDstu3Test {
public class ParamLoggingInterceptor extends InterceptorAdapter {
@Override
public boolean incomingRequestPreProcessed(HttpServletRequest theRequest, HttpServletResponse theResponse) {
ourLog.info("Params: {}", theRequest.getParameterMap());
return true;
}
}
private static CloseableHttpClient ourClient; private static CloseableHttpClient ourClient;
private static FhirContext ourCtx = FhirContext.forDstu3(); private static FhirContext ourCtx = FhirContext.forDstu3();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchPostDstu3Test.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchPostDstu3Test.class);
@ -48,24 +74,32 @@ public class SearchPostDstu3Test {
private static String ourLastMethod; private static String ourLastMethod;
private static SortSpec ourLastSortSpec; private static SortSpec ourLastSortSpec;
private static StringAndListParam ourLastName; private static StringAndListParam ourLastName;
private static RestfulServer ourServlet;
@Before @Before
public void before() { public void before() {
ourLastMethod = null; ourLastMethod = null;
ourLastSortSpec = null; ourLastSortSpec = null;
ourLastName = null; ourLastName = null;
for (IServerInterceptor next : new ArrayList<>(ourServlet.getInterceptors())) {
ourServlet.unregisterInterceptor(next);
}
} }
/** /**
* See #411 * See #411
*/ */
@Test @Test
public void testSearchWithMixedParams() throws Exception { public void testSearchWithMixedParamsNoInterceptorsYesParams() throws Exception {
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/_search?_format=application/xml"); HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/_search?_format=application/fhir+json");
httpPost.addHeader("Cache-Control","no-cache");
List<NameValuePair> parameters = Lists.newArrayList(); List<NameValuePair> parameters = Lists.newArrayList();
parameters.add(new BasicNameValuePair("name", "Smith")); parameters.add(new BasicNameValuePair("name", "Smith"));
httpPost.setEntity(new UrlEncodedFormEntity(parameters)); httpPost.setEntity(new UrlEncodedFormEntity(parameters));
ourLog.info("Outgoing post: {}", httpPost);
CloseableHttpResponse status = ourClient.execute(httpPost); CloseableHttpResponse status = ourClient.execute(httpPost);
try { try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
@ -77,13 +111,110 @@ public class SearchPostDstu3Test {
assertEquals(1, ourLastName.getValuesAsQueryTokens().size()); assertEquals(1, ourLastName.getValuesAsQueryTokens().size());
assertEquals(1, ourLastName.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().size()); assertEquals(1, ourLastName.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().size());
assertEquals("Smith", ourLastName.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValue()); assertEquals("Smith", ourLastName.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValue());
assertEquals(Constants.CT_FHIR_JSON_NEW, status.getEntity().getContentType().getValue().replaceAll(";.*", ""));
} finally { } finally {
IOUtils.closeQuietly(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent());
} }
} }
/**
* See #411
*/
@Test
public void testSearchWithMixedParamsNoInterceptorsNoParams() throws Exception {
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/_search");
httpPost.addHeader("Cache-Control","no-cache");
List<NameValuePair> parameters = Lists.newArrayList();
parameters.add(new BasicNameValuePair("name", "Smith"));
httpPost.setEntity(new UrlEncodedFormEntity(parameters));
ourLog.info("Outgoing post: {}", httpPost);
CloseableHttpResponse status = ourClient.execute(httpPost);
try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals("search", ourLastMethod);
assertEquals(null, ourLastSortSpec);
assertEquals(1, ourLastName.getValuesAsQueryTokens().size());
assertEquals(1, ourLastName.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().size());
assertEquals("Smith", ourLastName.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValue());
assertEquals(Constants.CT_FHIR_XML_NEW, status.getEntity().getContentType().getValue().replaceAll(";.*", ""));
} finally {
IOUtils.closeQuietly(status.getEntity().getContent());
}
}
/**
* See #411
*/
@Test
public void testSearchWithMixedParamsYesInterceptorsYesParams() throws Exception {
ourServlet.registerInterceptor(new ParamLoggingInterceptor());
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/_search?_format=application/fhir+json");
httpPost.addHeader("Cache-Control","no-cache");
List<NameValuePair> parameters = Lists.newArrayList();
parameters.add(new BasicNameValuePair("name", "Smith"));
httpPost.setEntity(new UrlEncodedFormEntity(parameters));
ourLog.info("Outgoing post: {}", httpPost);
CloseableHttpResponse status = ourClient.execute(httpPost);
try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals("search", ourLastMethod);
assertEquals(null, ourLastSortSpec);
assertEquals(1, ourLastName.getValuesAsQueryTokens().size());
assertEquals(1, ourLastName.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().size());
assertEquals("Smith", ourLastName.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValue());
assertEquals(Constants.CT_FHIR_JSON_NEW, status.getEntity().getContentType().getValue().replaceAll(";.*", ""));
} finally {
IOUtils.closeQuietly(status.getEntity().getContent());
}
}
/**
* See #411
*/
@Test
public void testSearchWithMixedParamsYesInterceptorsNoParams() throws Exception {
ourServlet.registerInterceptor(new ParamLoggingInterceptor());
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/_search");
httpPost.addHeader("Cache-Control","no-cache");
List<NameValuePair> parameters = Lists.newArrayList();
parameters.add(new BasicNameValuePair("name", "Smith"));
httpPost.setEntity(new UrlEncodedFormEntity(parameters));
ourLog.info("Outgoing post: {}", httpPost);
CloseableHttpResponse status = ourClient.execute(httpPost);
try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals("search", ourLastMethod);
assertEquals(null, ourLastSortSpec);
assertEquals(1, ourLastName.getValuesAsQueryTokens().size());
assertEquals(1, ourLastName.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().size());
assertEquals("Smith", ourLastName.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValue());
assertEquals(Constants.CT_FHIR_XML_NEW, status.getEntity().getContentType().getValue().replaceAll(";.*", ""));
} finally {
IOUtils.closeQuietly(status.getEntity().getContent());
}
}
@AfterClass @AfterClass
public static void afterClassClearContext() throws Exception { public static void afterClassClearContext() throws Exception {
ourServer.stop(); ourServer.stop();
@ -98,11 +229,12 @@ public class SearchPostDstu3Test {
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider(); DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
ServletHandler proxyHandler = new ServletHandler(); ServletHandler proxyHandler = new ServletHandler();
RestfulServer servlet = new RestfulServer(ourCtx); ourServlet = new RestfulServer(ourCtx);
servlet.setPagingProvider(new FifoMemoryPagingProvider(10)); ourServlet.setDefaultResponseEncoding(EncodingEnum.XML);
ourServlet.setPagingProvider(new FifoMemoryPagingProvider(10));
servlet.setResourceProviders(patientProvider); ourServlet.setResourceProviders(patientProvider);
ServletHolder servletHolder = new ServletHolder(servlet); ServletHolder servletHolder = new ServletHolder(ourServlet);
proxyHandler.addServletWithMapping(servletHolder, "/*"); proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler); ourServer.setHandler(proxyHandler);
ourServer.start(); ourServer.start();