Fix responsehighlighterinterceptor to work with graphql
This commit is contained in:
parent
33767b5399
commit
b127867ef7
|
@ -400,6 +400,12 @@ public enum Pointcut {
|
||||||
* <li>
|
* <li>
|
||||||
* java.lang.String - The GraphQL response
|
* java.lang.String - The GraphQL response
|
||||||
* </li>
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* javax.servlet.http.HttpServletRequest - The servlet request, when running in a servlet environment
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* javax.servlet.http.HttpServletResponse - The servlet response, when running in a servlet environment
|
||||||
|
* </li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* </p>
|
* </p>
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -417,7 +423,9 @@ public enum Pointcut {
|
||||||
"ca.uhn.fhir.rest.api.server.RequestDetails",
|
"ca.uhn.fhir.rest.api.server.RequestDetails",
|
||||||
"ca.uhn.fhir.rest.server.servlet.ServletRequestDetails",
|
"ca.uhn.fhir.rest.server.servlet.ServletRequestDetails",
|
||||||
"java.lang.String",
|
"java.lang.String",
|
||||||
"java.lang.String"
|
"java.lang.String",
|
||||||
|
"javax.servlet.http.HttpServletRequest",
|
||||||
|
"javax.servlet.http.HttpServletResponse"
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ package ca.uhn.fhir.rest.server.interceptor;
|
||||||
public class InterceptorOrders {
|
public class InterceptorOrders {
|
||||||
|
|
||||||
public static final int SERVE_MEDIA_RESOURCE_RAW_INTERCEPTOR = 1000;
|
public static final int SERVE_MEDIA_RESOURCE_RAW_INTERCEPTOR = 1000;
|
||||||
|
|
||||||
public static final int RESPONSE_HIGHLIGHTER_INTERCEPTOR = 10000;
|
public static final int RESPONSE_HIGHLIGHTER_INTERCEPTOR = 10000;
|
||||||
|
|
||||||
/** Non instantiable */
|
/** Non instantiable */
|
||||||
|
|
|
@ -268,7 +268,7 @@ public class ResponseHighlighterInterceptor {
|
||||||
responseDetails.setResponseCode(theException.getStatusCode());
|
responseDetails.setResponseCode(theException.getStatusCode());
|
||||||
|
|
||||||
BaseResourceReturningMethodBinding.callOutgoingFailureOperationOutcomeHook(theRequestDetails, oo);
|
BaseResourceReturningMethodBinding.callOutgoingFailureOperationOutcomeHook(theRequestDetails, oo);
|
||||||
streamResponse(theRequestDetails, theServletResponse, responseDetails.getResponseResource(), theServletRequest, responseDetails.getResponseCode());
|
streamResponse(theRequestDetails, theServletResponse, responseDetails.getResponseResource(), null, theServletRequest, responseDetails.getResponseCode());
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -313,10 +313,39 @@ public class ResponseHighlighterInterceptor {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Hook(value = Pointcut.SERVER_OUTGOING_GRAPHQL_RESPONSE, order = InterceptorOrders.RESPONSE_HIGHLIGHTER_INTERCEPTOR)
|
||||||
|
public boolean outgoingGraphqlResponse(RequestDetails theRequestDetails, String theRequest, String theResponse, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse)
|
||||||
|
throws AuthenticationException {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return true here so that we still fire SERVER_OUTGOING_GRAPHQL_RESPONSE!
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (handleOutgoingResponse(theRequestDetails, null, theServletRequest, theServletResponse, theResponse, null)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
theRequestDetails.setAttribute("ResponseHighlighterInterceptorHandled", Boolean.TRUE);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Hook(value = Pointcut.SERVER_OUTGOING_RESPONSE, order = InterceptorOrders.RESPONSE_HIGHLIGHTER_INTERCEPTOR)
|
@Hook(value = Pointcut.SERVER_OUTGOING_RESPONSE, order = InterceptorOrders.RESPONSE_HIGHLIGHTER_INTERCEPTOR)
|
||||||
public boolean outgoingResponse(RequestDetails theRequestDetails, ResponseDetails theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse)
|
public boolean outgoingResponse(RequestDetails theRequestDetails, ResponseDetails theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse)
|
||||||
throws AuthenticationException {
|
throws AuthenticationException {
|
||||||
|
|
||||||
|
if (!Boolean.TRUE.equals(theRequestDetails.getAttribute("ResponseHighlighterInterceptorHandled"))) {
|
||||||
|
String graphqlResponse = null;
|
||||||
|
IBaseResource resourceResponse = theResponseObject.getResponseResource();
|
||||||
|
if (handleOutgoingResponse(theRequestDetails, theResponseObject, theServletRequest, theServletResponse, graphqlResponse, resourceResponse)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handleOutgoingResponse(RequestDetails theRequestDetails, ResponseDetails theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse, String theGraphqlResponse, IBaseResource theResourceResponse) {
|
||||||
/*
|
/*
|
||||||
* Request for _raw
|
* Request for _raw
|
||||||
*/
|
*/
|
||||||
|
@ -380,12 +409,11 @@ public class ResponseHighlighterInterceptor {
|
||||||
/*
|
/*
|
||||||
* Not binary
|
* Not binary
|
||||||
*/
|
*/
|
||||||
if (!force && (theResponseObject.getResponseResource() instanceof IBaseBinary)) {
|
if (!force && theResponseObject != null && (theResponseObject.getResponseResource() instanceof IBaseBinary)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
streamResponse(theRequestDetails, theServletResponse, theResponseObject.getResponseResource(), theServletRequest, 200);
|
streamResponse(theRequestDetails, theServletResponse, theResourceResponse, theGraphqlResponse, theServletRequest, 200);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,40 +435,51 @@ public class ResponseHighlighterInterceptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void streamResponse(RequestDetails theRequestDetails, HttpServletResponse theServletResponse, IBaseResource theResource, ServletRequest theServletRequest, int theStatusCode) {
|
private void streamResponse(RequestDetails theRequestDetails, HttpServletResponse theServletResponse, IBaseResource theResource, String theGraphqlResponse, ServletRequest theServletRequest, int theStatusCode) {
|
||||||
|
EncodingEnum encoding;
|
||||||
|
String encoded;
|
||||||
|
Map<String, String[]> parameters = theRequestDetails.getParameters();
|
||||||
|
|
||||||
|
if (isNotBlank(theGraphqlResponse)) {
|
||||||
|
|
||||||
|
encoded = theGraphqlResponse;
|
||||||
|
encoding = EncodingEnum.JSON;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
IParser p;
|
||||||
|
if (parameters.containsKey(Constants.PARAM_FORMAT)) {
|
||||||
|
FhirVersionEnum forVersion = theResource.getStructureFhirVersionEnum();
|
||||||
|
p = RestfulServerUtils.getNewParser(theRequestDetails.getServer().getFhirContext(), forVersion, theRequestDetails);
|
||||||
|
} else {
|
||||||
|
EncodingEnum defaultResponseEncoding = theRequestDetails.getServer().getDefaultResponseEncoding();
|
||||||
|
p = defaultResponseEncoding.newParser(theRequestDetails.getServer().getFhirContext());
|
||||||
|
RestfulServerUtils.configureResponseParser(theRequestDetails, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This interceptor defaults to pretty printing unless the user
|
||||||
|
// has specifically requested us not to
|
||||||
|
boolean prettyPrintResponse = true;
|
||||||
|
String[] prettyParams = parameters.get(Constants.PARAM_PRETTY);
|
||||||
|
if (prettyParams != null && prettyParams.length > 0) {
|
||||||
|
if (Constants.PARAM_PRETTY_VALUE_FALSE.equals(prettyParams[0])) {
|
||||||
|
prettyPrintResponse = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (prettyPrintResponse) {
|
||||||
|
p.setPrettyPrint(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
encoding = p.getEncoding();
|
||||||
|
encoded = p.encodeResourceToString(theResource);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (theRequestDetails.getServer() instanceof RestfulServer) {
|
if (theRequestDetails.getServer() instanceof RestfulServer) {
|
||||||
RestfulServer rs = (RestfulServer) theRequestDetails.getServer();
|
RestfulServer rs = (RestfulServer) theRequestDetails.getServer();
|
||||||
rs.addHeadersToResponse(theServletResponse);
|
rs.addHeadersToResponse(theServletResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
IParser p;
|
|
||||||
Map<String, String[]> parameters = theRequestDetails.getParameters();
|
|
||||||
if (parameters.containsKey(Constants.PARAM_FORMAT)) {
|
|
||||||
FhirVersionEnum forVersion = theResource.getStructureFhirVersionEnum();
|
|
||||||
p = RestfulServerUtils.getNewParser(theRequestDetails.getServer().getFhirContext(), forVersion, theRequestDetails);
|
|
||||||
} else {
|
|
||||||
EncodingEnum defaultResponseEncoding = theRequestDetails.getServer().getDefaultResponseEncoding();
|
|
||||||
p = defaultResponseEncoding.newParser(theRequestDetails.getServer().getFhirContext());
|
|
||||||
RestfulServerUtils.configureResponseParser(theRequestDetails, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This interceptor defaults to pretty printing unless the user
|
|
||||||
// has specifically requested us not to
|
|
||||||
boolean prettyPrintResponse = true;
|
|
||||||
String[] prettyParams = parameters.get(Constants.PARAM_PRETTY);
|
|
||||||
if (prettyParams != null && prettyParams.length > 0) {
|
|
||||||
if (Constants.PARAM_PRETTY_VALUE_FALSE.equals(prettyParams[0])) {
|
|
||||||
prettyPrintResponse = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (prettyPrintResponse) {
|
|
||||||
p.setPrettyPrint(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
EncodingEnum encoding = p.getEncoding();
|
|
||||||
String encoded = p.encodeResourceToString(theResource);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
if (theStatusCode > 299) {
|
if (theStatusCode > 299) {
|
||||||
|
@ -545,27 +584,30 @@ public class ResponseHighlighterInterceptor {
|
||||||
outputBuffer.append(" <body>");
|
outputBuffer.append(" <body>");
|
||||||
|
|
||||||
outputBuffer.append("<p>");
|
outputBuffer.append("<p>");
|
||||||
outputBuffer.append("This result is being rendered in HTML for easy viewing. ");
|
|
||||||
outputBuffer.append("You may access this content as ");
|
|
||||||
|
|
||||||
outputBuffer.append("<a href=\"");
|
if (isBlank(theGraphqlResponse)) {
|
||||||
outputBuffer.append(createLinkHref(parameters, Constants.FORMAT_JSON));
|
outputBuffer.append("This result is being rendered in HTML for easy viewing. ");
|
||||||
outputBuffer.append("\">Raw JSON</a> or ");
|
outputBuffer.append("You may access this content as ");
|
||||||
|
|
||||||
outputBuffer.append("<a href=\"");
|
outputBuffer.append("<a href=\"");
|
||||||
outputBuffer.append(createLinkHref(parameters, Constants.FORMAT_XML));
|
outputBuffer.append(createLinkHref(parameters, Constants.FORMAT_JSON));
|
||||||
outputBuffer.append("\">Raw XML</a>, ");
|
outputBuffer.append("\">Raw JSON</a> or ");
|
||||||
|
|
||||||
outputBuffer.append(" or view this content in ");
|
outputBuffer.append("<a href=\"");
|
||||||
|
outputBuffer.append(createLinkHref(parameters, Constants.FORMAT_XML));
|
||||||
|
outputBuffer.append("\">Raw XML</a>, ");
|
||||||
|
|
||||||
outputBuffer.append("<a href=\"");
|
outputBuffer.append(" or view this content in ");
|
||||||
outputBuffer.append(createLinkHref(parameters, Constants.FORMATS_HTML_JSON));
|
|
||||||
outputBuffer.append("\">HTML JSON</a> ");
|
|
||||||
|
|
||||||
outputBuffer.append("or ");
|
outputBuffer.append("<a href=\"");
|
||||||
outputBuffer.append("<a href=\"");
|
outputBuffer.append(createLinkHref(parameters, Constants.FORMATS_HTML_JSON));
|
||||||
outputBuffer.append(createLinkHref(parameters, Constants.FORMATS_HTML_XML));
|
outputBuffer.append("\">HTML JSON</a> ");
|
||||||
outputBuffer.append("\">HTML XML</a>.");
|
|
||||||
|
outputBuffer.append("or ");
|
||||||
|
outputBuffer.append("<a href=\"");
|
||||||
|
outputBuffer.append(createLinkHref(parameters, Constants.FORMATS_HTML_XML));
|
||||||
|
outputBuffer.append("\">HTML XML</a>.");
|
||||||
|
}
|
||||||
|
|
||||||
Date startTime = (Date) theServletRequest.getAttribute(RestfulServer.REQUEST_START_TIME);
|
Date startTime = (Date) theServletRequest.getAttribute(RestfulServer.REQUEST_START_TIME);
|
||||||
if (startTime != null) {
|
if (startTime != null) {
|
||||||
|
|
|
@ -106,7 +106,9 @@ public class GraphQLMethodBinding extends BaseMethodBinding<String> {
|
||||||
.add(RequestDetails.class, theRequest)
|
.add(RequestDetails.class, theRequest)
|
||||||
.addIfMatchesType(ServletRequestDetails.class, theRequest)
|
.addIfMatchesType(ServletRequestDetails.class, theRequest)
|
||||||
.add(String.class, theRequest.getParameters().get(Constants.PARAM_GRAPHQL_QUERY)[0])
|
.add(String.class, theRequest.getParameters().get(Constants.PARAM_GRAPHQL_QUERY)[0])
|
||||||
.add(String.class, responseString);
|
.add(String.class, responseString)
|
||||||
|
.add(HttpServletRequest.class, servletRequest)
|
||||||
|
.add(HttpServletResponse.class, servletResponse);
|
||||||
if (!theRequest.getInterceptorBroadcaster().callHooks(Pointcut.SERVER_OUTGOING_GRAPHQL_RESPONSE, params)) {
|
if (!theRequest.getInterceptorBroadcaster().callHooks(Pointcut.SERVER_OUTGOING_GRAPHQL_RESPONSE, params)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.eclipse.jetty.servlet.ServletHandler;
|
||||||
import org.eclipse.jetty.servlet.ServletHolder;
|
import org.eclipse.jetty.servlet.ServletHolder;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.model.*;
|
import org.hl7.fhir.r4.model.*;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -387,6 +388,21 @@ public class ResponseHighlightingInterceptorTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHighlightGraphQLResponse() throws Exception {
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/A/$graphql?query=" + UrlUtil.escapeUrlParam("{name}"));
|
||||||
|
httpGet.addHeader("Accept", "text/html");
|
||||||
|
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
|
||||||
|
status.close();
|
||||||
|
|
||||||
|
ourLog.info("Resp: {}", responseContent);
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
|
||||||
|
assertThat(responseContent, stringContainsInOrder(""foo""));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHighlightException() throws Exception {
|
public void testHighlightException() throws Exception {
|
||||||
ResponseHighlighterInterceptor ic = ourInterceptor;
|
ResponseHighlighterInterceptor ic = ourInterceptor;
|
||||||
|
@ -799,6 +815,14 @@ public class ResponseHighlightingInterceptorTest {
|
||||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class GraphQLProvider {
|
||||||
|
@GraphQL
|
||||||
|
public String processGraphQlRequest(ServletRequestDetails theRequestDetails, @IdParam IIdType theId, @GraphQLQuery String theQuery) {
|
||||||
|
return "{\"foo\":\"bar\"}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void beforeClass() throws Exception {
|
public static void beforeClass() throws Exception {
|
||||||
ourServer = new Server(0);
|
ourServer = new Server(0);
|
||||||
|
@ -827,7 +851,7 @@ public class ResponseHighlightingInterceptorTest {
|
||||||
ourServlet.registerInterceptor(corsInterceptor);
|
ourServlet.registerInterceptor(corsInterceptor);
|
||||||
|
|
||||||
ourServlet.registerInterceptor(ourInterceptor);
|
ourServlet.registerInterceptor(ourInterceptor);
|
||||||
ourServlet.setResourceProviders(patientProvider, new DummyBinaryResourceProvider());
|
ourServlet.registerProviders(patientProvider, new DummyBinaryResourceProvider(), new GraphQLProvider());
|
||||||
ourServlet.setBundleInclusionRule(BundleInclusionRule.BASED_ON_RESOURCE_PRESENCE);
|
ourServlet.setBundleInclusionRule(BundleInclusionRule.BASED_ON_RESOURCE_PRESENCE);
|
||||||
ServletHolder servletHolder = new ServletHolder(ourServlet);
|
ServletHolder servletHolder = new ServletHolder(ourServlet);
|
||||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||||
|
|
Loading…
Reference in New Issue