Skip to content
This repository has been archived by the owner on Dec 19, 2023. It is now read-only.

Commit

Permalink
Replacement for binary content of multipart requests (#369)
Browse files Browse the repository at this point in the history
* feat: added MultipartContentOperationPreprocessor for replacing binary content of multipart/form-data requests

* docs: add MultipartContentOperationPreprocessor to docs
  • Loading branch information
MikeSafonov authored and fbenz committed Jan 27, 2020
1 parent 2559b34 commit 2a23c31
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package capital.scalable.restdocs.response;

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.preprocess.OperationPreprocessorAdapter;

import java.util.List;

import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.stream.Collectors.toList;

public class MultipartContentOperationPreprocessor extends OperationPreprocessorAdapter {
private static final byte[] BINARY_REPLACEMENT = "<binary>".getBytes(UTF_8);

private final OperationRequestPartFactory partFactory = new OperationRequestPartFactory();
private final OperationRequestFactory requestFactory = new OperationRequestFactory();

@Override
public OperationRequest preprocess(OperationRequest request) {
if (isMultipart(request)) {
List<OperationRequestPart> parts = request.getParts().stream()
.map(this::replaceBinary)
.collect(toList());
return requestFactory.create(request.getUri(),
request.getMethod(), request.getContent(), request.getHeaders(), request.getParameters()
, parts);
}
return request;
}

private boolean isMultipart(OperationRequest request) {
List<String> contentTypes = request.getHeaders().get(HttpHeaders.CONTENT_TYPE);
return contentTypes != null && contentTypes.contains(MediaType.MULTIPART_FORM_DATA_VALUE);
}

private OperationRequestPart replaceBinary(OperationRequestPart part) {
return partFactory.create(part.getName(), part.getSubmittedFileName()
, BINARY_REPLACEMENT, part.getHeaders());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,15 @@ public static OperationPreprocessor replaceBinaryContent() {
return new ContentModifyingOperationPreprocessor(new BinaryReplacementContentModifier());
}

/**
* For binary content of multipart/form-data requests, replaces value with "&lt;binary&gt;".
*
* @return a preprocessor replacing binary content of multipart/form-data requests
*/
public static OperationPreprocessor replaceMultipartBinaryContent() {
return new MultipartContentOperationPreprocessor();
}

/**
* For JSON content, cuts the length of all JSON arrays in the response to 3 elements.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package capital.scalable.restdocs.response;

import org.junit.Before;
import org.junit.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
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.Parameters;

import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;

public class MultipartContentOperationPreprocessorTest {
private static final byte[] EXPECTED_CONTENT = "<binary>".getBytes(StandardCharsets.UTF_8);
private static final byte[] BINARY_CONTENT = new byte[]{1, 2, 3, 3, 3};
private MultipartContentOperationPreprocessor preprocessor;
private OperationRequestFactory requestFactory;
private OperationRequestPartFactory partFactory;

@Before
public void setUp() {
preprocessor = new MultipartContentOperationPreprocessor();
requestFactory = new OperationRequestFactory();
partFactory = new OperationRequestPartFactory();
}

@Test
public void shouldReplaceContent() throws URISyntaxException {
OperationRequest request = createRequestWithContentType(MediaType.MULTIPART_FORM_DATA_VALUE);

OperationRequest processedRequest = preprocessor.preprocess(request);
assertArrayEquals(request.getContent(), processedRequest.getContent());
assertEquals(request.getHeaders(), processedRequest.getHeaders());
assertEquals(request.getMethod(), processedRequest.getMethod());
assertEquals(request.getUri(), processedRequest.getUri());
assertEquals(request.getParameters(), processedRequest.getParameters());
for (OperationRequestPart part : processedRequest.getParts()) {
assertArrayEquals(EXPECTED_CONTENT, part.getContent());
}
}

@Test
public void shouldNotReplaceWhenNotMultipart() throws URISyntaxException {
OperationRequest request = createRequestWithContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);

OperationRequest processedRequest = preprocessor.preprocess(request);
assertArrayEquals(request.getContent(), processedRequest.getContent());
assertEquals(request.getHeaders(), processedRequest.getHeaders());
assertEquals(request.getMethod(), processedRequest.getMethod());
assertEquals(request.getUri(), processedRequest.getUri());
assertEquals(request.getParameters(), processedRequest.getParameters());

OperationRequestPart[] expectedParts = request.getParts().toArray(new OperationRequestPart[0]);
OperationRequestPart[] operationRequestParts = processedRequest.getParts().toArray(new OperationRequestPart[0]);
for (int i = 0; i < operationRequestParts.length; i++) {
assertEquals(expectedParts[i], operationRequestParts[i]);
}
}

private OperationRequest createRequestWithContentType(String contentType) throws URISyntaxException {
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_TYPE, contentType);
Parameters parameters = new Parameters();
parameters.add("parameter", "value");
List<OperationRequestPart> requestParts = new ArrayList<>();
requestParts.add(partFactory.create("first", "file1", BINARY_CONTENT, new HttpHeaders()));
return requestFactory.create(new URI("http://localhost"), HttpMethod.POST, BINARY_CONTENT, headers, parameters, requestParts);
}
}
1 change: 1 addition & 0 deletions spring-auto-restdocs-docs/other.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ See example project for link:{example-dir}/src/main/asciidoc/index.adoc#overview
Preprocessors are available for use in order to improve quality of endpoint examples.

- link:{core-package}/response/BinaryReplacementContentModifier.java[binary replacement]: replaces content with `<binary>` for common mime types
- link:{core-package}/response/MultipartContentOperationPreprocessor.java[multipart binary replacement]: replaces content with `<binary>` for multipart/form-data requests
- link:{core-package}/response/ArrayLimitingJsonContentModifier.java[limit JSON array length]: limits all JSON arrays to 3 items

For a list of standard preprocessors see link:{restdocs-package}/operation/preprocess/Preprocessors.java[Preprocessors].
Expand Down

0 comments on commit 2a23c31

Please sign in to comment.