Add details to ResponseHighlighterInterceptor
This commit is contained in:
parent
ff7d64700b
commit
159377ac16
|
@ -13,7 +13,9 @@ import ca.uhn.fhir.rest.server.RestfulServerUtils.ResponseEncoding;
|
|||
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.util.StopWatch;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -440,206 +442,237 @@ public class ResponseHighlighterInterceptor extends InterceptorAdapter {
|
|||
}
|
||||
theServletResponse.setContentType(Constants.CT_HTML_WITH_UTF8);
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("<html lang=\"en\">\n");
|
||||
b.append(" <head>\n");
|
||||
b.append(" <meta charset=\"utf-8\" />\n");
|
||||
b.append(" <style>\n");
|
||||
b.append(".httpStatusDiv {");
|
||||
b.append(" font-size: 1.2em;");
|
||||
b.append(" font-weight: bold;");
|
||||
b.append("}");
|
||||
b.append(".hlQuot { color: #88F; }\n");
|
||||
b.append(".hlQuot a { text-decoration: underline; text-decoration-color: #CCC; }\n");
|
||||
b.append(".hlQuot a:HOVER { text-decoration: underline; text-decoration-color: #008; }\n");
|
||||
b.append(".hlQuot .uuid, .hlQuot .dateTime {\n");
|
||||
b.append(" user-select: all;\n");
|
||||
b.append(" -moz-user-select: all;\n");
|
||||
b.append(" -webkit-user-select: all;\n");
|
||||
b.append(" -ms-user-select: element;\n");
|
||||
b.append("}\n");
|
||||
b.append(".hlAttr {\n");
|
||||
b.append(" color: #888;\n");
|
||||
b.append("}\n");
|
||||
b.append(".hlTagName {\n");
|
||||
b.append(" color: #006699;\n");
|
||||
b.append("}\n");
|
||||
b.append(".hlControl {\n");
|
||||
b.append(" color: #660000;\n");
|
||||
b.append("}\n");
|
||||
b.append(".hlText {\n");
|
||||
b.append(" color: #000000;\n");
|
||||
b.append("}\n");
|
||||
b.append(".hlUrlBase {\n");
|
||||
b.append("}");
|
||||
b.append(".headersDiv {\n");
|
||||
b.append(" padding: 10px;");
|
||||
b.append(" margin-left: 10px;");
|
||||
b.append(" border: 1px solid #CCC;");
|
||||
b.append(" border-radius: 10px;");
|
||||
b.append("}");
|
||||
b.append(".headersRow {\n");
|
||||
b.append("}");
|
||||
b.append(".headerName {\n");
|
||||
b.append(" color: #888;\n");
|
||||
b.append(" font-family: monospace;\n");
|
||||
b.append("}");
|
||||
b.append(".headerValue {\n");
|
||||
b.append(" color: #88F;\n");
|
||||
b.append(" font-family: monospace;\n");
|
||||
b.append("}");
|
||||
b.append(".responseBodyTable {");
|
||||
b.append(" width: 100%;\n");
|
||||
b.append(" margin-left: 0px;\n");
|
||||
b.append(" margin-top: -10px;\n");
|
||||
b.append(" position: relative;\n");
|
||||
b.append("}");
|
||||
b.append(".responseBodyTableFirstColumn {");
|
||||
b.append(" position: absolute;\n");
|
||||
b.append(" width: 70px;\n");
|
||||
b.append("}");
|
||||
b.append(".responseBodyTableSecondColumn {");
|
||||
b.append(" position: absolute;\n");
|
||||
b.append(" margin-left: 70px;\n");
|
||||
b.append(" vertical-align: top;\n");
|
||||
b.append(" left: 0px;\n");
|
||||
b.append(" right: 0px;\n");
|
||||
b.append("}");
|
||||
b.append(".lineAnchor A {");
|
||||
b.append(" text-decoration: none;");
|
||||
b.append(" padding-left: 20px;");
|
||||
b.append("}");
|
||||
b.append(".lineAnchor {");
|
||||
b.append(" display: block;");
|
||||
b.append(" padding-right: 20px;");
|
||||
b.append("}");
|
||||
b.append(".selectedLine {");
|
||||
b.append(" background-color: #EEF;");
|
||||
b.append(" font-weight: bold;");
|
||||
b.append("}");
|
||||
b.append("H1 {");
|
||||
b.append(" font-size: 1.1em;");
|
||||
b.append(" color: #666;");
|
||||
b.append("}");
|
||||
b.append("BODY {\n");
|
||||
b.append(" font-family: Arial;\n");
|
||||
b.append("}");
|
||||
b.append(" </style>\n");
|
||||
b.append(" </head>\n");
|
||||
b.append("\n");
|
||||
b.append(" <body>");
|
||||
StringBuilder outputBuffer = new StringBuilder();
|
||||
outputBuffer.append("<html lang=\"en\">\n");
|
||||
outputBuffer.append(" <head>\n");
|
||||
outputBuffer.append(" <meta charset=\"utf-8\" />\n");
|
||||
outputBuffer.append(" <style>\n");
|
||||
outputBuffer.append(".httpStatusDiv {");
|
||||
outputBuffer.append(" font-size: 1.2em;");
|
||||
outputBuffer.append(" font-weight: bold;");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".hlQuot { color: #88F; }\n");
|
||||
outputBuffer.append(".hlQuot a { text-decoration: underline; text-decoration-color: #CCC; }\n");
|
||||
outputBuffer.append(".hlQuot a:HOVER { text-decoration: underline; text-decoration-color: #008; }\n");
|
||||
outputBuffer.append(".hlQuot .uuid, .hlQuot .dateTime {\n");
|
||||
outputBuffer.append(" user-select: all;\n");
|
||||
outputBuffer.append(" -moz-user-select: all;\n");
|
||||
outputBuffer.append(" -webkit-user-select: all;\n");
|
||||
outputBuffer.append(" -ms-user-select: element;\n");
|
||||
outputBuffer.append("}\n");
|
||||
outputBuffer.append(".hlAttr {\n");
|
||||
outputBuffer.append(" color: #888;\n");
|
||||
outputBuffer.append("}\n");
|
||||
outputBuffer.append(".hlTagName {\n");
|
||||
outputBuffer.append(" color: #006699;\n");
|
||||
outputBuffer.append("}\n");
|
||||
outputBuffer.append(".hlControl {\n");
|
||||
outputBuffer.append(" color: #660000;\n");
|
||||
outputBuffer.append("}\n");
|
||||
outputBuffer.append(".hlText {\n");
|
||||
outputBuffer.append(" color: #000000;\n");
|
||||
outputBuffer.append("}\n");
|
||||
outputBuffer.append(".hlUrlBase {\n");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".headersDiv {\n");
|
||||
outputBuffer.append(" padding: 10px;");
|
||||
outputBuffer.append(" margin-left: 10px;");
|
||||
outputBuffer.append(" border: 1px solid #CCC;");
|
||||
outputBuffer.append(" border-radius: 10px;");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".headersRow {\n");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".headerName {\n");
|
||||
outputBuffer.append(" color: #888;\n");
|
||||
outputBuffer.append(" font-family: monospace;\n");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".headerValue {\n");
|
||||
outputBuffer.append(" color: #88F;\n");
|
||||
outputBuffer.append(" font-family: monospace;\n");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".responseBodyTable {");
|
||||
outputBuffer.append(" width: 100%;\n");
|
||||
outputBuffer.append(" margin-left: 0px;\n");
|
||||
outputBuffer.append(" margin-top: -10px;\n");
|
||||
outputBuffer.append(" position: relative;\n");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".responseBodyTableFirstColumn {");
|
||||
// outputBuffer.append(" position: absolute;\n");
|
||||
// outputBuffer.append(" width: 70px;\n");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".responseBodyTableSecondColumn {");
|
||||
outputBuffer.append(" position: absolute;\n");
|
||||
outputBuffer.append(" margin-left: 70px;\n");
|
||||
outputBuffer.append(" vertical-align: top;\n");
|
||||
outputBuffer.append(" left: 0px;\n");
|
||||
outputBuffer.append(" right: 0px;\n");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".responseBodyTableSecondColumn PRE {");
|
||||
outputBuffer.append(" margin: 0px;");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".sizeInfo {");
|
||||
outputBuffer.append(" margin-top: 20px;");
|
||||
outputBuffer.append(" font-size: 0.8em;");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".lineAnchor A {");
|
||||
outputBuffer.append(" text-decoration: none;");
|
||||
outputBuffer.append(" padding-left: 20px;");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".lineAnchor {");
|
||||
outputBuffer.append(" display: block;");
|
||||
outputBuffer.append(" padding-right: 20px;");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".selectedLine {");
|
||||
outputBuffer.append(" background-color: #EEF;");
|
||||
outputBuffer.append(" font-weight: bold;");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append("H1 {");
|
||||
outputBuffer.append(" font-size: 1.1em;");
|
||||
outputBuffer.append(" color: #666;");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append("BODY {\n");
|
||||
outputBuffer.append(" font-family: Arial;\n");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(" </style>\n");
|
||||
outputBuffer.append(" </head>\n");
|
||||
outputBuffer.append("\n");
|
||||
outputBuffer.append(" <body>");
|
||||
|
||||
b.append("<p>");
|
||||
b.append("This result is being rendered in HTML for easy viewing. ");
|
||||
b.append("You may access this content as ");
|
||||
outputBuffer.append("<p>");
|
||||
outputBuffer.append("This result is being rendered in HTML for easy viewing. ");
|
||||
outputBuffer.append("You may access this content as ");
|
||||
|
||||
b.append("<a href=\"");
|
||||
b.append(createLinkHref(parameters, Constants.FORMAT_JSON));
|
||||
b.append("\">Raw JSON</a> or ");
|
||||
outputBuffer.append("<a href=\"");
|
||||
outputBuffer.append(createLinkHref(parameters, Constants.FORMAT_JSON));
|
||||
outputBuffer.append("\">Raw JSON</a> or ");
|
||||
|
||||
b.append("<a href=\"");
|
||||
b.append(createLinkHref(parameters, Constants.FORMAT_XML));
|
||||
b.append("\">Raw XML</a>, ");
|
||||
outputBuffer.append("<a href=\"");
|
||||
outputBuffer.append(createLinkHref(parameters, Constants.FORMAT_XML));
|
||||
outputBuffer.append("\">Raw XML</a>, ");
|
||||
|
||||
b.append(" or view this content in ");
|
||||
outputBuffer.append(" or view this content in ");
|
||||
|
||||
b.append("<a href=\"");
|
||||
b.append(createLinkHref(parameters, Constants.FORMATS_HTML_JSON));
|
||||
b.append("\">HTML JSON</a> ");
|
||||
outputBuffer.append("<a href=\"");
|
||||
outputBuffer.append(createLinkHref(parameters, Constants.FORMATS_HTML_JSON));
|
||||
outputBuffer.append("\">HTML JSON</a> ");
|
||||
|
||||
b.append("or ");
|
||||
b.append("<a href=\"");
|
||||
b.append(createLinkHref(parameters, Constants.FORMATS_HTML_XML));
|
||||
b.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);
|
||||
if (startTime != null) {
|
||||
long time = System.currentTimeMillis() - startTime.getTime();
|
||||
b.append(" Response generated in ");
|
||||
b.append(time);
|
||||
b.append("ms.");
|
||||
outputBuffer.append(" Response generated in ");
|
||||
outputBuffer.append(time);
|
||||
outputBuffer.append("ms.");
|
||||
}
|
||||
|
||||
b.append("</p>");
|
||||
outputBuffer.append("</p>");
|
||||
|
||||
b.append("\n");
|
||||
outputBuffer.append("\n");
|
||||
|
||||
// status (e.g. HTTP 200 OK)
|
||||
String statusName = Constants.HTTP_STATUS_NAMES.get(theServletResponse.getStatus());
|
||||
statusName = defaultString(statusName);
|
||||
b.append("<div class=\"httpStatusDiv\">");
|
||||
b.append("HTTP ");
|
||||
b.append(theServletResponse.getStatus());
|
||||
b.append(" ");
|
||||
b.append(statusName);
|
||||
b.append("</div>");
|
||||
outputBuffer.append("<div class=\"httpStatusDiv\">");
|
||||
outputBuffer.append("HTTP ");
|
||||
outputBuffer.append(theServletResponse.getStatus());
|
||||
outputBuffer.append(" ");
|
||||
outputBuffer.append(statusName);
|
||||
outputBuffer.append("</div>");
|
||||
|
||||
b.append("\n");
|
||||
b.append("\n");
|
||||
outputBuffer.append("\n");
|
||||
outputBuffer.append("\n");
|
||||
|
||||
try {
|
||||
if (isShowRequestHeaders()) {
|
||||
streamRequestHeaders(theServletRequest, b);
|
||||
streamRequestHeaders(theServletRequest, outputBuffer);
|
||||
}
|
||||
if (isShowResponseHeaders()) {
|
||||
streamResponseHeaders(theRequestDetails, theServletResponse, b);
|
||||
streamResponseHeaders(theRequestDetails, theServletResponse, outputBuffer);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// ignore (this will hit if we're running in a servlet 2.5 environment)
|
||||
}
|
||||
|
||||
b.append("<h1>Response Body</h1>");
|
||||
outputBuffer.append("<h1>Response Body</h1>");
|
||||
|
||||
b.append("<div class=\"responseBodyTable\">");
|
||||
outputBuffer.append("<div class=\"responseBodyTable\">");
|
||||
|
||||
// Response Body
|
||||
b.append("<div class=\"responseBodyTableSecondColumn\"><pre>");
|
||||
outputBuffer.append("<div class=\"responseBodyTableSecondColumn\"><pre>");
|
||||
StringBuilder target = new StringBuilder();
|
||||
int linesCount = format(encoded, target, encoding);
|
||||
b.append(target);
|
||||
b.append("</pre></div>");
|
||||
outputBuffer.append(target);
|
||||
outputBuffer.append("</pre></div>");
|
||||
|
||||
// Line Numbers
|
||||
b.append("<div class=\"responseBodyTableFirstColumn\"><pre>");
|
||||
outputBuffer.append("<div class=\"responseBodyTableFirstColumn\"><pre>");
|
||||
for (int i = 1; i <= linesCount; i++) {
|
||||
b.append("<div class=\"lineAnchor\" id=\"anchor");
|
||||
b.append(i);
|
||||
b.append("\">");
|
||||
outputBuffer.append("<div class=\"lineAnchor\" id=\"anchor");
|
||||
outputBuffer.append(i);
|
||||
outputBuffer.append("\">");
|
||||
|
||||
b.append("<a href=\"#L");
|
||||
b.append(i);
|
||||
b.append("\" name=\"L");
|
||||
b.append(i);
|
||||
b.append("\" id=\"L");
|
||||
b.append(i);
|
||||
b.append("\">");
|
||||
b.append(i);
|
||||
b.append("</a></div>");
|
||||
outputBuffer.append("<a href=\"#L");
|
||||
outputBuffer.append(i);
|
||||
outputBuffer.append("\" name=\"L");
|
||||
outputBuffer.append(i);
|
||||
outputBuffer.append("\" id=\"L");
|
||||
outputBuffer.append(i);
|
||||
outputBuffer.append("\">");
|
||||
outputBuffer.append(i);
|
||||
outputBuffer.append("</a></div>");
|
||||
}
|
||||
b.append("</div></td>");
|
||||
outputBuffer.append("</div></td>");
|
||||
|
||||
b.append("</div>");
|
||||
outputBuffer.append("</div>");
|
||||
|
||||
b.append("\n");
|
||||
outputBuffer.append("\n");
|
||||
|
||||
InputStream jsStream = ResponseHighlighterInterceptor.class.getResourceAsStream("ResponseHighlighter.js");
|
||||
String jsStr = jsStream != null ? IOUtils.toString(jsStream, "UTF-8") : "console.log('ResponseHighlighterInterceptor: javascript theResource not found')";
|
||||
jsStr = jsStr.replace("FHIR_BASE", theRequestDetails.getServerBaseForRequest());
|
||||
b.append("<script type=\"text/javascript\">");
|
||||
b.append(jsStr);
|
||||
b.append("</script>\n");
|
||||
outputBuffer.append("<script type=\"text/javascript\">");
|
||||
outputBuffer.append(jsStr);
|
||||
outputBuffer.append("</script>\n");
|
||||
|
||||
b.append("</body>");
|
||||
b.append("</html>");
|
||||
String out = b.toString();
|
||||
StopWatch writeSw = new StopWatch();
|
||||
theServletResponse.getWriter().append(outputBuffer);
|
||||
theServletResponse.getWriter().flush();
|
||||
|
||||
theServletResponse.getWriter().append("<div class=\"sizeInfo\">");
|
||||
theServletResponse.getWriter().append("Wrote ");
|
||||
writeLength(theServletResponse, encoded.length());
|
||||
theServletResponse.getWriter().append(" (");
|
||||
writeLength(theServletResponse, outputBuffer.length());
|
||||
theServletResponse.getWriter().append(" total including HTML)");
|
||||
|
||||
theServletResponse.getWriter().append(" in estimated ");
|
||||
theServletResponse.getWriter().append(writeSw.toString());
|
||||
theServletResponse.getWriter().append("</div>");
|
||||
|
||||
|
||||
theServletResponse.getWriter().append("</body>");
|
||||
theServletResponse.getWriter().append("</html>");
|
||||
|
||||
theServletResponse.getWriter().append(out);
|
||||
theServletResponse.getWriter().close();
|
||||
} catch (IOException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeLength(HttpServletResponse theServletResponse, int theLength) throws IOException {
|
||||
double kb = ((double)theLength) / FileUtils.ONE_KB;
|
||||
if (kb <= 1000) {
|
||||
theServletResponse.getWriter().append(String.format("%.1f", kb)).append(" KB");
|
||||
} else {
|
||||
double mb = kb / 1000;
|
||||
theServletResponse.getWriter().append(String.format("%.1f", mb)).append(" MB");
|
||||
}
|
||||
}
|
||||
|
||||
private void streamResponseHeaders(RequestDetails theRequestDetails, HttpServletResponse theServletResponse, StringBuilder b) {
|
||||
if (theServletResponse.getHeaderNames().isEmpty() == false) {
|
||||
b.append("<h1>Response Headers</h1>");
|
||||
|
|
|
@ -249,6 +249,10 @@
|
|||
queue (only the ID), which should reduce the memory/disk footprint of the queue
|
||||
when it grows long.
|
||||
</action>
|
||||
<action type="add">
|
||||
ResponseHighlighterInterceptor now displays the total size of the output and
|
||||
an estimate of the transfer time at the bottom of the response.
|
||||
</action>
|
||||
</release>
|
||||
<release version="3.4.0" date="2018-05-28">
|
||||
<action type="add">
|
||||
|
|
Loading…
Reference in New Issue