diff --git a/docs/src/docs/asciidoc/customizing-requests-and-responses.adoc b/docs/src/docs/asciidoc/customizing-requests-and-responses.adoc index 458e47a1..f47b9fd0 100644 --- a/docs/src/docs/asciidoc/customizing-requests-and-responses.adoc +++ b/docs/src/docs/asciidoc/customizing-requests-and-responses.adoc @@ -143,12 +143,13 @@ parameters. [[customizing-requests-and-responses-preprocessors-modify-uris]] ==== Modifying URIs -TIP: If you are using MockMvc or WebTestclient, URIs should be customized by -<>. +TIP: If you are using MockMvc or a WebTestClient that is not bound to a server, +URIs should be customized by <>. -`modifyUris` on `RestAssuredPreprocessors` can be used to modify any URIs in a request -or a response. When using REST Assured, this allows you to customize the URIs that appear -in the documentation while testing a local instance of the service. +`modifyUris` on `Preprocessors` can be used to modify any URIs in a request +or a response. When using REST Assured or WebTestClient bound to a server, this +allows you to customize the URIs that appear in the documentation while testing a +local instance of the service. diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/Preprocessors.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/Preprocessors.java index 23a31037..4aa19a63 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/Preprocessors.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/Preprocessors.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2015 the original author or authors. + * Copyright 2014-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -151,4 +151,15 @@ public final class Preprocessors { return new ParametersModifyingOperationPreprocessor(); } + /** + * Returns a {@code UriModifyingOperationPreprocessor} that will modify URIs in the + * request or response by changing one or more of their host, scheme, and port. + * + * @return the preprocessor + * @since 2.0.1 + */ + public static UriModifyingOperationPreprocessor modifyUris() { + return new UriModifyingOperationPreprocessor(); + } + } diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/UriModifyingOperationPreprocessor.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/UriModifyingOperationPreprocessor.java new file mode 100644 index 00000000..ae28056f --- /dev/null +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/preprocess/UriModifyingOperationPreprocessor.java @@ -0,0 +1,252 @@ +/* + * Copyright 2014-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.restdocs.operation.preprocess; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map.Entry; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.restdocs.operation.OperationRequest; +import org.springframework.restdocs.operation.OperationRequestFactory; +import org.springframework.restdocs.operation.OperationRequestPart; +import org.springframework.restdocs.operation.OperationRequestPartFactory; +import org.springframework.restdocs.operation.OperationResponse; +import org.springframework.restdocs.operation.OperationResponseFactory; +import org.springframework.util.StringUtils; +import org.springframework.web.util.UriComponentsBuilder; + +/** + * An {@link OperationPreprocessor} that modifies URIs in the request and in the response + * by changing one or more of their host, scheme, and port. URIs in the following + * locations are modified: + * + * + * @author Andy Wilkinson + * @since 2.0.1 + */ +public class UriModifyingOperationPreprocessor implements OperationPreprocessor { + + private final UriModifyingContentModifier contentModifier = new UriModifyingContentModifier(); + + private final OperationPreprocessor contentModifyingDelegate = new ContentModifyingOperationPreprocessor( + this.contentModifier); + + private String scheme; + + private String host; + + private String port; + + /** + * Modifies the URI to use the given {@code scheme}. {@code null}, the default, will + * leave the scheme unchanged. + * + * @param scheme the scheme + * @return {@code this} + */ + public UriModifyingOperationPreprocessor scheme(String scheme) { + this.scheme = scheme; + this.contentModifier.setScheme(scheme); + return this; + } + + /** + * Modifies the URI to use the given {@code host}. {@code null}, the default, will + * leave the host unchanged. + * + * @param host the host + * @return {@code this} + */ + public UriModifyingOperationPreprocessor host(String host) { + this.host = host; + this.contentModifier.setHost(host); + return this; + } + + /** + * Modifies the URI to use the given {@code port}. + * + * @param port the port + * @return {@code this} + */ + public UriModifyingOperationPreprocessor port(int port) { + return port(Integer.toString(port)); + } + + /** + * Removes the port from the URI. + * + * @return {@code this} + */ + public UriModifyingOperationPreprocessor removePort() { + return port(""); + } + + private UriModifyingOperationPreprocessor port(String port) { + this.port = port; + this.contentModifier.setPort(port); + return this; + } + + @Override + public OperationRequest preprocess(OperationRequest request) { + UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUri(request.getUri()); + if (this.scheme != null) { + uriBuilder.scheme(this.scheme); + } + if (this.host != null) { + uriBuilder.host(this.host); + } + if (this.port != null) { + if (StringUtils.hasText(this.port)) { + uriBuilder.port(this.port); + } + else { + uriBuilder.port(null); + } + } + URI modifiedUri = uriBuilder.build(true).toUri(); + HttpHeaders modifiedHeaders = modify(request.getHeaders()); + modifiedHeaders.set(HttpHeaders.HOST, modifiedUri.getHost() + + (modifiedUri.getPort() == -1 ? "" : ":" + modifiedUri.getPort())); + return this.contentModifyingDelegate.preprocess( + new OperationRequestFactory().create(uriBuilder.build(true).toUri(), + request.getMethod(), request.getContent(), modifiedHeaders, + request.getParameters(), modify(request.getParts()))); + } + + @Override + public OperationResponse preprocess(OperationResponse response) { + return this.contentModifyingDelegate + .preprocess(new OperationResponseFactory().create(response.getStatus(), + modify(response.getHeaders()), response.getContent())); + } + + private HttpHeaders modify(HttpHeaders headers) { + HttpHeaders modified = new HttpHeaders(); + for (Entry> header : headers.entrySet()) { + for (String value : header.getValue()) { + modified.add(header.getKey(), this.contentModifier.modify(value)); + } + } + return modified; + } + + private Collection modify( + Collection parts) { + List modifiedParts = new ArrayList<>(); + OperationRequestPartFactory factory = new OperationRequestPartFactory(); + for (OperationRequestPart part : parts) { + modifiedParts.add(factory.create(part.getName(), part.getSubmittedFileName(), + this.contentModifier.modifyContent(part.getContent(), + part.getHeaders().getContentType()), + modify(part.getHeaders()))); + } + return modifiedParts; + } + + private static final class UriModifyingContentModifier implements ContentModifier { + + private static final Pattern SCHEME_HOST_PORT_PATTERN = Pattern + .compile("(http[s]?)://([^/:#?]+)(:[0-9]+)?"); + + private String scheme; + + private String host; + + private String port; + + private void setScheme(String scheme) { + this.scheme = scheme; + } + + private void setHost(String host) { + this.host = host; + } + + private void setPort(String port) { + this.port = port; + } + + @Override + public byte[] modifyContent(byte[] content, MediaType contentType) { + String input; + if (contentType != null && contentType.getCharset() != null) { + input = new String(content, contentType.getCharset()); + } + else { + input = new String(content); + } + + return modify(input).getBytes(); + } + + private String modify(String input) { + List replacements = Arrays.asList(this.scheme, this.host, + StringUtils.hasText(this.port) ? ":" + this.port : this.port); + + int previous = 0; + + Matcher matcher = SCHEME_HOST_PORT_PATTERN.matcher(input); + StringBuilder builder = new StringBuilder(); + while (matcher.find()) { + for (int i = 1; i <= matcher.groupCount(); i++) { + if (matcher.start(i) >= 0) { + builder.append(input.substring(previous, matcher.start(i))); + } + if (matcher.start(i) >= 0) { + previous = matcher.end(i); + } + builder.append( + getReplacement(matcher.group(i), replacements.get(i - 1))); + } + } + + if (previous < input.length()) { + builder.append(input.substring(previous)); + } + return builder.toString(); + } + + private String getReplacement(String original, String candidate) { + if (candidate != null) { + return candidate; + } + if (original != null) { + return original; + } + return ""; + } + + } + +} diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/UriModifyingOperationPreprocessorTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/UriModifyingOperationPreprocessorTests.java new file mode 100644 index 00000000..27278eb5 --- /dev/null +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/operation/preprocess/UriModifyingOperationPreprocessorTests.java @@ -0,0 +1,373 @@ +/* + * Copyright 2014-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.restdocs.operation.preprocess; + +import java.net.URI; +import java.util.Arrays; +import java.util.Collections; + +import org.junit.Test; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.restdocs.operation.OperationRequest; +import org.springframework.restdocs.operation.OperationRequestFactory; +import org.springframework.restdocs.operation.OperationRequestPart; +import org.springframework.restdocs.operation.OperationRequestPartFactory; +import org.springframework.restdocs.operation.OperationResponse; +import org.springframework.restdocs.operation.OperationResponseFactory; +import org.springframework.restdocs.operation.Parameters; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * Tests for {@link UriModifyingOperationPreprocessor}. + * + * @author Andy Wilkinson + */ +public class UriModifyingOperationPreprocessorTests { + + private final OperationRequestFactory requestFactory = new OperationRequestFactory(); + + private final OperationResponseFactory responseFactory = new OperationResponseFactory(); + + private final UriModifyingOperationPreprocessor preprocessor = new UriModifyingOperationPreprocessor(); + + @Test + public void requestUriSchemeCanBeModified() { + this.preprocessor.scheme("https"); + OperationRequest processed = this.preprocessor + .preprocess(createRequestWithUri("http://localhost:12345")); + assertThat(processed.getUri(), + is(equalTo(URI.create("https://localhost:12345")))); + } + + @Test + public void requestUriHostCanBeModified() { + this.preprocessor.host("api.example.com"); + OperationRequest processed = this.preprocessor + .preprocess(createRequestWithUri("http://api.foo.com:12345")); + assertThat(processed.getUri(), + is(equalTo(URI.create("http://api.example.com:12345")))); + assertThat(processed.getHeaders().getFirst(HttpHeaders.HOST), + is(equalTo("api.example.com:12345"))); + } + + @Test + public void requestUriPortCanBeModified() { + this.preprocessor.port(23456); + OperationRequest processed = this.preprocessor + .preprocess(createRequestWithUri("http://api.example.com:12345")); + assertThat(processed.getUri(), + is(equalTo(URI.create("http://api.example.com:23456")))); + assertThat(processed.getHeaders().getFirst(HttpHeaders.HOST), + is(equalTo("api.example.com:23456"))); + } + + @Test + public void requestUriPortCanBeRemoved() { + this.preprocessor.removePort(); + OperationRequest processed = this.preprocessor + .preprocess(createRequestWithUri("http://api.example.com:12345")); + assertThat(processed.getUri(), is(equalTo(URI.create("http://api.example.com")))); + assertThat(processed.getHeaders().getFirst(HttpHeaders.HOST), + is(equalTo("api.example.com"))); + } + + @Test + public void requestUriPathIsPreserved() { + this.preprocessor.removePort(); + OperationRequest processed = this.preprocessor + .preprocess(createRequestWithUri("http://api.example.com:12345/foo/bar")); + assertThat(processed.getUri(), + is(equalTo(URI.create("http://api.example.com/foo/bar")))); + } + + @Test + public void requestUriQueryIsPreserved() { + this.preprocessor.removePort(); + OperationRequest processed = this.preprocessor + .preprocess(createRequestWithUri("http://api.example.com:12345?foo=bar")); + assertThat(processed.getUri(), + is(equalTo(URI.create("http://api.example.com?foo=bar")))); + } + + @Test + public void requestUriAnchorIsPreserved() { + this.preprocessor.removePort(); + OperationRequest processed = this.preprocessor + .preprocess(createRequestWithUri("http://api.example.com:12345#foo")); + assertThat(processed.getUri(), + is(equalTo(URI.create("http://api.example.com#foo")))); + } + + @Test + public void requestContentUriSchemeCanBeModified() { + this.preprocessor.scheme("https"); + OperationRequest processed = this.preprocessor + .preprocess(createRequestWithContent( + "The uri 'http://localhost:12345' should be used")); + assertThat(new String(processed.getContent()), + is(equalTo("The uri 'https://localhost:12345' should be used"))); + } + + @Test + public void requestContentUriHostCanBeModified() { + this.preprocessor.host("api.example.com"); + OperationRequest processed = this.preprocessor + .preprocess(createRequestWithContent( + "The uri 'http://localhost:12345' should be used")); + assertThat(new String(processed.getContent()), + is(equalTo("The uri 'http://api.example.com:12345' should be used"))); + } + + @Test + public void requestContentUriPortCanBeModified() { + this.preprocessor.port(23456); + OperationRequest processed = this.preprocessor + .preprocess(createRequestWithContent( + "The uri 'http://localhost:12345' should be used")); + assertThat(new String(processed.getContent()), + is(equalTo("The uri 'http://localhost:23456' should be used"))); + } + + @Test + public void requestContentUriPortCanBeRemoved() { + this.preprocessor.removePort(); + OperationRequest processed = this.preprocessor + .preprocess(createRequestWithContent( + "The uri 'http://localhost:12345' should be used")); + assertThat(new String(processed.getContent()), + is(equalTo("The uri 'http://localhost' should be used"))); + } + + @Test + public void multipleRequestContentUrisCanBeModified() { + this.preprocessor.removePort(); + OperationRequest processed = this.preprocessor + .preprocess(createRequestWithContent( + "Use 'http://localhost:12345' or 'https://localhost:23456' to access the service")); + assertThat(new String(processed.getContent()), is(equalTo( + "Use 'http://localhost' or 'https://localhost' to access the service"))); + } + + @Test + public void requestContentUriPathIsPreserved() { + this.preprocessor.removePort(); + OperationRequest processed = this.preprocessor + .preprocess(createRequestWithContent( + "The uri 'http://localhost:12345/foo/bar' should be used")); + assertThat(new String(processed.getContent()), + is(equalTo("The uri 'http://localhost/foo/bar' should be used"))); + } + + @Test + public void requestContentUriQueryIsPreserved() { + this.preprocessor.removePort(); + OperationRequest processed = this.preprocessor + .preprocess(createRequestWithContent( + "The uri 'http://localhost:12345?foo=bar' should be used")); + assertThat(new String(processed.getContent()), + is(equalTo("The uri 'http://localhost?foo=bar' should be used"))); + } + + @Test + public void requestContentUriAnchorIsPreserved() { + this.preprocessor.removePort(); + OperationRequest processed = this.preprocessor + .preprocess(createRequestWithContent( + "The uri 'http://localhost:12345#foo' should be used")); + assertThat(new String(processed.getContent()), + is(equalTo("The uri 'http://localhost#foo' should be used"))); + } + + @Test + public void responseContentUriSchemeCanBeModified() { + this.preprocessor.scheme("https"); + OperationResponse processed = this.preprocessor + .preprocess(createResponseWithContent( + "The uri 'http://localhost:12345' should be used")); + assertThat(new String(processed.getContent()), + is(equalTo("The uri 'https://localhost:12345' should be used"))); + } + + @Test + public void responseContentUriHostCanBeModified() { + this.preprocessor.host("api.example.com"); + OperationResponse processed = this.preprocessor + .preprocess(createResponseWithContent( + "The uri 'http://localhost:12345' should be used")); + assertThat(new String(processed.getContent()), + is(equalTo("The uri 'http://api.example.com:12345' should be used"))); + } + + @Test + public void responseContentUriPortCanBeModified() { + this.preprocessor.port(23456); + OperationResponse processed = this.preprocessor + .preprocess(createResponseWithContent( + "The uri 'http://localhost:12345' should be used")); + assertThat(new String(processed.getContent()), + is(equalTo("The uri 'http://localhost:23456' should be used"))); + } + + @Test + public void responseContentUriPortCanBeRemoved() { + this.preprocessor.removePort(); + OperationResponse processed = this.preprocessor + .preprocess(createResponseWithContent( + "The uri 'http://localhost:12345' should be used")); + assertThat(new String(processed.getContent()), + is(equalTo("The uri 'http://localhost' should be used"))); + } + + @Test + public void multipleResponseContentUrisCanBeModified() { + this.preprocessor.removePort(); + OperationResponse processed = this.preprocessor + .preprocess(createResponseWithContent( + "Use 'http://localhost:12345' or 'https://localhost:23456' to access the service")); + assertThat(new String(processed.getContent()), is(equalTo( + "Use 'http://localhost' or 'https://localhost' to access the service"))); + } + + @Test + public void responseContentUriPathIsPreserved() { + this.preprocessor.removePort(); + OperationResponse processed = this.preprocessor + .preprocess(createResponseWithContent( + "The uri 'http://localhost:12345/foo/bar' should be used")); + assertThat(new String(processed.getContent()), + is(equalTo("The uri 'http://localhost/foo/bar' should be used"))); + } + + @Test + public void responseContentUriQueryIsPreserved() { + this.preprocessor.removePort(); + OperationResponse processed = this.preprocessor + .preprocess(createResponseWithContent( + "The uri 'http://localhost:12345?foo=bar' should be used")); + assertThat(new String(processed.getContent()), + is(equalTo("The uri 'http://localhost?foo=bar' should be used"))); + } + + @Test + public void responseContentUriAnchorIsPreserved() { + this.preprocessor.removePort(); + OperationResponse processed = this.preprocessor + .preprocess(createResponseWithContent( + "The uri 'http://localhost:12345#foo' should be used")); + assertThat(new String(processed.getContent()), + is(equalTo("The uri 'http://localhost#foo' should be used"))); + } + + @Test + public void urisInRequestHeadersCanBeModified() { + OperationRequest processed = this.preprocessor.host("api.example.com") + .preprocess(createRequestWithHeader("Foo", "http://locahost:12345")); + assertThat(processed.getHeaders().getFirst("Foo"), + is(equalTo("http://api.example.com:12345"))); + assertThat(processed.getHeaders().getFirst("Host"), + is(equalTo("api.example.com"))); + } + + @Test + public void urisInResponseHeadersCanBeModified() { + OperationResponse processed = this.preprocessor.host("api.example.com") + .preprocess(createResponseWithHeader("Foo", "http://locahost:12345")); + assertThat(processed.getHeaders().getFirst("Foo"), + is(equalTo("http://api.example.com:12345"))); + } + + @Test + public void urisInRequestPartHeadersCanBeModified() { + OperationRequest processed = this.preprocessor.host("api.example.com").preprocess( + createRequestWithPartWithHeader("Foo", "http://locahost:12345")); + assertThat(processed.getParts().iterator().next().getHeaders().getFirst("Foo"), + is(equalTo("http://api.example.com:12345"))); + } + + @Test + public void urisInRequestPartContentCanBeModified() { + OperationRequest processed = this.preprocessor.host("api.example.com") + .preprocess(createRequestWithPartWithContent( + "The uri 'http://localhost:12345' should be used")); + assertThat(new String(processed.getParts().iterator().next().getContent()), + is(equalTo("The uri 'http://api.example.com:12345' should be used"))); + } + + @Test + public void modifiedUriDoesNotGetDoubleEncoded() { + this.preprocessor.scheme("https"); + OperationRequest processed = this.preprocessor + .preprocess(createRequestWithUri("http://localhost:12345?foo=%7B%7D")); + assertThat(processed.getUri(), + is(equalTo(URI.create("https://localhost:12345?foo=%7B%7D")))); + + } + + private OperationRequest createRequestWithUri(String uri) { + return this.requestFactory.create(URI.create(uri), HttpMethod.GET, new byte[0], + new HttpHeaders(), new Parameters(), + Collections.emptyList()); + } + + private OperationRequest createRequestWithContent(String content) { + return this.requestFactory.create(URI.create("http://localhost"), HttpMethod.GET, + content.getBytes(), new HttpHeaders(), new Parameters(), + Collections.emptyList()); + } + + private OperationRequest createRequestWithHeader(String name, String value) { + HttpHeaders headers = new HttpHeaders(); + headers.add(name, value); + return this.requestFactory.create(URI.create("http://localhost"), HttpMethod.GET, + new byte[0], headers, new Parameters(), + Collections.emptyList()); + } + + private OperationRequest createRequestWithPartWithHeader(String name, String value) { + HttpHeaders headers = new HttpHeaders(); + headers.add(name, value); + return this.requestFactory.create(URI.create("http://localhost"), HttpMethod.GET, + new byte[0], new HttpHeaders(), new Parameters(), + Arrays.asList(new OperationRequestPartFactory().create("part", "fileName", + new byte[0], headers))); + } + + private OperationRequest createRequestWithPartWithContent(String content) { + return this.requestFactory.create(URI.create("http://localhost"), HttpMethod.GET, + new byte[0], new HttpHeaders(), new Parameters(), + Arrays.asList(new OperationRequestPartFactory().create("part", "fileName", + content.getBytes(), new HttpHeaders()))); + } + + private OperationResponse createResponseWithContent(String content) { + return this.responseFactory.create(HttpStatus.OK, new HttpHeaders(), + content.getBytes()); + } + + private OperationResponse createResponseWithHeader(String name, String value) { + HttpHeaders headers = new HttpHeaders(); + headers.add(name, value); + return this.responseFactory.create(HttpStatus.OK, headers, new byte[0]); + } + +} diff --git a/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured3/operation/preprocess/RestAssuredPreprocessors.java b/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured3/operation/preprocess/RestAssuredPreprocessors.java index 2deb20cc..49b669a1 100644 --- a/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured3/operation/preprocess/RestAssuredPreprocessors.java +++ b/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured3/operation/preprocess/RestAssuredPreprocessors.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2017 the original author or authors. + * Copyright 2014-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,8 @@ package org.springframework.restdocs.restassured3.operation.preprocess; import org.springframework.restdocs.operation.Operation; import org.springframework.restdocs.operation.OperationRequest; import org.springframework.restdocs.operation.OperationResponse; +import org.springframework.restdocs.operation.preprocess.Preprocessors; +import org.springframework.restdocs.operation.preprocess.UriModifyingOperationPreprocessor; /** * Static factory methods for creating @@ -29,7 +31,10 @@ import org.springframework.restdocs.operation.OperationResponse; * * @author Andy Wilkinson * @since 1.1.0 + * @deprecated since 2.0.1 in favor of {@link Preprocessors} and, specifically, + * {@link Preprocessors#modifyUris()} */ +@Deprecated public abstract class RestAssuredPreprocessors { private RestAssuredPreprocessors() { @@ -41,7 +46,9 @@ public abstract class RestAssuredPreprocessors { * request or response by changing one or more of their host, scheme, and port. * * @return the preprocessor + * @deprecated since 2.0.1 in favor of {@link Preprocessors#modifyUris()} */ + @Deprecated public static UriModifyingOperationPreprocessor modifyUris() { return new UriModifyingOperationPreprocessor(); } diff --git a/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured3/operation/preprocess/UriModifyingOperationPreprocessor.java b/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured3/operation/preprocess/UriModifyingOperationPreprocessor.java index 6d3d510d..267dbc24 100644 --- a/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured3/operation/preprocess/UriModifyingOperationPreprocessor.java +++ b/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured3/operation/preprocess/UriModifyingOperationPreprocessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2017 the original author or authors. + * Copyright 2014-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,28 +16,10 @@ package org.springframework.restdocs.restassured3.operation.preprocess; -import java.net.URI; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map.Entry; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; import org.springframework.restdocs.operation.OperationRequest; -import org.springframework.restdocs.operation.OperationRequestFactory; import org.springframework.restdocs.operation.OperationRequestPart; -import org.springframework.restdocs.operation.OperationRequestPartFactory; import org.springframework.restdocs.operation.OperationResponse; -import org.springframework.restdocs.operation.OperationResponseFactory; -import org.springframework.restdocs.operation.preprocess.ContentModifier; -import org.springframework.restdocs.operation.preprocess.ContentModifyingOperationPreprocessor; import org.springframework.restdocs.operation.preprocess.OperationPreprocessor; -import org.springframework.util.StringUtils; -import org.springframework.web.util.UriComponentsBuilder; /** * An {@link OperationPreprocessor} that modifies URIs in the request and in the response @@ -55,201 +37,11 @@ import org.springframework.web.util.UriComponentsBuilder; * * @author Andy Wilkinson * @since 1.2.0 + * @deprecated since 2.0.1 in favor of + * {@link org.springframework.restdocs.operation.preprocess.UriModifyingOperationPreprocessor} */ -public final class UriModifyingOperationPreprocessor implements OperationPreprocessor { - - private final UriModifyingContentModifier contentModifier = new UriModifyingContentModifier(); - - private final OperationPreprocessor contentModifyingDelegate = new ContentModifyingOperationPreprocessor( - this.contentModifier); - - private String scheme; - - private String host; - - private String port; - - /** - * Modifies the URI to use the given {@code scheme}. {@code null}, the default, will - * leave the scheme unchanged. - * - * @param scheme the scheme - * @return {@code this} - */ - public UriModifyingOperationPreprocessor scheme(String scheme) { - this.scheme = scheme; - this.contentModifier.setScheme(scheme); - return this; - } - - /** - * Modifies the URI to use the given {@code host}. {@code null}, the default, will - * leave the host unchanged. - * - * @param host the host - * @return {@code this} - */ - public UriModifyingOperationPreprocessor host(String host) { - this.host = host; - this.contentModifier.setHost(host); - return this; - } - - /** - * Modifies the URI to use the given {@code port}. - * - * @param port the port - * @return {@code this} - */ - public UriModifyingOperationPreprocessor port(int port) { - return port(Integer.toString(port)); - } - - /** - * Removes the port from the URI. - * - * @return {@code this} - */ - public UriModifyingOperationPreprocessor removePort() { - return port(""); - } - - private UriModifyingOperationPreprocessor port(String port) { - this.port = port; - this.contentModifier.setPort(port); - return this; - } - - @Override - public OperationRequest preprocess(OperationRequest request) { - UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUri(request.getUri()); - if (this.scheme != null) { - uriBuilder.scheme(this.scheme); - } - if (this.host != null) { - uriBuilder.host(this.host); - } - if (this.port != null) { - if (StringUtils.hasText(this.port)) { - uriBuilder.port(this.port); - } - else { - uriBuilder.port(null); - } - } - URI modifiedUri = uriBuilder.build(true).toUri(); - HttpHeaders modifiedHeaders = modify(request.getHeaders()); - modifiedHeaders.set(HttpHeaders.HOST, modifiedUri.getHost() - + (modifiedUri.getPort() == -1 ? "" : ":" + modifiedUri.getPort())); - return this.contentModifyingDelegate.preprocess( - new OperationRequestFactory().create(uriBuilder.build(true).toUri(), - request.getMethod(), request.getContent(), modifiedHeaders, - request.getParameters(), modify(request.getParts()))); - } - - @Override - public OperationResponse preprocess(OperationResponse response) { - return this.contentModifyingDelegate - .preprocess(new OperationResponseFactory().create(response.getStatus(), - modify(response.getHeaders()), response.getContent())); - } - - private HttpHeaders modify(HttpHeaders headers) { - HttpHeaders modified = new HttpHeaders(); - for (Entry> header : headers.entrySet()) { - for (String value : header.getValue()) { - modified.add(header.getKey(), this.contentModifier.modify(value)); - } - } - return modified; - } - - private Collection modify( - Collection parts) { - List modifiedParts = new ArrayList<>(); - OperationRequestPartFactory factory = new OperationRequestPartFactory(); - for (OperationRequestPart part : parts) { - modifiedParts.add(factory.create(part.getName(), part.getSubmittedFileName(), - this.contentModifier.modifyContent(part.getContent(), - part.getHeaders().getContentType()), - modify(part.getHeaders()))); - } - return modifiedParts; - } - - private static final class UriModifyingContentModifier implements ContentModifier { - - private static final Pattern SCHEME_HOST_PORT_PATTERN = Pattern - .compile("(http[s]?)://([^/:#?]+)(:[0-9]+)?"); - - private String scheme; - - private String host; - - private String port; - - private void setScheme(String scheme) { - this.scheme = scheme; - } - - private void setHost(String host) { - this.host = host; - } - - private void setPort(String port) { - this.port = port; - } - - @Override - public byte[] modifyContent(byte[] content, MediaType contentType) { - String input; - if (contentType != null && contentType.getCharset() != null) { - input = new String(content, contentType.getCharset()); - } - else { - input = new String(content); - } - - return modify(input).getBytes(); - } - - private String modify(String input) { - List replacements = Arrays.asList(this.scheme, this.host, - StringUtils.hasText(this.port) ? ":" + this.port : this.port); - - int previous = 0; - - Matcher matcher = SCHEME_HOST_PORT_PATTERN.matcher(input); - StringBuilder builder = new StringBuilder(); - while (matcher.find()) { - for (int i = 1; i <= matcher.groupCount(); i++) { - if (matcher.start(i) >= 0) { - builder.append(input.substring(previous, matcher.start(i))); - } - if (matcher.start(i) >= 0) { - previous = matcher.end(i); - } - builder.append( - getReplacement(matcher.group(i), replacements.get(i - 1))); - } - } - - if (previous < input.length()) { - builder.append(input.substring(previous)); - } - return builder.toString(); - } - - private String getReplacement(String original, String candidate) { - if (candidate != null) { - return candidate; - } - if (original != null) { - return original; - } - return ""; - } - - } +@Deprecated +public class UriModifyingOperationPreprocessor extends + org.springframework.restdocs.operation.preprocess.UriModifyingOperationPreprocessor { } diff --git a/spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured3/RestAssuredRestDocumentationIntegrationTests.java b/spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured3/RestAssuredRestDocumentationIntegrationTests.java index fde03e74..57ff2a10 100644 --- a/spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured3/RestAssuredRestDocumentationIntegrationTests.java +++ b/spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured3/RestAssuredRestDocumentationIntegrationTests.java @@ -43,6 +43,7 @@ import static org.springframework.restdocs.headers.HeaderDocumentation.responseH import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel; import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links; import static org.springframework.restdocs.operation.preprocess.Preprocessors.maskLinks; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.modifyUris; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; @@ -59,7 +60,6 @@ import static org.springframework.restdocs.request.RequestDocumentation.requestP import static org.springframework.restdocs.request.RequestDocumentation.requestParts; import static org.springframework.restdocs.restassured3.RestAssuredRestDocumentation.document; import static org.springframework.restdocs.restassured3.RestAssuredRestDocumentation.documentationConfiguration; -import static org.springframework.restdocs.restassured3.operation.preprocess.RestAssuredPreprocessors.modifyUris; import static org.springframework.restdocs.templates.TemplateFormats.asciidoctor; import static org.springframework.restdocs.test.SnippetMatchers.codeBlock; import static org.springframework.restdocs.test.SnippetMatchers.httpRequest; diff --git a/spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured3/operation/preprocess/UriModifyingOperationPreprocessorTests.java b/spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured3/operation/preprocess/UriModifyingOperationPreprocessorTests.java index 7f262e9f..fb34f816 100644 --- a/spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured3/operation/preprocess/UriModifyingOperationPreprocessorTests.java +++ b/spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured3/operation/preprocess/UriModifyingOperationPreprocessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2016 the original author or authors. + * Copyright 2014-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,6 +42,7 @@ import static org.junit.Assert.assertThat; * * @author Andy Wilkinson */ +@Deprecated public class UriModifyingOperationPreprocessorTests { private final OperationRequestFactory requestFactory = new OperationRequestFactory();