Add line selection and header display to ResponseHighlighterInterceptor

This commit is contained in:
James Agnew 2017-07-12 09:04:05 -04:00
parent 41a64a6999
commit 38b7212e52
7 changed files with 423 additions and 143 deletions

View File

@ -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);
}

View File

@ -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'>&quot;");
theTarget.append("<span class='hlQuot'>&quot;");
} else {
b.append("<span class='hlTagName'>&quot;");
theTarget.append("<span class='hlTagName'>&quot;");
}
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'>&gt;</span>");
theTarget.append("</span><span class='hlControl'>&gt;</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'>&quot;");
theTarget.append("<span class='hlQuot'>&quot;");
inQuote = true;
i += 5;
} else {
b.append(nextChar);
theTarget.append(nextChar);
}
} else {
if (nextChar == '&' && nextChar2 == 'l' && nextChar3 == 't' && nextChar4 == ';') {
b.append("<span class='hlControl'>&lt;</span><span class='hlTagName'>");
theTarget.append("<span class='hlControl'>&lt;</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>");
}
}
}

View File

@ -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");

View File

@ -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());
/*

View File

@ -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>

View File

@ -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() {

View File

@ -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">