Add request ID
This commit is contained in:
parent
1faf7785c4
commit
56aaef641c
|
@ -50,7 +50,7 @@ public class ConsentInterceptors {
|
|||
* Modify resources that are being shown to the user
|
||||
*/
|
||||
@Override
|
||||
public ConsentOutcome seeResource(RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices) {
|
||||
public ConsentOutcome willSeeResource(RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices) {
|
||||
// Don't return the subject for Observation resources
|
||||
if (theResource instanceof Observation) {
|
||||
Observation obs = (Observation)theResource;
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.util.*;
|
|||
|
||||
public class Constants {
|
||||
|
||||
public static final String HEADER_REQUEST_ID = "X-Request-ID";
|
||||
public static final String CACHE_CONTROL_MAX_RESULTS = "max-results";
|
||||
public static final String CACHE_CONTROL_NO_CACHE = "no-cache";
|
||||
public static final String CACHE_CONTROL_NO_STORE = "no-store";
|
||||
|
|
|
@ -469,7 +469,7 @@ public class ConsentInterceptorResourceProviderR4Test extends BaseResourceProvid
|
|||
}
|
||||
return ConsentOutcome.PROCEED;
|
||||
});
|
||||
when(svc.seeResource(any(), any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
when(svc.willSeeResource(any(), any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
|
||||
consentService.setTarget(svc);
|
||||
String query = "{ name { family, given }, managingOrganization { reference, resource {name} } }";
|
||||
|
@ -502,7 +502,7 @@ public class ConsentInterceptorResourceProviderR4Test extends BaseResourceProvid
|
|||
IConsentService svc = mock(IConsentService.class);
|
||||
when(svc.startOperation(any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
when(svc.canSeeResource(any(), any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
when(svc.seeResource(any(RequestDetails.class), any(IBaseResource.class), any())).thenAnswer(t -> {
|
||||
when(svc.willSeeResource(any(RequestDetails.class), any(IBaseResource.class), any())).thenAnswer(t -> {
|
||||
IBaseResource resource = t.getArgument(1, IBaseResource.class);
|
||||
if (resource instanceof Organization) {
|
||||
Organization org = new Organization();
|
||||
|
@ -598,7 +598,7 @@ public class ConsentInterceptorResourceProviderR4Test extends BaseResourceProvid
|
|||
}
|
||||
|
||||
@Override
|
||||
public ConsentOutcome seeResource(RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices) {
|
||||
public ConsentOutcome willSeeResource(RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices) {
|
||||
mySeeCount++;
|
||||
String resourceId = theResource.getIdElement().toUnqualifiedVersionless().getValue();
|
||||
ourLog.info("** SEE: {}", resourceId);
|
||||
|
@ -640,7 +640,7 @@ public class ConsentInterceptorResourceProviderR4Test extends BaseResourceProvid
|
|||
}
|
||||
|
||||
@Override
|
||||
public ConsentOutcome seeResource(RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices) {
|
||||
public ConsentOutcome willSeeResource(RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices) {
|
||||
return ConsentOutcome.PROCEED;
|
||||
}
|
||||
|
||||
|
@ -674,7 +674,7 @@ public class ConsentInterceptorResourceProviderR4Test extends BaseResourceProvid
|
|||
}
|
||||
|
||||
@Override
|
||||
public ConsentOutcome seeResource(RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices) {
|
||||
public ConsentOutcome willSeeResource(RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices) {
|
||||
return ConsentOutcome.PROCEED;
|
||||
}
|
||||
|
||||
|
@ -710,7 +710,7 @@ public class ConsentInterceptorResourceProviderR4Test extends BaseResourceProvid
|
|||
}
|
||||
|
||||
@Override
|
||||
public ConsentOutcome seeResource(RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices) {
|
||||
public ConsentOutcome willSeeResource(RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices) {
|
||||
return ConsentOutcome.PROCEED;
|
||||
}
|
||||
|
||||
|
@ -740,7 +740,7 @@ public class ConsentInterceptorResourceProviderR4Test extends BaseResourceProvid
|
|||
}
|
||||
|
||||
@Override
|
||||
public ConsentOutcome seeResource(RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices) {
|
||||
public ConsentOutcome willSeeResource(RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices) {
|
||||
return ConsentOutcome.PROCEED;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ package ca.uhn.fhir.rest.api.server;
|
|||
*/
|
||||
import java.io.*;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
|
@ -48,6 +50,8 @@ public interface IRestfulResponse {
|
|||
|
||||
void setOperationResourceLastUpdated(IPrimitiveType<Date> theOperationResourceLastUpdated);
|
||||
|
||||
Map<String, List<String>> getHeaders();
|
||||
|
||||
void setOperationResourceId(IIdType theOperationResourceId);
|
||||
|
||||
}
|
||||
|
|
|
@ -37,9 +37,9 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
|
|||
* 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.
|
||||
|
@ -72,6 +72,7 @@ public abstract class RequestDetails {
|
|||
private Map<String, List<String>> myUnqualifiedToQualifiedNames;
|
||||
private Map<Object, Object> myUserData;
|
||||
private IBaseResource myResource;
|
||||
private String myRequestId;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -80,6 +81,14 @@ public abstract class RequestDetails {
|
|||
myInterceptorBroadcaster = theInterceptorBroadcaster;
|
||||
}
|
||||
|
||||
public String getRequestId() {
|
||||
return myRequestId;
|
||||
}
|
||||
|
||||
public void setRequestId(String theRequestId) {
|
||||
myRequestId = theRequestId;
|
||||
}
|
||||
|
||||
public StopWatch getRequestStopwatch() {
|
||||
return myRequestStopwatch;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ public abstract class RestfulResponse<T extends RequestDetails> implements IRest
|
|||
* Get the http headers
|
||||
* @return the headers
|
||||
*/
|
||||
@Override
|
||||
public Map<String, List<String>> getHeaders() {
|
||||
return theHeaders;
|
||||
}
|
||||
|
|
|
@ -9,9 +9,9 @@ package ca.uhn.fhir.rest.server;
|
|||
* 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.
|
||||
|
@ -77,8 +77,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public class RestfulServer extends HttpServlet implements IRestfulServer<ServletRequestDetails> {
|
||||
|
@ -105,6 +104,7 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
|
|||
private static final ExceptionHandlingInterceptor DEFAULT_EXCEPTION_HANDLER = new ExceptionHandlingInterceptor();
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(RestfulServer.class);
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Random RANDOM = new Random();
|
||||
private final List<Object> myPlainProviders = new ArrayList<>();
|
||||
private final List<IResourceProvider> myResourceProviders = new ArrayList<>();
|
||||
private IInterceptorService myInterceptorService;
|
||||
|
@ -171,6 +171,8 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
|
|||
if (isNotBlank(poweredByHeader)) {
|
||||
theHttpResponse.addHeader(Constants.POWERED_BY_HEADER, poweredByHeader);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void addLocationHeader(RequestDetails theRequest, HttpServletResponse theResponse, MethodOutcome response, String headerLocation, String resourceName) {
|
||||
|
@ -561,6 +563,7 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
|
|||
|
||||
/**
|
||||
* Returns a list of all registered server interceptors
|
||||
*
|
||||
* @deprecated As of HAPI FHIR 3.8.0, use {@link #getInterceptorService()} to access the interceptor service. You can register and unregister interceptors using this service.
|
||||
*/
|
||||
@Deprecated
|
||||
|
@ -577,6 +580,7 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
|
|||
|
||||
/**
|
||||
* Returns the interceptor registry for this service. Use this registry to register and unregister
|
||||
*
|
||||
* @since 3.8.0
|
||||
*/
|
||||
@Override
|
||||
|
@ -850,6 +854,10 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
|
|||
requestDetails.setServletRequest(theRequest);
|
||||
requestDetails.setServletResponse(theResponse);
|
||||
|
||||
String requestId = getOrCreateRequestId(theRequest);
|
||||
requestDetails.setRequestId(requestId);
|
||||
addRequestIdToResponse(requestDetails, requestId);
|
||||
|
||||
theRequest.setAttribute(SERVLET_CONTEXT_ATTRIBUTE, getServletContext());
|
||||
|
||||
try {
|
||||
|
@ -1066,6 +1074,40 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
|
|||
}
|
||||
}
|
||||
|
||||
protected void addRequestIdToResponse(ServletRequestDetails theRequestDetails, String theRequestId) {
|
||||
theRequestDetails.getResponse().addHeader(Constants.HEADER_REQUEST_ID, theRequestId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a requet ID from the request headers via the {@link Constants#HEADER_REQUEST_ID}
|
||||
* header, or generates one if none is supplied.
|
||||
* <p>
|
||||
* Note that the generated request ID is a random 64-bit long integer encoded as
|
||||
* hexadecimal. It is not generated using any cryptographic algorithms or a secure
|
||||
* PRNG, so it should not be used for anything other than troubleshooting purposes.
|
||||
* </p>
|
||||
*/
|
||||
protected String getOrCreateRequestId(HttpServletRequest theRequest) {
|
||||
String requestId = theRequest.getHeader(Constants.HEADER_REQUEST_ID);
|
||||
if (isNotBlank(requestId)) {
|
||||
for (char nextChar : requestId.toCharArray()) {
|
||||
if (!Character.isLetterOrDigit(nextChar)) {
|
||||
if (nextChar != '.' && nextChar != '-' && nextChar != '_' && nextChar != ' ') {
|
||||
requestId = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isBlank(requestId)) {
|
||||
requestId = Long.toHexString(RANDOM.nextLong());
|
||||
requestId = leftPad(requestId, 16, '0');
|
||||
}
|
||||
|
||||
return requestId;
|
||||
}
|
||||
|
||||
protected void validateRequest(ServletRequestDetails theRequestDetails) {
|
||||
String[] elements = theRequestDetails.getParameters().get(Constants.PARAM_ELEMENTS);
|
||||
if (elements != null) {
|
||||
|
|
|
@ -8,6 +8,7 @@ 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.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.server.IRestfulResponse;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.api.server.ResponseDetails;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
|
@ -31,10 +32,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
|
@ -402,10 +400,7 @@ public class ResponseHighlighterInterceptor {
|
|||
Enumeration<String> headerValuesEnum = sr.getHeaders(nextHeaderName);
|
||||
while (headerValuesEnum.hasMoreElements()) {
|
||||
String nextHeaderValue = headerValuesEnum.nextElement();
|
||||
b.append("<div class=\"headersRow\">");
|
||||
b.append("<span class=\"headerName\">").append(nextHeaderName).append(": ").append("</span>");
|
||||
b.append("<span class=\"headerValue\">").append(nextHeaderValue).append("</span>");
|
||||
b.append("</div>");
|
||||
appendHeader(b, nextHeaderName, nextHeaderValue);
|
||||
}
|
||||
}
|
||||
b.append("</div>");
|
||||
|
@ -701,14 +696,26 @@ public class ResponseHighlighterInterceptor {
|
|||
nextHeaderValue = responseEncoding.getResourceContentType() + ";charset=utf-8";
|
||||
}
|
||||
}
|
||||
b.append("<div class=\"headersRow\">");
|
||||
b.append("<span class=\"headerName\">").append(nextHeaderName).append(": ").append("</span>");
|
||||
b.append("<span class=\"headerValue\">").append(nextHeaderValue).append("</span>");
|
||||
b.append("</div>");
|
||||
appendHeader(b, nextHeaderName, nextHeaderValue);
|
||||
}
|
||||
}
|
||||
IRestfulResponse response = theRequestDetails.getResponse();
|
||||
for (Map.Entry<String, List<String>> next : response.getHeaders().entrySet()) {
|
||||
String name = next.getKey();
|
||||
for (String nextValue : next.getValue()) {
|
||||
appendHeader(b, name, nextValue);
|
||||
}
|
||||
}
|
||||
|
||||
b.append("</div>");
|
||||
}
|
||||
}
|
||||
|
||||
private void appendHeader(StringBuilder theBuilder, String theHeaderName, String theHeaderValue) {
|
||||
theBuilder.append("<div class=\"headersRow\">");
|
||||
theBuilder.append("<span class=\"headerName\">").append(theHeaderName).append(": ").append("</span>");
|
||||
theBuilder.append("<span class=\"headerValue\">").append(theHeaderValue).append("</span>");
|
||||
theBuilder.append("</div>");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -158,7 +158,7 @@ public class ConsentInterceptor {
|
|||
continue;
|
||||
}
|
||||
|
||||
ConsentOutcome nextOutcome = myConsentService.seeResource(theRequestDetails, nextResource, myContextConsentServices);
|
||||
ConsentOutcome nextOutcome = myConsentService.willSeeResource(theRequestDetails, nextResource, myContextConsentServices);
|
||||
switch (nextOutcome.getStatus()) {
|
||||
case PROCEED:
|
||||
if (nextOutcome.getResource() != null) {
|
||||
|
@ -203,7 +203,7 @@ public class ConsentInterceptor {
|
|||
|
||||
// See outer resource
|
||||
if (alreadySeenResources.putIfAbsent(theResource.getResponseResource(), Boolean.TRUE) == null) {
|
||||
final ConsentOutcome outcome = myConsentService.seeResource(theRequestDetails, theResource.getResponseResource(), myContextConsentServices);
|
||||
final ConsentOutcome outcome = myConsentService.willSeeResource(theRequestDetails, theResource.getResponseResource(), myContextConsentServices);
|
||||
if (outcome.getResource() != null) {
|
||||
theResource.setResponseResource(outcome.getResource());
|
||||
}
|
||||
|
@ -245,7 +245,7 @@ public class ConsentInterceptor {
|
|||
if (alreadySeenResources.putIfAbsent((IBaseResource) theElement, Boolean.TRUE) != null) {
|
||||
return true;
|
||||
}
|
||||
ConsentOutcome childOutcome = myConsentService.seeResource(theRequestDetails, (IBaseResource) theElement, myContextConsentServices);
|
||||
ConsentOutcome childOutcome = myConsentService.willSeeResource(theRequestDetails, (IBaseResource) theElement, myContextConsentServices);
|
||||
|
||||
IBaseResource replacementResource = null;
|
||||
boolean shouldReplaceResource = false;
|
||||
|
|
|
@ -44,8 +44,8 @@ public class DelegatingConsentService implements IConsentService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ConsentOutcome seeResource(RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices) {
|
||||
return myTarget.seeResource(theRequestDetails, theResource ,theContextServices);
|
||||
public ConsentOutcome willSeeResource(RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices) {
|
||||
return myTarget.willSeeResource(theRequestDetails, theResource ,theContextServices);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -51,7 +51,7 @@ public interface IConsentService {
|
|||
* <p>
|
||||
* Implementations should make no attempt to modify the returned result within
|
||||
* this method. For modification use cases (e.g. masking for consent rules) the
|
||||
* user should use the {@link #seeResource(RequestDetails, IBaseResource, IConsentContextServices)}
|
||||
* user should use the {@link #willSeeResource(RequestDetails, IBaseResource, IConsentContextServices)}
|
||||
* method to actually make changes. This method is intended to only
|
||||
* to make decisions.
|
||||
* </p>
|
||||
|
@ -76,7 +76,7 @@ public interface IConsentService {
|
|||
ConsentOutcome canSeeResource(RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices);
|
||||
|
||||
/**
|
||||
* This method is called if a user may potentially see a resource, either completely
|
||||
* This method is called if a user is about to see a resource, either completely
|
||||
* or partially. In other words, if the user is going to see any part of this resource
|
||||
* via READ operations, SEARCH operations, etc., this method is
|
||||
* called. This method may modify the resource in order to filter/mask aspects of
|
||||
|
@ -92,7 +92,7 @@ public interface IConsentService {
|
|||
* </p>
|
||||
* <ul>
|
||||
* <li>{@link ConsentOperationStatusEnum#AUTHORIZED}: The resource will be returned to the client.</li>
|
||||
* <li>{@link ConsentOperationStatusEnum#PROCEED}: The resource will be returned to the client. Any embedded resources contained within the resource will also be checked by {@link #seeResource(RequestDetails, IBaseResource, IConsentContextServices)}.</li>
|
||||
* <li>{@link ConsentOperationStatusEnum#PROCEED}: The resource will be returned to the client. Any embedded resources contained within the resource will also be checked by {@link #willSeeResource(RequestDetails, IBaseResource, IConsentContextServices)}.</li>
|
||||
* <li>{@link ConsentOperationStatusEnum#REJECT}: The resource will not be returned to the client. If the resource supplied to the </li>
|
||||
* </ul>
|
||||
*
|
||||
|
@ -108,7 +108,7 @@ public interface IConsentService {
|
|||
* consent directives.
|
||||
* @return An outcome object. See method documentation for a description.
|
||||
*/
|
||||
ConsentOutcome seeResource(RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices);
|
||||
ConsentOutcome willSeeResource(RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices);
|
||||
|
||||
/**
|
||||
* This method is called when an operation is complete. It can be used to perform
|
||||
|
|
|
@ -40,6 +40,9 @@ import ca.uhn.fhir.rest.server.RestfulResponse;
|
|||
|
||||
public class ServletRestfulResponse extends RestfulResponse<ServletRequestDetails> {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public ServletRestfulResponse(ServletRequestDetails servletRequestDetails) {
|
||||
super(servletRequestDetails);
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@ import org.eclipse.jetty.servlet.ServletHandler;
|
|||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
|
@ -45,8 +44,7 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||
|
@ -364,6 +362,38 @@ public class SearchR4Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestIdGeneratedAndReturned() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_pretty=true");
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String requestId = status.getFirstHeader(Constants.HEADER_REQUEST_ID).getValue();
|
||||
assertThat(requestId, matchesPattern("[a-z0-9]{16}"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestIdSuppliedAndReturned() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_pretty=true");
|
||||
httpGet.addHeader(Constants.HEADER_REQUEST_ID, "help im a bug");
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String requestId = status.getFirstHeader(Constants.HEADER_REQUEST_ID).getValue();
|
||||
assertThat(requestId, matchesPattern("help im a bug"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestIdSuppliedAndReturned_Invalid() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_pretty=true");
|
||||
httpGet.addHeader(Constants.HEADER_REQUEST_ID, "help i'm a bug");
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String requestId = status.getFirstHeader(Constants.HEADER_REQUEST_ID).getValue();
|
||||
assertThat(requestId, matchesPattern("[a-z0-9]{16}"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithInvalidChain() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier.chain=foo%7Cbar");
|
||||
|
|
|
@ -97,7 +97,7 @@ public class ConsentInterceptorTest {
|
|||
|
||||
when(myConsentSvc.startOperation(any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
when(myConsentSvc.canSeeResource(any(), any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
when(myConsentSvc.seeResource(any(), any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
when(myConsentSvc.willSeeResource(any(), any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
|
||||
|
||||
|
@ -131,7 +131,7 @@ public class ConsentInterceptorTest {
|
|||
|
||||
when(myConsentSvc.startOperation(any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
when(myConsentSvc.canSeeResource(any(), any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
when(myConsentSvc.seeResource(any(), any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
when(myConsentSvc.willSeeResource(any(), any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_total=accurate");
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||
|
@ -159,7 +159,7 @@ public class ConsentInterceptorTest {
|
|||
|
||||
when(myConsentSvc.startOperation(any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
when(myConsentSvc.canSeeResource(any(RequestDetails.class), any(IBaseResource.class), any())).thenAnswer(t-> ConsentOutcome.PROCEED);
|
||||
when(myConsentSvc.seeResource(any(RequestDetails.class), any(IBaseResource.class), any())).thenAnswer(t-> ConsentOutcome.AUTHORIZED);
|
||||
when(myConsentSvc.willSeeResource(any(RequestDetails.class), any(IBaseResource.class), any())).thenAnswer(t-> ConsentOutcome.AUTHORIZED);
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
|
||||
|
||||
|
@ -172,7 +172,7 @@ public class ConsentInterceptorTest {
|
|||
|
||||
verify(myConsentSvc, times(1)).startOperation(any(), any());
|
||||
verify(myConsentSvc, times(2)).canSeeResource(any(), any(), any());
|
||||
verify(myConsentSvc, times(3)).seeResource(any(), any(), any());
|
||||
verify(myConsentSvc, times(3)).willSeeResource(any(), any(), any());
|
||||
verify(myConsentSvc, times(1)).completeOperationSuccess(any(), any());
|
||||
verify(myConsentSvc, times(0)).completeOperationFailure(any(), any(), any());
|
||||
verifyNoMoreInteractions(myConsentSvc);
|
||||
|
@ -186,7 +186,7 @@ public class ConsentInterceptorTest {
|
|||
|
||||
when(myConsentSvc.startOperation(any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
when(myConsentSvc.canSeeResource(any(), any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
when(myConsentSvc.seeResource(any(RequestDetails.class), any(IBaseResource.class), any())).thenAnswer(t->{
|
||||
when(myConsentSvc.willSeeResource(any(RequestDetails.class), any(IBaseResource.class), any())).thenAnswer(t->{
|
||||
OperationOutcome oo = new OperationOutcome();
|
||||
oo.addIssue().setDiagnostics("A DIAG");
|
||||
return new ConsentOutcome(ConsentOperationStatusEnum.REJECT, oo);
|
||||
|
@ -203,7 +203,7 @@ public class ConsentInterceptorTest {
|
|||
|
||||
verify(myConsentSvc, times(1)).startOperation(any(), any());
|
||||
verify(myConsentSvc, times(2)).canSeeResource(any(), any(), any());
|
||||
verify(myConsentSvc, times(3)).seeResource(any(), any(), any());
|
||||
verify(myConsentSvc, times(3)).willSeeResource(any(), any(), any());
|
||||
verify(myConsentSvc, times(1)).completeOperationSuccess(any(), any());
|
||||
verify(myConsentSvc, times(0)).completeOperationFailure(any(), any(), any());
|
||||
verifyNoMoreInteractions(myConsentSvc);
|
||||
|
@ -216,7 +216,7 @@ public class ConsentInterceptorTest {
|
|||
|
||||
when(myConsentSvc.startOperation(any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
when(myConsentSvc.canSeeResource(any(RequestDetails.class), any(IBaseResource.class), any())).thenAnswer(t-> ConsentOutcome.PROCEED);
|
||||
when(myConsentSvc.seeResource(any(RequestDetails.class), any(IBaseResource.class), any())).thenAnswer(t-> {
|
||||
when(myConsentSvc.willSeeResource(any(RequestDetails.class), any(IBaseResource.class), any())).thenAnswer(t-> {
|
||||
return ConsentOutcome.REJECT;
|
||||
});
|
||||
|
||||
|
@ -230,7 +230,7 @@ public class ConsentInterceptorTest {
|
|||
|
||||
verify(myConsentSvc, times(1)).startOperation(any(), any());
|
||||
verify(myConsentSvc, times(2)).canSeeResource(any(), any(), any());
|
||||
verify(myConsentSvc, times(3)).seeResource(any(), any(), any()); // the two patients + the bundle
|
||||
verify(myConsentSvc, times(3)).willSeeResource(any(), any(), any()); // the two patients + the bundle
|
||||
verify(myConsentSvc, times(1)).completeOperationSuccess(any(), any());
|
||||
verify(myConsentSvc, times(0)).completeOperationFailure(any(), any(), any());
|
||||
verifyNoMoreInteractions(myConsentSvc);
|
||||
|
@ -243,7 +243,7 @@ public class ConsentInterceptorTest {
|
|||
|
||||
when(myConsentSvc.startOperation(any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
when(myConsentSvc.canSeeResource(any(), any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
when(myConsentSvc.seeResource(any(RequestDetails.class), any(IBaseResource.class), any())).thenAnswer(t->{
|
||||
when(myConsentSvc.willSeeResource(any(RequestDetails.class), any(IBaseResource.class), any())).thenAnswer(t->{
|
||||
IBaseResource resource = (IBaseResource) t.getArguments()[1];
|
||||
if ("PTA".equals(resource.getIdElement().getIdPart())) {
|
||||
OperationOutcome oo = new OperationOutcome();
|
||||
|
@ -268,7 +268,7 @@ public class ConsentInterceptorTest {
|
|||
|
||||
verify(myConsentSvc, times(1)).startOperation(any(), any());
|
||||
verify(myConsentSvc, times(2)).canSeeResource(any(), any(), any());
|
||||
verify(myConsentSvc, times(3)).seeResource(any(), any(), any());
|
||||
verify(myConsentSvc, times(3)).willSeeResource(any(), any(), any());
|
||||
verify(myConsentSvc, times(1)).completeOperationSuccess(any(), any());
|
||||
verify(myConsentSvc, times(0)).completeOperationFailure(any(), any(), any());
|
||||
verifyNoMoreInteractions(myConsentSvc);
|
||||
|
@ -281,7 +281,7 @@ public class ConsentInterceptorTest {
|
|||
|
||||
when(myConsentSvc.startOperation(any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
when(myConsentSvc.canSeeResource(any(), any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
when(myConsentSvc.seeResource(any(RequestDetails.class), any(IBaseResource.class), any())).thenAnswer(t->{
|
||||
when(myConsentSvc.willSeeResource(any(RequestDetails.class), any(IBaseResource.class), any())).thenAnswer(t->{
|
||||
IBaseResource resource = (IBaseResource) t.getArguments()[1];
|
||||
if (resource.getIdElement().getIdPart().equals("PTA")) {
|
||||
Patient replacement = new Patient();
|
||||
|
@ -308,7 +308,7 @@ public class ConsentInterceptorTest {
|
|||
|
||||
verify(myConsentSvc, times(1)).startOperation(any(), any());
|
||||
verify(myConsentSvc, times(2)).canSeeResource(any(), any(), any());
|
||||
verify(myConsentSvc, times(4)).seeResource(any(), any(), any());
|
||||
verify(myConsentSvc, times(4)).willSeeResource(any(), any(), any());
|
||||
verify(myConsentSvc, times(1)).completeOperationSuccess(any(), any());
|
||||
verify(myConsentSvc, times(0)).completeOperationFailure(any(), any(), any());
|
||||
verifyNoMoreInteractions(myConsentSvc);
|
||||
|
@ -321,7 +321,7 @@ public class ConsentInterceptorTest {
|
|||
|
||||
when(myConsentSvc.startOperation(any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
when(myConsentSvc.canSeeResource(any(), any(), any())).thenReturn(ConsentOutcome.PROCEED);
|
||||
when(myConsentSvc.seeResource(any(RequestDetails.class), any(IBaseResource.class), any())).thenAnswer(t->{
|
||||
when(myConsentSvc.willSeeResource(any(RequestDetails.class), any(IBaseResource.class), any())).thenAnswer(t->{
|
||||
IBaseResource resource = (IBaseResource) t.getArguments()[1];
|
||||
if (resource.getIdElement().getIdPart().equals("PTA")) {
|
||||
((Patient)resource).addIdentifier().setSystem("REPLACEMENT");
|
||||
|
@ -345,7 +345,7 @@ public class ConsentInterceptorTest {
|
|||
|
||||
verify(myConsentSvc, times(1)).startOperation(any(), any());
|
||||
verify(myConsentSvc, times(2)).canSeeResource(any(), any(), any());
|
||||
verify(myConsentSvc, times(3)).seeResource(any(), any(), any());
|
||||
verify(myConsentSvc, times(3)).willSeeResource(any(), any(), any());
|
||||
verify(myConsentSvc, times(1)).completeOperationSuccess(any(), any());
|
||||
verify(myConsentSvc, times(0)).completeOperationFailure(any(), any(), any());
|
||||
verifyNoMoreInteractions(myConsentSvc);
|
||||
|
|
|
@ -258,13 +258,15 @@ public class ResponseHighlightingInterceptorTest {
|
|||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
status.close();
|
||||
ourLog.info(responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals("text/html;charset=utf-8", status.getFirstHeader("content-type").getValue().replace(" ", "").toLowerCase());
|
||||
assertThat(responseContent, containsString("html"));
|
||||
assertThat(responseContent, containsString(">{<"));
|
||||
assertThat(responseContent, not(containsString("<")));
|
||||
assertThat(responseContent, containsString(Constants.HEADER_REQUEST_ID));
|
||||
|
||||
ourLog.info(responseContent);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -215,6 +215,11 @@
|
|||
in the processing lifecycle if there is no chance they will be permitted
|
||||
later (i.e. because the type is not authorized at all)
|
||||
</action>
|
||||
<action type="add">
|
||||
The HAPI FHIR server will now generate a random transaction ID to every
|
||||
request and add it to the response headers. Clients may supply the transaction
|
||||
header via the <![CDATA[<code>X-Request-ID</code>]]> header.
|
||||
</action>
|
||||
</release>
|
||||
<release version="3.8.0" date="2019-05-30" description="Hippo">
|
||||
<action type="fix">
|
||||
|
|
Loading…
Reference in New Issue