Add a Host: header to HTTP request snippets

HTTP 1.1 requires a Host: header in all requests. This commit updates
the HTTP request snippet to ensure that such a header is always
present.

Closes gh-85
This commit is contained in:
Andy Wilkinson
2015-07-13 18:05:39 +01:00
parent 5d44015e7d
commit 833a01d6a5
2 changed files with 58 additions and 21 deletions

View File

@@ -100,13 +100,15 @@ public abstract class HttpDocumentation {
this.result.getRequest());
this.writer.printf("%s %s HTTP/1.1%n", request.getMethod(),
request.getRequestUriWithQueryString());
if (requiresHostHeader(request)) {
writeHeader(HttpHeaders.HOST, request.getHost());
}
for (Entry<String, List<String>> header : request.getHeaders().entrySet()) {
for (String value : header.getValue()) {
if (header.getKey() == HttpHeaders.CONTENT_TYPE
&& request.isMultipartRequest()) {
this.writer.printf("%s: %s; boundary=%s%n", header.getKey(),
value, MULTIPART_BOUNDARY);
writeHeader(header.getKey(), String.format("%s; boundary=%s",
value, MULTIPART_BOUNDARY));
}
else {
this.writer.printf("%s: %s%n", header.getKey(), value);
@@ -115,7 +117,7 @@ public abstract class HttpDocumentation {
}
}
if (requiresFormEncodingContentType(request)) {
this.writer.printf("%s: %s%n", HttpHeaders.CONTENT_TYPE,
writeHeader(HttpHeaders.CONTENT_TYPE,
MediaType.APPLICATION_FORM_URLENCODED_VALUE);
}
this.writer.println();
@@ -133,6 +135,10 @@ public abstract class HttpDocumentation {
}
}
private boolean requiresHostHeader(DocumentableHttpServletRequest request) {
return request.getHeaders().get(HttpHeaders.HOST) == null;
}
private boolean requiresFormEncodingContentType(
DocumentableHttpServletRequest request) {
return request.getHeaders().getContentType() == null
@@ -140,6 +146,10 @@ public abstract class HttpDocumentation {
&& StringUtils.hasText(request.getParameterMapAsQueryString());
}
private void writeHeader(String name, String value) {
this.writer.printf("%s: %s%n", name, value);
}
private void writeParts(DocumentableHttpServletRequest request)
throws IOException {
for (Entry<String, List<MultipartFile>> entry : request.getMultipartFiles()

View File

@@ -35,7 +35,9 @@ import java.io.IOException;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.restdocs.test.ExpectedSnippet;
@@ -54,7 +56,8 @@ public class HttpDocumentationTests {
@Test
public void getRequest() throws IOException {
this.snippet.expectHttpRequest("get-request").withContents(
httpRequest(GET, "/foo").header("Alpha", "a"));
httpRequest(GET, "/foo").header(HttpHeaders.HOST, "localhost").header(
"Alpha", "a"));
documentHttpRequest("get-request").handle(
result(get("/foo").header("Alpha", "a")));
@@ -63,7 +66,7 @@ public class HttpDocumentationTests {
@Test
public void getRequestWithQueryString() throws IOException {
this.snippet.expectHttpRequest("get-request-with-query-string").withContents(
httpRequest(GET, "/foo?bar=baz"));
httpRequest(GET, "/foo?bar=baz").header(HttpHeaders.HOST, "localhost"));
documentHttpRequest("get-request-with-query-string").handle(
result(get("/foo?bar=baz")));
@@ -72,7 +75,7 @@ public class HttpDocumentationTests {
@Test
public void getRequestWithParameter() throws IOException {
this.snippet.expectHttpRequest("get-request-with-parameter").withContents(
httpRequest(GET, "/foo?b%26r=baz"));
httpRequest(GET, "/foo?b%26r=baz").header(HttpHeaders.HOST, "localhost"));
documentHttpRequest("get-request-with-parameter").handle(
result(get("/foo").param("b&r", "baz")));
@@ -81,8 +84,8 @@ public class HttpDocumentationTests {
@Test
public void postRequestWithContent() throws IOException {
this.snippet.expectHttpRequest("post-request-with-content").withContents(
httpRequest(POST, "/foo") //
.content("Hello, world"));
httpRequest(POST, "/foo").header(HttpHeaders.HOST, "localhost").content(
"Hello, world"));
documentHttpRequest("post-request-with-content").handle(
result(post("/foo").content("Hello, world")));
@@ -91,8 +94,8 @@ public class HttpDocumentationTests {
@Test
public void postRequestWithParameter() throws IOException {
this.snippet.expectHttpRequest("post-request-with-parameter").withContents(
httpRequest(POST, "/foo") //
.header("Content-Type", "application/x-www-form-urlencoded") //
httpRequest(POST, "/foo").header(HttpHeaders.HOST, "localhost")
.header("Content-Type", "application/x-www-form-urlencoded")
.content("b%26r=baz&a=alpha"));
documentHttpRequest("post-request-with-parameter").handle(
@@ -102,8 +105,8 @@ public class HttpDocumentationTests {
@Test
public void putRequestWithContent() throws IOException {
this.snippet.expectHttpRequest("put-request-with-content").withContents(
httpRequest(PUT, "/foo") //
.content("Hello, world"));
httpRequest(PUT, "/foo").header(HttpHeaders.HOST, "localhost").content(
"Hello, world"));
documentHttpRequest("put-request-with-content").handle(
result(put("/foo").content("Hello, world")));
@@ -112,8 +115,8 @@ public class HttpDocumentationTests {
@Test
public void putRequestWithParameter() throws IOException {
this.snippet.expectHttpRequest("put-request-with-parameter").withContents(
httpRequest(PUT, "/foo") //
.header("Content-Type", "application/x-www-form-urlencoded") //
httpRequest(PUT, "/foo").header(HttpHeaders.HOST, "localhost")
.header("Content-Type", "application/x-www-form-urlencoded")
.content("b%26r=baz&a=alpha"));
documentHttpRequest("put-request-with-parameter").handle(
@@ -164,9 +167,11 @@ public class HttpDocumentationTests {
String expectedContent = String.format("--%s%nContent-Disposition: form-data; "
+ "name=image%n%n<< data >>%n--%s--", boundary, boundary);
this.snippet.expectHttpRequest("multipart-post").withContents(
httpRequest(POST, "/upload").header("Content-Type",
"multipart/form-data; boundary=" + boundary).content(
expectedContent));
httpRequest(POST, "/upload")
.header(HttpHeaders.HOST, "localhost")
.header("Content-Type",
"multipart/form-data; boundary=" + boundary)
.content(expectedContent));
MockMultipartFile multipartFile = new MockMultipartFile("image",
"documents/images/example.png", null, "<< data >>".getBytes());
documentHttpRequest("multipart-post").handle(
@@ -180,13 +185,35 @@ public class HttpDocumentationTests {
+ "name=image%nContent-Type: image/png%n%n<< data >>%n--%s--", boundary,
boundary);
this.snippet.expectHttpRequest("multipart-post-with-content-type").withContents(
httpRequest(POST, "/upload").header("Content-Type",
"multipart/form-data; boundary=" + boundary).content(
expectedContent));
httpRequest(POST, "/upload")
.header(HttpHeaders.HOST, "localhost")
.header("Content-Type",
"multipart/form-data; boundary=" + boundary)
.content(expectedContent));
MockMultipartFile multipartFile = new MockMultipartFile("image",
"documents/images/example.png", MediaType.IMAGE_PNG_VALUE,
"<< data >>".getBytes());
documentHttpRequest("multipart-post-with-content-type").handle(
result(fileUpload("/upload").file(multipartFile)));
}
@Test
public void getRequestWithCustomServerName() throws IOException {
this.snippet.expectHttpRequest("get-request-custom-server-name").withContents(
httpRequest(GET, "/foo").header(HttpHeaders.HOST, "api.example.com"));
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
request.setServerName("api.example.com");
documentHttpRequest("get-request-custom-server-name").handle(result(request));
}
@Test
public void getRequestWithCustomHost() throws IOException {
this.snippet.expectHttpRequest("get-request-custom-host").withContents(
httpRequest(GET, "/foo").header(HttpHeaders.HOST, "api.example.com"));
documentHttpRequest("get-request-custom-host").handle(
result(get("/foo").header(HttpHeaders.HOST, "api.example.com")));
}
}