Ensure that query string is not duplicated when parameters overlap

Closes gh-286
This commit is contained in:
Andy Wilkinson
2016-07-29 21:10:21 +01:00
parent 110fa23958
commit bf9b0f2d64
8 changed files with 276 additions and 59 deletions

View File

@@ -52,34 +52,6 @@ final class CliOperationRequest implements OperationRequest {
new BasicAuthHeaderFilter(), new HostHeaderFilter(delegate.getUri())));
}
Parameters getUniqueParameters() {
Parameters queryStringParameters = new QueryStringParser()
.parse(this.delegate.getUri());
Parameters uniqueParameters = new Parameters();
for (Map.Entry<String, List<String>> parameter : this.delegate.getParameters()
.entrySet()) {
addIfUnique(parameter, queryStringParameters, uniqueParameters);
}
return uniqueParameters;
}
private void addIfUnique(Map.Entry<String, List<String>> parameter,
Parameters queryStringParameters, Parameters uniqueParameters) {
if (!queryStringParameters.containsKey(parameter.getKey())) {
uniqueParameters.put(parameter.getKey(), parameter.getValue());
}
else {
List<String> candidates = parameter.getValue();
List<String> existing = queryStringParameters.get(parameter.getKey());
for (String candidate : candidates) {
if (!existing.contains(candidate)) {
uniqueParameters.add(parameter.getKey(), candidate);
}
}
}
}
boolean isPutOrPost() {
return HttpMethod.PUT.equals(this.delegate.getMethod())
|| HttpMethod.POST.equals(this.delegate.getMethod());

View File

@@ -70,9 +70,12 @@ public class CurlRequestSnippet extends TemplatedSnippet {
private String getUrl(Operation operation) {
OperationRequest request = operation.getRequest();
if (!request.getParameters().isEmpty() && includeParametersInUri(request)) {
return String.format("'%s?%s'", request.getUri(),
request.getParameters().toQueryString());
Parameters uniqueParameters = request.getParameters()
.getUniqueParameters(operation.getRequest().getUri());
if (!uniqueParameters.isEmpty() && includeParametersInUri(request)) {
return String.format("'%s%s%s'", request.getUri(),
StringUtils.hasText(request.getUri().getRawQuery()) ? "&" : "?",
uniqueParameters.toQueryString());
}
return String.format("'%s'", request.getUri());
}
@@ -157,9 +160,10 @@ public class CurlRequestSnippet extends TemplatedSnippet {
}
}
private void writeContentUsingParameters(CliOperationRequest request,
private void writeContentUsingParameters(OperationRequest request,
PrintWriter writer) {
Parameters uniqueParameters = request.getUniqueParameters();
Parameters uniqueParameters = request.getParameters()
.getUniqueParameters(request.getUri());
String queryString = uniqueParameters.toQueryString();
if (StringUtils.hasText(queryString)) {
writer.print(String.format(" -d '%s'", queryString));

View File

@@ -90,10 +90,13 @@ public class HttpieRequestSnippet extends TemplatedSnippet {
return options.toString();
}
private String getUrl(CliOperationRequest request) {
if (!request.getUniqueParameters().isEmpty() && includeParametersInUri(request)) {
return String.format("'%s?%s'", request.getUri(),
request.getParameters().toQueryString());
private String getUrl(OperationRequest request) {
Parameters uniqueParameters = request.getParameters()
.getUniqueParameters(request.getUri());
if (!uniqueParameters.isEmpty() && includeParametersInUri(request)) {
return String.format("'%s%s%s'", request.getUri(),
StringUtils.hasText(request.getUri().getRawQuery()) ? "&" : "?",
uniqueParameters.toQueryString());
}
return String.format("'%s'", request.getUri());
}
@@ -107,14 +110,15 @@ public class HttpieRequestSnippet extends TemplatedSnippet {
return requestItems.toString();
}
private void writeOptions(CliOperationRequest request, PrintWriter writer) {
if (!request.getParts().isEmpty() || (!request.getUniqueParameters().isEmpty()
&& !includeParametersInUri(request))) {
private void writeOptions(OperationRequest request, PrintWriter writer) {
if (!request.getParts().isEmpty()
|| (!request.getParameters().getUniqueParameters(request.getUri())
.isEmpty() && !includeParametersInUri(request))) {
writer.print("--form ");
}
}
private boolean includeParametersInUri(CliOperationRequest request) {
private boolean includeParametersInUri(OperationRequest request) {
return request.getMethod() == HttpMethod.GET || request.getContent().length > 0;
}
@@ -167,7 +171,9 @@ public class HttpieRequestSnippet extends TemplatedSnippet {
writeContentUsingParameters(request.getParameters(), writer);
}
else if (request.isPutOrPost()) {
writeContentUsingParameters(request.getUniqueParameters(), writer);
writeContentUsingParameters(
request.getParameters().getUniqueParameters(request.getUri()),
writer);
}
}

View File

@@ -30,6 +30,7 @@ import org.springframework.http.MediaType;
import org.springframework.restdocs.operation.Operation;
import org.springframework.restdocs.operation.OperationRequest;
import org.springframework.restdocs.operation.OperationRequestPart;
import org.springframework.restdocs.operation.Parameters;
import org.springframework.restdocs.snippet.Snippet;
import org.springframework.restdocs.snippet.TemplatedSnippet;
import org.springframework.util.StringUtils;
@@ -75,12 +76,14 @@ public class HttpRequestSnippet extends TemplatedSnippet {
private String getPath(OperationRequest request) {
String path = request.getUri().getRawPath();
String queryString = request.getUri().getRawQuery();
if (!request.getParameters().isEmpty() && includeParametersInUri(request)) {
Parameters uniqueParameters = request.getParameters()
.getUniqueParameters(request.getUri());
if (!uniqueParameters.isEmpty() && includeParametersInUri(request)) {
if (StringUtils.hasText(queryString)) {
queryString = queryString + "&" + request.getParameters().toQueryString();
queryString = queryString + "&" + uniqueParameters.toQueryString();
}
else {
queryString = request.getParameters().toQueryString();
queryString = uniqueParameters.toQueryString();
}
}
if (StringUtils.hasText(queryString)) {

View File

@@ -17,10 +17,12 @@
package org.springframework.restdocs.operation;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import org.springframework.restdocs.cli.QueryStringParser;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.StringUtils;
@@ -53,6 +55,39 @@ public class Parameters extends LinkedMultiValueMap<String, String> {
return sb.toString();
}
/**
* Returns a new {@code Parameters} containing only the parameters that do no appear
* in the query string of the given {@code uri}.
*
* @param uri the uri
* @return the unique parameters
*/
public Parameters getUniqueParameters(URI uri) {
Parameters queryStringParameters = new QueryStringParser().parse(uri);
Parameters uniqueParameters = new Parameters();
for (Map.Entry<String, List<String>> parameter : entrySet()) {
addIfUnique(parameter, queryStringParameters, uniqueParameters);
}
return uniqueParameters;
}
private void addIfUnique(Map.Entry<String, List<String>> parameter,
Parameters queryStringParameters, Parameters uniqueParameters) {
if (!queryStringParameters.containsKey(parameter.getKey())) {
uniqueParameters.put(parameter.getKey(), parameter.getValue());
}
else {
List<String> candidates = parameter.getValue();
List<String> existing = queryStringParameters.get(parameter.getKey());
for (String candidate : candidates) {
if (!existing.contains(candidate)) {
uniqueParameters.add(parameter.getKey(), candidate);
}
}
}
}
private static void append(StringBuilder sb, String key) {
append(sb, key, "");
}