Add line selection and header display to ResponseHighlighterInterceptor
This commit is contained in:
parent
41a64a6999
commit
38b7212e52
|
@ -43,7 +43,8 @@ public class BanUnsupportedHttpMethodsInterceptor extends InterceptorAdapter {
|
|||
myAllowedMethods.add(RequestTypeEnum.OPTIONS);
|
||||
myAllowedMethods.add(RequestTypeEnum.DELETE);
|
||||
myAllowedMethods.add(RequestTypeEnum.PUT);
|
||||
myAllowedMethods.add(RequestTypeEnum.POST);
|
||||
myAllowedMethods.add(RequestTypeEnum.POST);
|
||||
myAllowedMethods.add(RequestTypeEnum.PATCH);
|
||||
myAllowedMethods.add(RequestTypeEnum.HEAD);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package ca.uhn.fhir.rest.server.interceptor;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
|
@ -25,9 +26,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
|
@ -41,13 +40,9 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
|||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.RestfulServerUtils;
|
||||
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.rest.server.*;
|
||||
import ca.uhn.fhir.rest.server.RestfulServerUtils.ResponseEncoding;
|
||||
import ca.uhn.fhir.rest.server.exceptions.*;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
|
||||
/**
|
||||
|
@ -67,120 +62,165 @@ public class ResponseHighlighterInterceptor extends InterceptorAdapter {
|
|||
* requesting _format=json or xml so eventually this parameter should be removed
|
||||
*/
|
||||
public static final String PARAM_RAW = "_raw";
|
||||
|
||||
public static final String PARAM_RAW_TRUE = "true";
|
||||
|
||||
public static final String PARAM_TRUE = "true";
|
||||
|
||||
private String format(String theResultBody, EncodingEnum theEncodingEnum) {
|
||||
private boolean myShowRequestHeaders;
|
||||
private boolean myShowResponseHeaders;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public ResponseHighlighterInterceptor() {
|
||||
super();
|
||||
}
|
||||
|
||||
private String createLinkHref(Map<String, String[]> parameters, String formatValue) {
|
||||
StringBuilder rawB = new StringBuilder();
|
||||
for (String next : parameters.keySet()) {
|
||||
if (Constants.PARAM_FORMAT.equals(next)) {
|
||||
continue;
|
||||
}
|
||||
for (String nextValue : parameters.get(next)) {
|
||||
if (isBlank(nextValue)) {
|
||||
continue;
|
||||
}
|
||||
if (rawB.length() == 0) {
|
||||
rawB.append('?');
|
||||
} else {
|
||||
rawB.append('&');
|
||||
}
|
||||
rawB.append(UrlUtil.escape(next));
|
||||
rawB.append('=');
|
||||
rawB.append(UrlUtil.escape(nextValue));
|
||||
}
|
||||
}
|
||||
if (rawB.length() == 0) {
|
||||
rawB.append('?');
|
||||
} else {
|
||||
rawB.append('&');
|
||||
}
|
||||
rawB.append(Constants.PARAM_FORMAT).append('=').append(formatValue);
|
||||
|
||||
String link = rawB.toString();
|
||||
return link;
|
||||
}
|
||||
|
||||
private int format(String theResultBody, StringBuilder theTarget, EncodingEnum theEncodingEnum) {
|
||||
String str = StringEscapeUtils.escapeHtml4(theResultBody);
|
||||
if (str == null || theEncodingEnum == null) {
|
||||
return str;
|
||||
theTarget.append(str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
theTarget.append("<div id=\"line1\">");
|
||||
|
||||
if (theEncodingEnum == EncodingEnum.JSON) {
|
||||
boolean inValue = false;
|
||||
boolean inQuote = false;
|
||||
boolean inTag = false;
|
||||
int lineCount = 1;
|
||||
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
char prevChar = (i > 0) ? str.charAt(i - 1) : ' ';
|
||||
char nextChar = str.charAt(i);
|
||||
char nextChar2 = (i + 1) < str.length() ? str.charAt(i + 1) : ' ';
|
||||
char nextChar3 = (i + 2) < str.length() ? str.charAt(i + 2) : ' ';
|
||||
char nextChar4 = (i + 3) < str.length() ? str.charAt(i + 3) : ' ';
|
||||
char nextChar5 = (i + 4) < str.length() ? str.charAt(i + 4) : ' ';
|
||||
char nextChar6 = (i + 5) < str.length() ? str.charAt(i + 5) : ' ';
|
||||
|
||||
if (nextChar == '\n') {
|
||||
lineCount++;
|
||||
theTarget.append("</div><div id=\"line");
|
||||
theTarget.append(lineCount);
|
||||
theTarget.append("\" onclick=\"window.location.hash='L");
|
||||
theTarget.append(lineCount);
|
||||
theTarget.append("';\">");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (theEncodingEnum == EncodingEnum.JSON) {
|
||||
|
||||
boolean inValue = false;
|
||||
boolean inQuote = false;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
char prevChar = (i > 0) ? str.charAt(i - 1) : ' ';
|
||||
char nextChar = str.charAt(i);
|
||||
char nextChar2 = (i + 1) < str.length() ? str.charAt(i + 1) : ' ';
|
||||
char nextChar3 = (i + 2) < str.length() ? str.charAt(i + 2) : ' ';
|
||||
char nextChar4 = (i + 3) < str.length() ? str.charAt(i + 3) : ' ';
|
||||
char nextChar5 = (i + 4) < str.length() ? str.charAt(i + 4) : ' ';
|
||||
char nextChar6 = (i + 5) < str.length() ? str.charAt(i + 5) : ' ';
|
||||
if (inQuote) {
|
||||
b.append(nextChar);
|
||||
theTarget.append(nextChar);
|
||||
if (prevChar != '\\' && nextChar == '&' && nextChar2 == 'q' && nextChar3 == 'u' && nextChar4 == 'o' && nextChar5 == 't' && nextChar6 == ';') {
|
||||
b.append("quot;</span>");
|
||||
theTarget.append("quot;</span>");
|
||||
i += 5;
|
||||
inQuote = false;
|
||||
} else if (nextChar == '\\' && nextChar2 == '"') {
|
||||
b.append("quot;</span>");
|
||||
theTarget.append("quot;</span>");
|
||||
i += 5;
|
||||
inQuote = false;
|
||||
}
|
||||
} else {
|
||||
if (nextChar == ':') {
|
||||
inValue = true;
|
||||
b.append(nextChar);
|
||||
theTarget.append(nextChar);
|
||||
} else if (nextChar == '[' || nextChar == '{') {
|
||||
b.append("<span class='hlControl'>");
|
||||
b.append(nextChar);
|
||||
b.append("</span>");
|
||||
theTarget.append("<span class='hlControl'>");
|
||||
theTarget.append(nextChar);
|
||||
theTarget.append("</span>");
|
||||
inValue = false;
|
||||
} else if (nextChar == '{' || nextChar == '}' || nextChar == ',') {
|
||||
b.append("<span class='hlControl'>");
|
||||
b.append(nextChar);
|
||||
b.append("</span>");
|
||||
theTarget.append("<span class='hlControl'>");
|
||||
theTarget.append(nextChar);
|
||||
theTarget.append("</span>");
|
||||
inValue = false;
|
||||
} else if (nextChar == '&' && nextChar2 == 'q' && nextChar3 == 'u' && nextChar4 == 'o' && nextChar5 == 't' && nextChar6 == ';') {
|
||||
if (inValue) {
|
||||
b.append("<span class='hlQuot'>"");
|
||||
theTarget.append("<span class='hlQuot'>"");
|
||||
} else {
|
||||
b.append("<span class='hlTagName'>"");
|
||||
theTarget.append("<span class='hlTagName'>"");
|
||||
}
|
||||
inQuote = true;
|
||||
i += 5;
|
||||
} else if (nextChar == ':') {
|
||||
b.append("<span class='hlControl'>");
|
||||
b.append(nextChar);
|
||||
b.append("</span>");
|
||||
theTarget.append("<span class='hlControl'>");
|
||||
theTarget.append(nextChar);
|
||||
theTarget.append("</span>");
|
||||
inValue = true;
|
||||
} else {
|
||||
b.append(nextChar);
|
||||
theTarget.append(nextChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
boolean inQuote = false;
|
||||
boolean inTag = false;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
char nextChar = str.charAt(i);
|
||||
char nextChar2 = (i + 1) < str.length() ? str.charAt(i + 1) : ' ';
|
||||
char nextChar3 = (i + 2) < str.length() ? str.charAt(i + 2) : ' ';
|
||||
char nextChar4 = (i + 3) < str.length() ? str.charAt(i + 3) : ' ';
|
||||
char nextChar5 = (i + 4) < str.length() ? str.charAt(i + 4) : ' ';
|
||||
char nextChar6 = (i + 5) < str.length() ? str.charAt(i + 5) : ' ';
|
||||
} else {
|
||||
if (inQuote) {
|
||||
b.append(nextChar);
|
||||
theTarget.append(nextChar);
|
||||
if (nextChar == '&' && nextChar2 == 'q' && nextChar3 == 'u' && nextChar4 == 'o' && nextChar5 == 't' && nextChar6 == ';') {
|
||||
b.append("quot;</span>");
|
||||
theTarget.append("quot;</span>");
|
||||
i += 5;
|
||||
inQuote = false;
|
||||
}
|
||||
} else if (inTag) {
|
||||
if (nextChar == '&' && nextChar2 == 'g' && nextChar3 == 't' && nextChar4 == ';') {
|
||||
b.append("</span><span class='hlControl'>></span>");
|
||||
theTarget.append("</span><span class='hlControl'>></span>");
|
||||
inTag = false;
|
||||
i += 3;
|
||||
} else if (nextChar == ' ') {
|
||||
b.append("</span><span class='hlAttr'>");
|
||||
b.append(nextChar);
|
||||
theTarget.append("</span><span class='hlAttr'>");
|
||||
theTarget.append(nextChar);
|
||||
} else if (nextChar == '&' && nextChar2 == 'q' && nextChar3 == 'u' && nextChar4 == 'o' && nextChar5 == 't' && nextChar6 == ';') {
|
||||
b.append("<span class='hlQuot'>"");
|
||||
theTarget.append("<span class='hlQuot'>"");
|
||||
inQuote = true;
|
||||
i += 5;
|
||||
} else {
|
||||
b.append(nextChar);
|
||||
theTarget.append(nextChar);
|
||||
}
|
||||
} else {
|
||||
if (nextChar == '&' && nextChar2 == 'l' && nextChar3 == 't' && nextChar4 == ';') {
|
||||
b.append("<span class='hlControl'><</span><span class='hlTagName'>");
|
||||
theTarget.append("<span class='hlControl'><</span><span class='hlTagName'>");
|
||||
inTag = true;
|
||||
i += 3;
|
||||
} else {
|
||||
b.append(nextChar);
|
||||
theTarget.append(nextChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return b.toString();
|
||||
theTarget.append("</div>");
|
||||
return lineCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -218,6 +258,22 @@ public class ResponseHighlighterInterceptor extends InterceptorAdapter {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to <code>true</code> (default is <code>false</code>) response will include the
|
||||
* request headers
|
||||
*/
|
||||
public boolean isShowRequestHeaders() {
|
||||
return myShowRequestHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to <code>true</code> (default is <code>false</code>) response will include the
|
||||
* response headers
|
||||
*/
|
||||
public boolean isShowResponseHeaders() {
|
||||
return myShowResponseHeaders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean outgoingResponse(RequestDetails theRequestDetails, IBaseResource theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse)
|
||||
throws AuthenticationException {
|
||||
|
@ -288,7 +344,56 @@ public class ResponseHighlighterInterceptor extends InterceptorAdapter {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to <code>true</code> (default is <code>false</code>) response will include the
|
||||
* request headers
|
||||
*
|
||||
* @return Returns a reference to this for easy method chaining
|
||||
*/
|
||||
public ResponseHighlighterInterceptor setShowRequestHeaders(boolean theShowRequestHeaders) {
|
||||
myShowRequestHeaders = theShowRequestHeaders;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to <code>true</code> (default is <code>false</code>) response will include the
|
||||
* response headers
|
||||
*
|
||||
* @return Returns a reference to this for easy method chaining
|
||||
*/
|
||||
public ResponseHighlighterInterceptor setShowResponseHeaders(boolean theShowResponseHeaders) {
|
||||
myShowResponseHeaders = theShowResponseHeaders;
|
||||
return this;
|
||||
}
|
||||
|
||||
private void streamRequestHeaders(ServletRequest theServletRequest, StringBuilder b) {
|
||||
if (theServletRequest instanceof HttpServletRequest) {
|
||||
HttpServletRequest sr = (HttpServletRequest) theServletRequest;
|
||||
b.append("<h1>Request</h1>");
|
||||
b.append("<div class=\"headersDiv\">");
|
||||
Enumeration<String> headerNamesEnum = sr.getHeaderNames();
|
||||
while (headerNamesEnum.hasMoreElements()) {
|
||||
String nextHeaderName = headerNamesEnum.nextElement();
|
||||
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>");
|
||||
}
|
||||
}
|
||||
b.append("</div>");
|
||||
}
|
||||
}
|
||||
|
||||
private void streamResponse(RequestDetails theRequestDetails, HttpServletResponse theServletResponse, IBaseResource resource, ServletRequest theServletRequest, int theStatusCode) {
|
||||
|
||||
if (theRequestDetails.getServer() instanceof RestfulServer) {
|
||||
RestfulServer rs = (RestfulServer) theRequestDetails.getServer();
|
||||
rs.addHeadersToResponse(theServletResponse);
|
||||
}
|
||||
|
||||
IParser p;
|
||||
Map<String, String[]> parameters = theRequestDetails.getParameters();
|
||||
if (parameters.containsKey(Constants.PARAM_FORMAT)) {
|
||||
|
@ -327,6 +432,10 @@ public class ResponseHighlighterInterceptor extends InterceptorAdapter {
|
|||
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: none; color: #88F; }\n");
|
||||
b.append(".hlQuot .uuid, .hlQuot .dateTime {\n");
|
||||
|
@ -350,7 +459,12 @@ public class ResponseHighlighterInterceptor extends InterceptorAdapter {
|
|||
b.append(".hlUrlBase {\n");
|
||||
b.append("}");
|
||||
b.append(".headersDiv {\n");
|
||||
b.append(" background: #EEE;");
|
||||
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");
|
||||
|
@ -360,6 +474,32 @@ public class ResponseHighlighterInterceptor extends InterceptorAdapter {
|
|||
b.append(" color: #88F;\n");
|
||||
b.append(" font-family: monospace;\n");
|
||||
b.append("}");
|
||||
b.append(".responseBodyTable {");
|
||||
b.append(" width: 100%;");
|
||||
b.append(" margin-left: 0px;");
|
||||
b.append(" margin-top: 20px;");
|
||||
b.append("}");
|
||||
b.append(".responseBodyTableFirstColumn {");
|
||||
b.append("}");
|
||||
b.append(".responseBodyTableSecondColumn {");
|
||||
b.append(" width: 100%;");
|
||||
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("}");
|
||||
|
@ -403,21 +543,65 @@ public class ResponseHighlighterInterceptor extends InterceptorAdapter {
|
|||
|
||||
b.append("\n");
|
||||
|
||||
// if (isEncodeHeaders()) {
|
||||
// b.append("<h1>Request Headers</h1>");
|
||||
// b.append("<div class=\"headersDiv\">");
|
||||
// for (int next : theRequestDetails.get)
|
||||
// b.append("</div>");
|
||||
// b.append("<h1>Response Headers</h1>");
|
||||
// b.append("<div class=\"headersDiv\">");
|
||||
// b.append("</div>");
|
||||
// b.append("<h1>Response Body</h1>");
|
||||
// }
|
||||
b.append("<pre>");
|
||||
b.append(format(encoded, encoding));
|
||||
b.append("</pre>");
|
||||
// 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>");
|
||||
|
||||
b.append("\n");
|
||||
|
||||
b.append("\n");
|
||||
|
||||
if (true) {
|
||||
try {
|
||||
if (isShowRequestHeaders()) {
|
||||
streamRequestHeaders(theServletRequest, b);
|
||||
}
|
||||
if (isShowResponseHeaders()) {
|
||||
streamResponseHeaders(theRequestDetails, theServletResponse, b);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// ignore (this will hit if we're running in a servlet 2.5 environment)
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder target = new StringBuilder();
|
||||
int linesCount = format(encoded, target, encoding);
|
||||
|
||||
b.append("<table class=\"responseBodyTable\" cellspacing=\"0\">");
|
||||
b.append("<tr>");
|
||||
|
||||
b.append("<td class=\"responseBodyTableFirstColumn\"><pre>");
|
||||
for (int i = 1; i <= linesCount; i++) {
|
||||
b.append("<div class=\"lineAnchor\" id=\"anchor");
|
||||
b.append(i);
|
||||
b.append("\">");
|
||||
;
|
||||
|
||||
b.append("<a href=\"#L");
|
||||
b.append(i);
|
||||
b.append("\" name=\"L");
|
||||
b.append(i);
|
||||
b.append("\">");
|
||||
b.append(i);
|
||||
b.append("</a></div>");
|
||||
}
|
||||
b.append("</pre></td>");
|
||||
|
||||
// Response Body
|
||||
b.append("<td class=\"responseBodyTableSecondColumn\"><pre>");
|
||||
b.append(target);
|
||||
b.append("</pre></td>");
|
||||
|
||||
b.append("</tr>");
|
||||
b.append("</table>");
|
||||
|
||||
b.append("\n");
|
||||
|
||||
InputStream jsStream = ResponseHighlighterInterceptor.class.getResourceAsStream("ResponseHighlighter.js");
|
||||
String jsStr = jsStream != null ? IOUtils.toString(jsStream, "UTF-8") : "console.log('ResponseHighlighterInterceptor: javascript resource not found')";
|
||||
jsStr = jsStr.replace("FHIR_BASE", theRequestDetails.getServerBaseForRequest());
|
||||
|
@ -438,35 +622,31 @@ public class ResponseHighlighterInterceptor extends InterceptorAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
private String createLinkHref(Map<String, String[]> parameters, String formatValue) {
|
||||
StringBuilder rawB = new StringBuilder();
|
||||
for (String next : parameters.keySet()) {
|
||||
if (Constants.PARAM_FORMAT.equals(next)) {
|
||||
continue;
|
||||
}
|
||||
for (String nextValue : parameters.get(next)) {
|
||||
if (isBlank(nextValue)) {
|
||||
continue;
|
||||
}
|
||||
if (rawB.length() == 0) {
|
||||
rawB.append('?');
|
||||
} else {
|
||||
rawB.append('&');
|
||||
}
|
||||
rawB.append(UrlUtil.escape(next));
|
||||
rawB.append('=');
|
||||
rawB.append(UrlUtil.escape(nextValue));
|
||||
}
|
||||
}
|
||||
if (rawB.length() == 0) {
|
||||
rawB.append('?');
|
||||
} else {
|
||||
rawB.append('&');
|
||||
}
|
||||
rawB.append(Constants.PARAM_FORMAT).append('=').append(formatValue);
|
||||
private void streamResponseHeaders(RequestDetails theRequestDetails, HttpServletResponse theServletResponse, StringBuilder b) {
|
||||
if (theServletResponse.getHeaderNames().isEmpty() == false) {
|
||||
b.append("<h1>Response</h1>");
|
||||
|
||||
String link = rawB.toString();
|
||||
return link;
|
||||
b.append("<div class=\"headersDiv\">");
|
||||
for (String nextHeaderName : theServletResponse.getHeaderNames()) {
|
||||
for (String nextHeaderValue : theServletResponse.getHeaders(nextHeaderName)) {
|
||||
/*
|
||||
* Let's pretend we're returning a FHIR content type even though we're
|
||||
* actually returning an HTML one
|
||||
*/
|
||||
if (nextHeaderName.equalsIgnoreCase(Constants.HEADER_CONTENT_TYPE)) {
|
||||
ResponseEncoding responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequestDetails, theRequestDetails.getServer().getDefaultResponseEncoding());
|
||||
if (responseEncoding != null && isNotBlank(responseEncoding.getResourceContentType())) {
|
||||
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>");
|
||||
}
|
||||
}
|
||||
b.append("</div>");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,42 @@
|
|||
|
||||
var selectedLines = new Array();
|
||||
function updateHighlightedLine() {
|
||||
|
||||
for (var next in selectedLines) {
|
||||
document.getElementById('line' + selectedLines[next]).className = '';
|
||||
document.getElementById('anchor' + selectedLines[next]).className = 'lineAnchor';
|
||||
}
|
||||
selectedLines = new Array();
|
||||
|
||||
var line = -1;
|
||||
if (window.location.hash && window.location.hash.match('L[0-9]+-L[0-9]+')) {
|
||||
var dashIndex = window.location.hash.indexOf('-');
|
||||
var start = parseInt(window.location.hash.substring(2, dashIndex));
|
||||
var end = parseInt(window.location.hash.substring(dashIndex+2));
|
||||
for (var i = start; i <= end; i++) {
|
||||
selectedLines.push(i);
|
||||
}
|
||||
} else if (window.location.hash && window.location.hash.match('L[0-9]+')) {
|
||||
var line = parseInt(window.location.hash.substring(2));
|
||||
selectedLines.push(line);
|
||||
}
|
||||
|
||||
|
||||
for (var next in selectedLines) {
|
||||
document.getElementById('line' + selectedLines[next]).className = 'selectedLine';
|
||||
document.getElementById('anchor' + selectedLines[next]).className = 'lineAnchor selectedLine';
|
||||
}
|
||||
|
||||
selectedLine = line;
|
||||
}
|
||||
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
|
||||
updateHighlightedLine();
|
||||
window.onhashchange = updateHighlightedLine;
|
||||
|
||||
/* bail out if user is testing a version of this script via Greasemonkey or Tampermonkey */
|
||||
if (window.HAPI_ResponseHighlighter_userscript) {
|
||||
console.log("HAPI ResponseHighlighter: userscript detected - not executing embedded script");
|
||||
|
|
|
@ -197,7 +197,11 @@ public class TestRestfulServer extends RestfulServer {
|
|||
* We want to format the response using nice HTML if it's a browser, since this
|
||||
* makes things a little easier for testers.
|
||||
*/
|
||||
registerInterceptor(new ResponseHighlighterInterceptor());
|
||||
ResponseHighlighterInterceptor responseHighlighterInterceptor = new ResponseHighlighterInterceptor();
|
||||
responseHighlighterInterceptor.setShowRequestHeaders(true);
|
||||
responseHighlighterInterceptor.setShowResponseHeaders(true);
|
||||
registerInterceptor(responseHighlighterInterceptor);
|
||||
|
||||
registerInterceptor(new BanUnsupportedHttpMethodsInterceptor());
|
||||
|
||||
/*
|
||||
|
|
|
@ -27,14 +27,6 @@
|
|||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- The JPA project uses a newer API but we'll try to hold to this version as much as possible. See #283. -->
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Testing -->
|
||||
<!-- <dependency> <groupId>ca.uhn.hapi.fhir</groupId> <artifactId>hapi-fhir-structures-dstu</artifactId> <version>0.8</version> <scope>test</scope> </dependency> -->
|
||||
<dependency>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package ca.uhn.fhir.rest.server.interceptor;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.containsStringIgnoringCase;
|
||||
import static org.hamcrest.Matchers.matchesPattern;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||
|
@ -32,8 +33,7 @@ import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
|||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.*;
|
||||
import org.junit.Test;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
@ -45,28 +45,21 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
|
||||
import ca.uhn.fhir.model.dstu2.composite.IdentifierDt;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Binary;
|
||||
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
|
||||
import ca.uhn.fhir.model.dstu2.resource.*;
|
||||
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome.Issue;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Organization;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.model.dstu2.valueset.IdentifierUseEnum;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.UriDt;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.Read;
|
||||
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.server.*;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import ca.uhn.fhir.util.*;
|
||||
|
||||
public class ResponseHighlightingInterceptorTest {
|
||||
|
||||
private static ResponseHighlighterInterceptor ourInterceptor = new ResponseHighlighterInterceptor();
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forDstu2();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResponseHighlightingInterceptorTest.class);
|
||||
|
@ -80,6 +73,12 @@ public class ResponseHighlightingInterceptorTest {
|
|||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourInterceptor.setShowRequestHeaders(new ResponseHighlighterInterceptor().isShowRequestHeaders());
|
||||
ourInterceptor.setShowResponseHeaders(new ResponseHighlighterInterceptor().isShowResponseHeaders());
|
||||
}
|
||||
|
||||
/**
|
||||
* See #464
|
||||
*/
|
||||
|
@ -148,6 +147,69 @@ public class ResponseHighlightingInterceptorTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShowNeither() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_format=html/json");
|
||||
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals("text/html;charset=utf-8", status.getFirstHeader("content-type").getValue().replace(" ", "").toLowerCase());
|
||||
assertThat(responseContent, not(containsStringIgnoringCase("Accept")));
|
||||
assertThat(responseContent, not(containsStringIgnoringCase("Content-Type")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShowResponse() throws Exception {
|
||||
ourInterceptor.setShowResponseHeaders(true);
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_format=html/json");
|
||||
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals("text/html;charset=utf-8", status.getFirstHeader("content-type").getValue().replace(" ", "").toLowerCase());
|
||||
assertThat(responseContent, not(containsStringIgnoringCase("Accept")));
|
||||
assertThat(responseContent, (containsStringIgnoringCase("Content-Type")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShowRequest() throws Exception {
|
||||
ourInterceptor.setShowRequestHeaders(true);
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_format=html/json");
|
||||
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals("text/html;charset=utf-8", status.getFirstHeader("content-type").getValue().replace(" ", "").toLowerCase());
|
||||
assertThat(responseContent, (containsStringIgnoringCase("Accept")));
|
||||
assertThat(responseContent, not(containsStringIgnoringCase("Content-Type")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShowRequestAndResponse() throws Exception {
|
||||
ourInterceptor.setShowRequestHeaders(true);
|
||||
ourInterceptor.setShowResponseHeaders(true);
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_format=html/json");
|
||||
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals("text/html;charset=utf-8", status.getFirstHeader("content-type").getValue().replace(" ", "").toLowerCase());
|
||||
assertThat(responseContent, (containsStringIgnoringCase("Accept")));
|
||||
assertThat(responseContent, (containsStringIgnoringCase("Content-Type")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetInvalidResource() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Foobar/123");
|
||||
|
@ -196,7 +258,7 @@ public class ResponseHighlightingInterceptorTest {
|
|||
|
||||
@Test
|
||||
public void testHighlightException() throws Exception {
|
||||
ResponseHighlighterInterceptor ic = new ResponseHighlighterInterceptor();
|
||||
ResponseHighlighterInterceptor ic = ourInterceptor;
|
||||
|
||||
HttpServletRequest req = mock(HttpServletRequest.class);
|
||||
when(req.getHeaders(Constants.HEADER_ACCEPT)).thenAnswer(new Answer<Enumeration<String>>() {
|
||||
|
@ -234,7 +296,7 @@ public class ResponseHighlightingInterceptorTest {
|
|||
|
||||
@Test
|
||||
public void testHighlightNormalResponseForcePrettyPrint() throws Exception {
|
||||
ResponseHighlighterInterceptor ic = new ResponseHighlighterInterceptor();
|
||||
ResponseHighlighterInterceptor ic = ourInterceptor;
|
||||
|
||||
HttpServletRequest req = mock(HttpServletRequest.class);
|
||||
when(req.getHeaders(Constants.HEADER_ACCEPT)).thenAnswer(new Answer<Enumeration<String>>() {
|
||||
|
@ -269,7 +331,7 @@ public class ResponseHighlightingInterceptorTest {
|
|||
|
||||
@Test
|
||||
public void testHighlightForceRaw() throws Exception {
|
||||
ResponseHighlighterInterceptor ic = new ResponseHighlighterInterceptor();
|
||||
ResponseHighlighterInterceptor ic = ourInterceptor;
|
||||
|
||||
HttpServletRequest req = mock(HttpServletRequest.class);
|
||||
when(req.getHeaders(Constants.HEADER_ACCEPT)).thenAnswer(new Answer<Enumeration<String>>() {
|
||||
|
@ -303,7 +365,7 @@ public class ResponseHighlightingInterceptorTest {
|
|||
|
||||
@Test
|
||||
public void testDontHighlightWhenOriginHeaderPresent() throws Exception {
|
||||
ResponseHighlighterInterceptor ic = new ResponseHighlighterInterceptor();
|
||||
ResponseHighlighterInterceptor ic = ourInterceptor;
|
||||
|
||||
HttpServletRequest req = mock(HttpServletRequest.class);
|
||||
when(req.getHeaders(Constants.HEADER_ACCEPT)).thenAnswer(new Answer<Enumeration<String>>() {
|
||||
|
@ -343,7 +405,7 @@ public class ResponseHighlightingInterceptorTest {
|
|||
*/
|
||||
@Test
|
||||
public void testHighlightForceHtmlCt() throws Exception {
|
||||
ResponseHighlighterInterceptor ic = new ResponseHighlighterInterceptor();
|
||||
ResponseHighlighterInterceptor ic = ourInterceptor;
|
||||
|
||||
HttpServletRequest req = mock(HttpServletRequest.class);
|
||||
when(req.getHeaders(Constants.HEADER_ACCEPT)).thenAnswer(new Answer<Enumeration<String>>() {
|
||||
|
@ -377,7 +439,7 @@ public class ResponseHighlightingInterceptorTest {
|
|||
*/
|
||||
@Test
|
||||
public void testHighlightForceHtmlFormat() throws Exception {
|
||||
ResponseHighlighterInterceptor ic = new ResponseHighlighterInterceptor();
|
||||
ResponseHighlighterInterceptor ic = ourInterceptor;
|
||||
|
||||
HttpServletRequest req = mock(HttpServletRequest.class);
|
||||
when(req.getHeaders(Constants.HEADER_ACCEPT)).thenAnswer(new Answer<Enumeration<String>>() {
|
||||
|
@ -408,7 +470,7 @@ public class ResponseHighlightingInterceptorTest {
|
|||
|
||||
@Test
|
||||
public void testHighlightNormalResponse() throws Exception {
|
||||
ResponseHighlighterInterceptor ic = new ResponseHighlighterInterceptor();
|
||||
ResponseHighlighterInterceptor ic = ourInterceptor;
|
||||
|
||||
HttpServletRequest req = mock(HttpServletRequest.class);
|
||||
when(req.getHeaders(Constants.HEADER_ACCEPT)).thenAnswer(new Answer<Enumeration<String>>() {
|
||||
|
@ -445,7 +507,7 @@ public class ResponseHighlightingInterceptorTest {
|
|||
*/
|
||||
@Test
|
||||
public void testHighlightProducesDefaultJsonWithBrowserRequest() throws Exception {
|
||||
ResponseHighlighterInterceptor ic = new ResponseHighlighterInterceptor();
|
||||
ResponseHighlighterInterceptor ic = ourInterceptor;
|
||||
|
||||
HttpServletRequest req = mock(HttpServletRequest.class);
|
||||
|
||||
|
@ -483,7 +545,7 @@ public class ResponseHighlightingInterceptorTest {
|
|||
|
||||
@Test
|
||||
public void testHighlightProducesDefaultJsonWithBrowserRequest2() throws Exception {
|
||||
ResponseHighlighterInterceptor ic = new ResponseHighlighterInterceptor();
|
||||
ResponseHighlighterInterceptor ic = ourInterceptor;
|
||||
|
||||
HttpServletRequest req = mock(HttpServletRequest.class);
|
||||
|
||||
|
@ -718,7 +780,7 @@ public class ResponseHighlightingInterceptorTest {
|
|||
config.setAllowedMethods(Arrays.asList("GET","POST","PUT","DELETE","OPTIONS"));
|
||||
ourServlet.registerInterceptor(corsInterceptor);
|
||||
|
||||
ourServlet.registerInterceptor(new ResponseHighlighterInterceptor());
|
||||
ourServlet.registerInterceptor(ourInterceptor);
|
||||
ourServlet.setResourceProviders(patientProvider, new DummyBinaryResourceProvider());
|
||||
ourServlet.setBundleInclusionRule(BundleInclusionRule.BASED_ON_RESOURCE_PRESENCE);
|
||||
ServletHolder servletHolder = new ServletHolder(ourServlet);
|
||||
|
@ -762,9 +824,6 @@ public class ResponseHighlightingInterceptorTest {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
*/
|
||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||
|
||||
private Patient createPatient1() {
|
||||
|
|
|
@ -136,6 +136,15 @@
|
|||
body are now converted to actual clickable hyperlinks. Thanks to Eugene Lubarsky
|
||||
for the pull request!
|
||||
</action>
|
||||
<action type="add">
|
||||
BanUnsupportedHttpMethodsInterceptor has been modified so that it now allows
|
||||
HTTP PATCH to proceed.
|
||||
</action>
|
||||
<action type="add" issue="651">
|
||||
Enhancement to ResponseHighlighterInterceptor so that it now can be configured
|
||||
to display the request headers and response headers, and individual lines
|
||||
may be highlighted.
|
||||
</action>
|
||||
</release>
|
||||
<release version="2.5" date="2017-06-08">
|
||||
<action type="fix">
|
||||
|
|
Loading…
Reference in New Issue