Add error handling for cds hooks servlet

This commit is contained in:
Brenin Rhodes
2023-10-03 11:07:19 -06:00
parent 3d51876a8d
commit f33dd6f093
3 changed files with 94 additions and 7 deletions

View File

@@ -44,7 +44,7 @@ public class CdsHooksServlet extends HttpServlet {
// CORS Pre-flight // CORS Pre-flight
@Override @Override
protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//ErrorHandling.setAccessControlHeaders(resp, appProperties); ErrorHandling.setAccessControlHeaders(resp, appProperties);
resp.setHeader("Content-Type", ContentType.APPLICATION_JSON.getMimeType()); resp.setHeader("Content-Type", ContentType.APPLICATION_JSON.getMimeType());
resp.setHeader("X-Content-Type-Options", "nosniff"); resp.setHeader("X-Content-Type-Options", "nosniff");
resp.setStatus(HttpServletResponse.SC_OK); resp.setStatus(HttpServletResponse.SC_OK);
@@ -59,7 +59,7 @@ public class CdsHooksServlet extends HttpServlet {
logger.error(request.getRequestURI()); logger.error(request.getRequestURI());
throw new ServletException("This servlet is not configured to handle GET requests."); throw new ServletException("This servlet is not configured to handle GET requests.");
} }
//ErrorHandling.setAccessControlHeaders(response, myAppProperties); ErrorHandling.setAccessControlHeaders(response, appProperties);
response.setHeader("Content-Type", ContentType.APPLICATION_JSON.getMimeType()); response.setHeader("Content-Type", ContentType.APPLICATION_JSON.getMimeType());
response.getWriter().println(new GsonBuilder().setPrettyPrinting().create().toJson(getServices())); response.getWriter().println(new GsonBuilder().setPrettyPrinting().create().toJson(getServices()));
} }
@@ -90,7 +90,7 @@ public class CdsHooksServlet extends HttpServlet {
response.setContentType("text/json;charset=UTF-8"); response.setContentType("text/json;charset=UTF-8");
response.getWriter().println(jsonResponse); response.getWriter().println(jsonResponse);
} catch (BaseServerResponseException e) { } catch (BaseServerResponseException e) {
// ErrorHandling.handleError(response, "ERROR: Exception connecting to remote server.", e, myAppProperties); ErrorHandling.handleError(response, "ERROR: Exception connecting to remote server.", e, appProperties);
logger.error(e.toString()); logger.error(e.toString());
} catch (Exception e) { } catch (Exception e) {
logger.error(e.toString()); logger.error(e.toString());

View File

@@ -0,0 +1,91 @@
package ca.uhn.fhir.jpa.starter.cdshooks;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Arrays;
import javax.servlet.http.HttpServletResponse;
import ca.uhn.fhir.jpa.starter.AppProperties;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
public class ErrorHandling {
private ErrorHandling() {}
public static void handleError(HttpServletResponse response, String message,
Exception e, AppProperties myAppProperties)
throws IOException {
setAccessControlHeaders(response, myAppProperties);
response.setStatus(500); // This will be overwritten with the correct status code downstream if needed.
response.getWriter().println(message);
printMessageAndCause(e, response);
if (e instanceof BaseServerResponseException) {
handleServerResponseException((BaseServerResponseException) e, response);
} else if (e.getCause() instanceof BaseServerResponseException) {
handleServerResponseException((BaseServerResponseException) e.getCause(), response);
}
printStackTrack(e, response);
}
private static void handleServerResponseException(BaseServerResponseException e, HttpServletResponse response)
throws IOException {
switch (e.getStatusCode()) {
case 401:
case 403:
response.getWriter().println("Precondition Failed. Remote FHIR server returned: " + e.getStatusCode());
response.getWriter().println(
"Ensure that the fhirAuthorization token is set or that the remote server allows unauthenticated access.");
response.setStatus(412);
break;
case 404:
response.getWriter().println("Precondition Failed. Remote FHIR server returned: " + e.getStatusCode());
response.getWriter().println("Ensure the resource exists on the remote server.");
response.setStatus(412);
break;
default:
response.getWriter().println("Unhandled Error in Remote FHIR server: " + e.getStatusCode());
}
}
private static void printMessageAndCause(Exception e, HttpServletResponse response) throws IOException {
if (e.getMessage() != null) {
response.getWriter().println(e.getMessage());
}
if (e.getCause() != null && e.getCause().getMessage() != null) {
response.getWriter().println(e.getCause().getMessage());
}
}
private static void printStackTrack(Exception e, HttpServletResponse response) throws IOException {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
response.getWriter().println(exceptionAsString);
}
public static void setAccessControlHeaders(HttpServletResponse resp, AppProperties myAppProperties) {
if (myAppProperties.getCors() != null) {
if (myAppProperties.getCors().getAllow_Credentials()) {
resp.setHeader("Access-Control-Allow-Origin",
myAppProperties.getCors().getAllowed_origin().stream().findFirst().get());
resp.setHeader("Access-Control-Allow-Methods",
String.join(", ", Arrays.asList("GET", "HEAD", "POST", "OPTIONS")));
resp.setHeader("Access-Control-Allow-Headers",
String.join(", ", Arrays.asList("x-fhir-starter", "Origin",
"Accept", "X-Requested-With", "Content-Type", "Authorization", "Cache-Control")));
resp.setHeader("Access-Control-Expose-Headers",
String.join(", ", Arrays.asList("Location", "Content-Location")));
resp.setHeader("Access-Control-Max-Age", "86400");
}
}
}
public static class CdsHooksError extends RuntimeException {
public CdsHooksError(String message) {
super(message);
}
}
}

View File

@@ -1,16 +1,12 @@
package ca.uhn.fhir.jpa.starter.cdshooks; package ca.uhn.fhir.jpa.starter.cdshooks;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import ca.uhn.fhir.jpa.cache.IResourceChangeListenerRegistry;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.hapi.fhir.cdshooks.api.ICdsHooksDaoAuthorizationSvc; import ca.uhn.hapi.fhir.cdshooks.api.ICdsHooksDaoAuthorizationSvc;
import ca.uhn.hapi.fhir.cdshooks.config.CdsHooksConfig; import ca.uhn.hapi.fhir.cdshooks.config.CdsHooksConfig;
import ca.uhn.hapi.fhir.cdshooks.svc.CdsHooksContextBooter; import ca.uhn.hapi.fhir.cdshooks.svc.CdsHooksContextBooter;