Skip to content

Commit

Permalink
extends the response template model to include remote address and cli…
Browse files Browse the repository at this point in the history
…ent certificate chain
  • Loading branch information
jamesdbloom committed Mar 16, 2022
1 parent b55ba94 commit a8836ee
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 23 deletions.
2 changes: 1 addition & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- added response template variables and functions for date, uuid, random, xPath and jsonPath for mustache
- added response template variables for date, uuid and random for velocity
- added response template variables for date, uuid and random for javascript
- added path parameters to response template model
- added path parameters, remote address and client certificate chain to response template model
- added support for EMCAScript 6 in JavaScript response templates for Java versions between 9 and 15

### Changed
Expand Down
108 changes: 96 additions & 12 deletions jekyll-www.mock-server.com/mock_server/response_templates.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ <h2>Response Template Testing</h2>

<p><a href="#mustache_templates">mustache templates</a> can be tested locally as follows:</p>

<pre class="prettyprint lang-javascript code"><code class="code">// inputs
<pre class="prettyprint code"><code class="code">// inputs
String template = "{\n" +
" 'statusCode': 200,\n" +
" 'body': \"{'method': '&lbrace;&lbrace; request.method &rbrace;&rbrace;', 'path': '&lbrace;&lbrace; request.path &rbrace;&rbrace;', 'headers': '&lbrace;&lbrace; request.headers.host.0 &rbrace;&rbrace;'}\"\n" +
Expand All @@ -69,7 +69,7 @@ <h2>Response Template Testing</h2>

<p><a href="#velocity_templates">velocity templates</a> can be tested locally as follows:</p>

<pre class="prettyprint lang-javascript code"><code class="code">// inputs
<pre class="prettyprint code"><code class="code">// inputs
String template = "{\n" +
" 'statusCode': 200,\n" +
" 'body': \"{'method': '$request.method', 'path': '$request.path', 'headers': '$request.headers.host[0]'}\"\n" +
Expand All @@ -88,7 +88,7 @@ <h2>Response Template Testing</h2>

<p><a href="#javascript_templates">javascript templates</a> can be tested locally as follows:</p>

<pre class="prettyprint lang-javascript code"><code class="code">// inputs
<pre class="prettyprint code"><code class="code">// inputs
String template = "return {\n" +
" 'statusCode': 200,\n" +
" 'body': '{\\'method\\': \\'' + request.method + '\\', \\'path\\': \\'' + request.path + '\\', \\'headers\\': \\'' + request.headers.host[0] + '\\'}'\n" +
Expand Down Expand Up @@ -272,6 +272,76 @@ <h2>Request Model Variables</h2>
</tr>
</table>
</li>
<li><strong>client certificate chain</strong>
<p>During TLS connections MockServer requests clients to optionally present certificates i.e. optional mTLS.<br/>If the client presents certificates this field is populated with a list of the clients certificates.<br/>Each item in the list contains the following fields:</p>
<ul>
<li><strong>issuerDistinguishedName</strong> as a <code class="inline_code">string</code></li>
<li><strong>subjectDistinguishedName</strong> as a <code class="inline_code">string</code></li>
<li><strong>serialNumber</strong> as a <code class="inline_code">string</code></li>
<li><strong>signatureAlgorithmName</strong> as a <code class="inline_code">string</code></li>
<li><strong>certificate</strong> as a <code class="inline_code">java.security.cert.X509Certificate</code></li>
</ul>
<table>
<tr>
<td style="padding-left: 20px; width: 100px">mustache:</td>
<td><code class="inline code">&lbrace;&lbrace; request.clientCertificateChain &rbrace;&rbrace;</code></td>
</tr>
</table>
<table>
<tr>
<td style="padding-left: 20px; width: 100px;">velocity:</td>
<td><code class="inline code">$!request.clientCertificateChain</code></td>
</tr>
</table>
<table>
<tr>
<td style="padding-left: 20px; width: 100px;">javascript:</td>
<td><code class="inline code">request.clientCertificateChain</code></td>
</tr>
</table>
</li>
<li><strong>remote address</strong>
<p>The address of the TCP connection to MockServer; typically the client's address, unless there is a NAT device or load balancer between the client and MockServer.</p>
<table>
<tr>
<td style="padding-left: 20px; width: 100px">mustache:</td>
<td><code class="inline code">&lbrace;&lbrace; request.remoteAddress &rbrace;&rbrace;</code></td>
</tr>
</table>
<table>
<tr>
<td style="padding-left: 20px; width: 100px;">velocity:</td>
<td><code class="inline code">$!request.remoteAddress</code></td>
</tr>
</table>
<table>
<tr>
<td style="padding-left: 20px; width: 100px;">javascript:</td>
<td><code class="inline code">request.remoteAddress</code></td>
</tr>
</table>
</li>
<li><strong>keep alive</strong>
<p>True is the client requested HTTP keep alive.</p>
<table>
<tr>
<td style="padding-left: 20px; width: 100px">mustache:</td>
<td><code class="inline code">&lbrace;&lbrace; request.keepAlive &rbrace;&rbrace;</code></td>
</tr>
</table>
<table>
<tr>
<td style="padding-left: 20px; width: 100px;">velocity:</td>
<td><code class="inline code">$!request.keepAlive</code></td>
</tr>
</table>
<table>
<tr>
<td style="padding-left: 20px; width: 100px;">javascript:</td>
<td><code class="inline code">request.keepAlive</code></td>
</tr>
</table>
</li>
</ul>

<a id="request_multi_value_maps" class="anchor" href="#request_multi_value_maps">&nbsp;</a>
Expand Down Expand Up @@ -334,7 +404,7 @@ <h2>Request Multi-Value And Single Value Maps</h2>
<div style="padding: 20px 0"><table>
<tr>
<td style="padding-left: 20px; width: 100px;">javascript:</td>
<td>not available</td>
<td><strong>not available</strong></td>
</tr>
</table></div>
</li>
Expand Down Expand Up @@ -607,7 +677,7 @@ <h2>Mustache Response Templates</h2>

<p>The following shows a basic example for a mustache format response template</p>

<pre class="prettyprint lang-javascript code"><code class="code">new ClientAndServer(1080)
<pre class="prettyprint code"><code class="code">new ClientAndServer(1080)
.when(request().withPath("/some/path"))
.respond(
template(
Expand Down Expand Up @@ -796,7 +866,7 @@ <h4>JsonPath</h4>
<h4>XPath</h4>

<p>It is possible to use XPath expressions to extract values from request bodies containing XML with a <code class="inline code">&lbrace;&lbrace;#xPath&rbrace;&rbrace;</code> section.</p>
<p>The result of all XPath expressions are converted to a string due to the inherent limitations with XML.</p>
<p>The <code class="inline code">&lbrace;&lbrace;#xPath&rbrace;&rbrace;</code> section only supports outputting the result of the XPath expression as a string, if an XML fragment is matched the string content of all the elements is printed.</p>

<p>For a quick summary the XPath syntax please see <a target="_blank" href="https://www.w3schools.com/xml/xpath_syntax.asp">w3schools</a>, for details of the full XPath syntax please see <a target="_blank" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#path-abbrev">www.w3.org</a></p>

Expand Down Expand Up @@ -844,7 +914,7 @@ <h2>Velocity Response Templates</h2>

<p>The following shows a basic example for a Velocity format response template</p>

<pre class="prettyprint lang-javascript code"><code class="code">new ClientAndServer(1080)
<pre class="prettyprint code"><code class="code">new ClientAndServer(1080)
.when(request().withPath("/some/path"))
.respond(
template(
Expand Down Expand Up @@ -937,9 +1007,9 @@ <h4>Mathematical</h4>

<h2>JavaScript Response Templates</h2>

<p>The following shows a basic example for a JavaScript format response template</p>
<p>The following shows a basic example for a Javaacript format response template</p>

<pre class="prettyprint lang-javascript code"><code class="code">new ClientAndServer(1080)
<pre class="prettyprint code"><code class="code">new ClientAndServer(1080)
.when(request().withPath("/some/path"))
.respond(
template(
Expand All @@ -959,9 +1029,23 @@ <h2>JavaScript Response Templates</h2>

<h3>JavaScript Syntax</h3>

<p>All JavaScript response templates should return the response as an object as shown in the example above.</p>
<p>All javascript response templates should return the response as an object as shown in the example above.</p>

<p>Javascript response templates support ES6 syntax for Java 9 to 14, for a summary of ES6 syntax see <a target="_blank" href="https://www.w3schools.com/js/js_es6.asp">w3schools</a>.</p>

<p>Javascript response templates support ES5 syntax for Java 8, for a summary of ES5 syntax see <a target="_blank" href="https://www.w3schools.com/js/js_es5.asp">w3schools</a>.</p>

<h4>Java Version Support</h4>

<p>Javascript templates rely on Nashorn which has the following limitations for Java versions:</p>
<ul>
<li>Java 8 - ES5 only</li>
<li>Java 9 or 10 - ES5 & ES6</li>
<li>Java 11 to 14 - ES5 & ES6 but prints deprecated warning</li>
<li>Java 15+ - not supported</li>
</ul>

<p>JavaScript response templates support ECMAScript 6 (ES6) syntax, for a summary of ES6 see <a target="_blank" href="https://www.w3schools.com/js/js_es6.asp">w3schools</a>.</p>
<p>From Java 15 Nashorn is no longer part of the JDK but it is available as a separate library that requires Java 11+. Once MockServer minimum Java version is 11 then this separate library will be used.</p>

<h4>Variables</h4>

Expand All @@ -971,7 +1055,7 @@ <h4>Variables</h4>

<pre class="prettyprint lang-java code"><code class="code">return {
'statusCode': 200,
'body': '{\'method\': \'' + request.method + '\', \'path\': \'' + request.path + '\', \'headers\': \'' + request.headers.host[0] + '\'}'
'body': '{\'method\': \'' + request.method + '\', \'path\': \'' + request.path + '\', \'header\': \'' + request.headers.host[0] + '\'}'
};</code></pre>

<h4>Conditionals</h4>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public <T> T executeTemplate(String template, HttpRequest request, Class<? exten
try {
if (engine != null) {
Compilable compilable = (Compilable) engine;
// HttpResponse handle(HttpRequest httpRequest) - ES5
// HttpResponse handle(HttpRequest httpRequest) - ES6
CompiledScript compiledScript = compilable.compile(script + " function serialise(request) { return JSON.stringify(handle(JSON.parse(request)), null, 2); }");

Bindings serialiseBindings = engine.createBindings();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ public class HttpRequestTemplateObject extends RequestDefinition {
private final Map<String, String> cookies = new HashMap<>();
private final Map<String, List<String>> headers = new HashMap<>();
private BodyDTO body = null;
private Boolean keepAlive = null;
private Boolean secure = null;
private List<X509Certificate> clientCertificateChain = null;
private String remoteAddress = null;
private Boolean keepAlive = null;

public HttpRequestTemplateObject(HttpRequest httpRequest) {
if (httpRequest != null) {
Expand All @@ -41,8 +43,10 @@ public HttpRequestTemplateObject(HttpRequest httpRequest) {
cookies.put(cookie.getName().getValue(), cookie.getValue().getValue());
}
body = BodyDTO.createDTO(httpRequest.getBody());
keepAlive = httpRequest.isKeepAlive();
secure = httpRequest.isSecure();
clientCertificateChain = httpRequest.getClientCertificateChain();
remoteAddress = httpRequest.getRemoteAddress();
keepAlive = httpRequest.isKeepAlive();
setNot(httpRequest.getNot());
}
}
Expand Down Expand Up @@ -80,14 +84,22 @@ public String getBodyAsString() {
return BodyDTO.toString(body);
}

public Boolean getKeepAlive() {
return keepAlive;
}

public Boolean getSecure() {
return secure;
}

public List<X509Certificate> getClientCertificateChain() {
return clientCertificateChain;
}

public String getRemoteAddress() {
return remoteAddress;
}

public Boolean getKeepAlive() {
return keepAlive;
}

public HttpRequestTemplateObject shallowClone() {
return this;
}
Expand All @@ -114,14 +126,15 @@ public boolean equals(Object o) {
Objects.equals(cookies, that.cookies) &&
Objects.equals(headers, that.headers) &&
Objects.equals(body, that.body) &&
Objects.equals(keepAlive, that.keepAlive) &&
Objects.equals(secure, that.secure);
Objects.equals(secure, that.secure) &&
Objects.equals(remoteAddress, that.remoteAddress) &&
Objects.equals(keepAlive, that.keepAlive);
}

@Override
public int hashCode() {
if (hashCode == 0) {
hashCode = Objects.hash(super.hashCode(), method, path, pathParameters, queryStringParameters, cookies, headers, body, keepAlive, secure);
hashCode = Objects.hash(super.hashCode(), method, path, pathParameters, queryStringParameters, cookies, headers, body, secure, remoteAddress, keepAlive);
}
return hashCode;
}
Expand Down

0 comments on commit a8836ee

Please sign in to comment.