explicit http url decoding support

This commit is contained in:
Jonathan Shook
2020-12-22 23:33:48 -06:00
parent f0223501f8
commit 9d5c225ca8
2 changed files with 83 additions and 65 deletions

View File

@@ -8,12 +8,13 @@ import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class HttpFormatParser {
public static Map<String, String> parseUrl(String uri) {
if (uri.matches("http.+")) {
return Map.of("uri", rewriteUriWithStaticsEncoded(uri));
return Map.of("uri", rewriteExplicitSections(uri));
}
return null;
}
@@ -54,14 +55,14 @@ public class HttpFormatParser {
throw new BasicError("Request template must have at least a method and a uri: " + methodAndHeaders[0]);
}
props.put("method", methodLine[0]);
props.put("uri", rewriteUriWithStaticsEncoded(methodLine[1]));
props.put("uri", rewriteExplicitSections(methodLine[1]));
if (methodLine.length == 3) {
String actualVersion = methodLine[2];
String symbolicVersion = actualVersion
.replaceAll("/1.1", "_1_1")
.replaceAll("/2.0", "_2")
.replaceAll("/2", "_2");
.replaceAll("/2", "_2");
props.put("version", symbolicVersion);
}
@@ -69,27 +70,37 @@ public class HttpFormatParser {
return props;
}
private static String rewriteUriWithStaticsEncoded(String template) {
String[] parts = template.split("\\?", 2);
private final static Pattern DOENCODE = Pattern.compile("(URLENCODE|E)\\[\\[(?<data>.+?)\\]\\]");
if (parts.length == 2) {
StringBuilder sb = new StringBuilder();
String input = parts[1];
Matcher matcher = ParsedTemplate.STANDARD_ANCHOR.matcher(input);
int idx = 0;
while (matcher.find()) {
String pre = input.substring(0, matcher.start());
sb.append(URLEncoder.encode(pre, StandardCharsets.UTF_8));
sb.append(matcher.group());
idx = matcher.end();
// matcher.appendReplacement(sb, "test-value" + idx);
}
sb.append(URLEncoder.encode(input.substring(idx), StandardCharsets.UTF_8));
return parts[0] + "?" + sb.toString();
} else {
return template;
private static String rewriteExplicitSections(String template) {
StringBuilder sb = new StringBuilder();
Matcher matcher = DOENCODE.matcher(template);
while (matcher.find()) {
String rewrite = matcher.group("data");
String encoded = rewriteStaticsOnly(rewrite);
matcher.appendReplacement(sb, encoded);
}
matcher.appendTail(sb);
return sb.toString();
}
private static String rewriteStaticsOnly(String template) {
StringBuilder sb = new StringBuilder();
String input = template;
Matcher matcher = ParsedTemplate.STANDARD_ANCHOR.matcher(input);
int idx = 0;
while (matcher.find()) {
String pre = input.substring(0, matcher.start());
sb.append(URLEncoder.encode(pre, StandardCharsets.UTF_8));
sb.append(matcher.group());
idx = matcher.end();
// matcher.appendReplacement(sb, "test-value" + idx);
}
sb.append(URLEncoder.encode(input.substring(idx), StandardCharsets.UTF_8));
return sb.toString();
}
}

View File

@@ -45,7 +45,7 @@ You can even make a detailed request with custom headers and result verification
```yaml
# Require that the result be status code 200-299 match regex "OK, account id is .*" in the body
statements:
- name: 'get-from-google'
- name: 'get-from-google'
method: GET
uri: "https://google.com/"
version: "HTTP/1.1"
@@ -120,12 +120,19 @@ All other request fields are optional and have reasonable defaults:
- **uri** - This is the URI that you might put into the URL bar of your
browser. There is no default.
Example: `https://en.wikipedia.org/wiki/Leonhard_Euler`
If the uri contains a question mark '?' as a query delimiter, then all
characters after this are automatically URL encoded. This is done for
any literal part of the uri. If you use bindings in the uri as
in `https://en.wikipedia.org/wiki/{topic}`, then it is up to you to
ensure that the values are produced in a valid form for a URI. You can
use the `URLEncode()` binding function where needed to achieve this.
embedded sections which are contained within `URLENCODE[[` ... `]]`
sections are preprocessed by the HTTP driver. This allows you to keep
your test data in a recognizable form. This is done at startup, so there
is no cost during the test run. As an added convenience, binding points
which are within the encoded block will be preserved, so
both `https://en.wikipedia.org/URLENCODE[[wiki/]]{topic}` and
`https://en.wikipedia.org/URLENCODE[[wiki/{topic}]]` will yield the same
configuration. For a terser form, you can use `E[[...]]`. You must also
ensure that the values that are inserted at binding points are produced
in a valid form for a URI. You can use the `URLEncode()`
binding function where needed to achieve this.
- **method** - An optional request method. If not provided, "GET" is assumed. Any method name will
work here, even custom ones that are specific to a given target system. No validation is done for
standard method names, as there is no way to know what method names may be valid.
@@ -177,49 +184,49 @@ results. Support may be added for long-lived connections in a future release.
- **follow_redirects** - default: normal - One of never, always, or
normal. Normal redirects
are those which do not redirect from HTTPS to HTTP.
- **diagnostics** - default: none - synonym: **diag**
example: `diag=brief,1000` - print diagnostics for every 1000th
cycle, including only brief details as explained below.
This setting is a selector for what level of verbosity you will get
on the console. If you set this to true, you'll get every request
and response logged to console. This is only for verifying that a test
is configured and to spot check services before running higher scale
tests.
All of the data shown in diagnostics is post-hoc, directly from
the response provided by the internal HTTP client in the Java runtime.
example: `diag=brief,1000` - print diagnostics for every 1000th cycle,
including only brief details as explained below.
This setting is a selector for what level of verbosity you will get on
the console. If you set this to true, you'll get every request and
response logged to console. This is only for verifying that a test is
configured and to spot check services before running higher scale tests.
All of the data shown in diagnostics is post-hoc, directly from the
response provided by the internal HTTP client in the Java runtime.
If you want finer control over how much information diagnostics
provides, you can specify a comma separated list of the below.
- headers - show headers
- stats - show basic stats of each request
- data10 - show only the first 10 characters of each response body
- data100 - show only the first 100 characters of each response body
this setting supersedes `data10`
- data1000 - show only the first 1000 characters of each response body
this setting supersedes `data100`
- data - show all of each response body
this setting supersedes `data1000`
- redirects - show details for interstitial request which are made
when the client follows a redirect directive like a `location` header.
- requests - show details for requests
- responses - show details for responses
- brief - Show headers, stats, requests, responses, and 10 characters
- all - Show everything, including full payloads and redirects
- a modulo - any number, like 3000 - causes the diagnostics to be
reported only on this cycle modulo. If you set `diag=300,brief`
then you will get the brief diagnostic output for every 300th
response.
- headers - show headers
- stats - show basic stats of each request
- data10 - show only the first 10 characters of each response body
- data100 - show only the first 100 characters of each response body
this setting supersedes `data10`
- data1000 - show only the first 1000 characters of each response body
this setting supersedes `data100`
- data - show all of each response body this setting
supersedes `data1000`
- redirects - show details for interstitial request which are made
when the client follows a redirect directive like a `location`
header.
- requests - show details for requests
- responses - show details for responses
- brief - Show headers, stats, requests, responses, and 10 characters
- all - Show everything, including full payloads and redirects
- a modulo - any number, like 3000 - causes the diagnostics to be
reported only on this cycle modulo. If you set `diag=300,brief`
then you will get the brief diagnostic output for every 300th
response.
The requests, responses, and redirects setting work intersectionally.
For example, if you specify responses, and redirect, but not requests,
then you will only see the response portion of all calls made by the
client.
All of the diagnostic filters are incrementally added.
- **timeout** - default: forever -
Sets the timeout of each request in milliseconds.
All of the diagnostic filters are incrementally added.
- **timeout** - default: forever - Sets the timeout of each request in
milliseconds.