diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/curl/CurlDocumentation.java b/spring-restdocs/src/main/java/org/springframework/restdocs/curl/CurlDocumentation.java index bb9a3ee2..cd738df7 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/curl/CurlDocumentation.java +++ b/spring-restdocs/src/main/java/org/springframework/restdocs/curl/CurlDocumentation.java @@ -20,6 +20,9 @@ import static org.springframework.restdocs.util.IterableEnumeration.iterable; import java.io.IOException; import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.Map; import javax.servlet.http.HttpServletRequest; @@ -29,6 +32,7 @@ import org.springframework.restdocs.snippet.DocumentationWriter; import org.springframework.restdocs.snippet.DocumentationWriter.DocumentationAction; import org.springframework.test.web.servlet.MvcResult; import org.springframework.util.FileCopyUtils; +import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMethod; /** @@ -36,6 +40,7 @@ import org.springframework.web.bind.annotation.RequestMethod; * the cURL command-line utility. * * @author Andy Wilkinson + * @author Yann Le Guern */ public abstract class CurlDocumentation { @@ -141,9 +146,8 @@ public abstract class CurlDocumentation { this.writer.print(" -i"); } - RequestMethod requestMethod = RequestMethod.valueOf(request.getMethod()); - if (requestMethod != RequestMethod.GET) { - this.writer.print(String.format(" -X %s", requestMethod.toString())); + if (!isGetRequest(request)) { + this.writer.print(String.format(" -X %s", request.getMethod())); } for (String headerName : iterable(request.getHeaderNames())) { @@ -160,6 +164,10 @@ public abstract class CurlDocumentation { this.writer.println(); } + private boolean isGetRequest(HttpServletRequest request) { + return RequestMethod.GET == RequestMethod.valueOf(request.getMethod()); + } + private boolean isNonStandardPort(HttpServletRequest request) { return (SCHEME_HTTP.equals(request.getScheme()) && request.getRemotePort() != STANDARD_PORT_HTTP) || (SCHEME_HTTPS.equals(request.getScheme()) && request @@ -167,8 +175,47 @@ public abstract class CurlDocumentation { } private String getRequestUriWithQueryString(HttpServletRequest request) { - return request.getQueryString() != null ? request.getRequestURI() + "?" - + request.getQueryString() : request.getRequestURI(); + StringBuilder sb = new StringBuilder(); + sb.append(request.getRequestURI()); + String queryString = getQueryString(request); + if (StringUtils.hasText(queryString)) { + sb.append('?').append(queryString); + } + return sb.toString(); + } + + private String getQueryString(HttpServletRequest request) { + if (request.getQueryString() != null) { + return request.getQueryString(); + } + if (isGetRequest(request)) { + return toQueryString(request.getParameterMap()); + } + return null; + } + + private static String toQueryString(Map map) { + StringBuilder sb = new StringBuilder(); + for (Map.Entry entry : map.entrySet()) { + for (String value : entry.getValue()) { + if (sb.length() > 0) { + sb.append("&"); + } + sb.append(urlEncodeUTF8(entry.getKey())).append('=') + .append(urlEncodeUTF8(value)); + } + } + return sb.toString(); + } + + private static String urlEncodeUTF8(String s) { + try { + return URLEncoder.encode(s, "UTF-8"); + } + catch (UnsupportedEncodingException ex) { + throw new IllegalStateException("Unable to URL encode " + s + + " using UTF-8", ex); + } } private String getContent(MockHttpServletRequest request) throws IOException { diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/curl/CurlDocumentationTests.java b/spring-restdocs/src/test/java/org/springframework/restdocs/curl/CurlDocumentationTests.java index 8b590ec5..caaa90e6 100644 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/curl/CurlDocumentationTests.java +++ b/spring-restdocs/src/test/java/org/springframework/restdocs/curl/CurlDocumentationTests.java @@ -44,6 +44,7 @@ import org.springframework.restdocs.StubMvcResult; * Tests for {@link CurlDocumentation} * * @author Andy Wilkinson + * @author Yann Le Guern */ public class CurlDocumentationTests { @@ -114,6 +115,38 @@ public class CurlDocumentationTests { hasItem("$ curl http://localhost/foo?param=value -i")); } + @Test + public void requestWithOneParameter() throws IOException { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo"); + request.addParameter("k1", "v1"); + documentCurlRequest("request-with-one-parameter").handle( + new StubMvcResult(request, null)); + assertThat(requestSnippetLines("request-with-one-parameter"), + hasItem("$ curl http://localhost/foo?k1=v1 -i")); + } + + @Test + public void requestWithMultipleParameters() throws IOException { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo"); + request.addParameter("k1", "v1"); + request.addParameter("k2", "v2"); + request.addParameter("k1", "v1-bis"); + documentCurlRequest("request-with-multiple-parameters").handle( + new StubMvcResult(request, null)); + assertThat(requestSnippetLines("request-with-multiple-parameters"), + hasItem("$ curl http://localhost/foo?k1=v1&k1=v1-bis&k2=v2 -i")); + } + + @Test + public void requestWithUrlEncodedParameter() throws IOException { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo"); + request.addParameter("k1", "foo bar&"); + documentCurlRequest("request-with-url-encoded-parameter").handle( + new StubMvcResult(request, null)); + assertThat(requestSnippetLines("request-with-url-encoded-parameter"), + hasItem("$ curl http://localhost/foo?k1=foo+bar%26 -i")); + } + @Test public void requestWithHeaders() throws IOException { MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");