/*
* Copyright 2002-2017 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.http.codec.multipart;
import java.io.IOException;
import java.util.Map;
import org.junit.Test;
import reactor.core.publisher.Flux;
import reactor.test.StepVerifier;
import org.springframework.core.ResolvableType;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.MockHttpOutputMessage;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import static java.util.Collections.emptyMap;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.springframework.core.ResolvableType.forClassWithGenerics;
import static org.springframework.http.HttpHeaders.CONTENT_LENGTH;
import static org.springframework.http.HttpHeaders.CONTENT_TYPE;
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA;
/**
* @author Sebastien Deleuze
*/
public class SynchronossPartHttpMessageReaderTests {
private final MultipartHttpMessageReader reader =
new MultipartHttpMessageReader(new SynchronossPartHttpMessageReader());
@Test
public void canRead() {
assertTrue(this.reader.canRead(
forClassWithGenerics(MultiValueMap.class, String.class, Part.class),
MediaType.MULTIPART_FORM_DATA));
assertFalse(this.reader.canRead(
forClassWithGenerics(MultiValueMap.class, String.class, Object.class),
MediaType.MULTIPART_FORM_DATA));
assertFalse(this.reader.canRead(
forClassWithGenerics(MultiValueMap.class, String.class, String.class),
MediaType.MULTIPART_FORM_DATA));
assertFalse(this.reader.canRead(
forClassWithGenerics(Map.class, String.class, String.class),
MediaType.MULTIPART_FORM_DATA));
assertFalse(this.reader.canRead(
forClassWithGenerics(MultiValueMap.class, String.class, Part.class),
MediaType.APPLICATION_FORM_URLENCODED));
}
@Test
public void resolveParts() throws IOException {
ServerHttpRequest request = generateMultipartRequest();
ResolvableType elementType = forClassWithGenerics(MultiValueMap.class, String.class, Part.class);
MultiValueMap<String, Part> parts = this.reader.readMono(elementType, request, emptyMap()).block();
assertEquals(2, parts.size());
assertTrue(parts.containsKey("fooPart"));
Part part = parts.getFirst("fooPart");
assertTrue(part instanceof FilePart);
assertEquals("fooPart", part.name());
assertEquals("foo.txt", ((FilePart) part).filename());
DataBuffer buffer = part.content().reduce(DataBuffer::write).block();
assertEquals(12, buffer.readableByteCount());
byte[] byteContent = new byte[12];
buffer.read(byteContent);
assertEquals("Lorem Ipsum.", new String(byteContent));
assertTrue(parts.containsKey("barPart"));
part = parts.getFirst("barPart");
assertTrue(part instanceof FormFieldPart);
assertEquals("barPart", part.name());
assertEquals("bar", ((FormFieldPart) part).value());
}
@Test
public void bodyError() {
ServerHttpRequest request = generateErrorMultipartRequest();
ResolvableType elementType = forClassWithGenerics(MultiValueMap.class, String.class, Part.class);
StepVerifier.create(this.reader.readMono(elementType, request, emptyMap())).verifyError();
}
private ServerHttpRequest generateMultipartRequest() throws IOException {
HttpHeaders fooHeaders = new HttpHeaders();
fooHeaders.setContentType(MediaType.TEXT_PLAIN);
ClassPathResource fooResource = new ClassPathResource("org/springframework/http/codec/multipart/foo.txt");
HttpEntity<ClassPathResource> fooPart = new HttpEntity<>(fooResource, fooHeaders);
HttpEntity<String> barPart = new HttpEntity<>("bar");
FormHttpMessageConverter converter = new FormHttpMessageConverter();
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
parts.add("fooPart", fooPart);
parts.add("barPart", barPart);
converter.write(parts, MULTIPART_FORM_DATA, outputMessage);
byte[] content = outputMessage.getBodyAsBytes();
return MockServerHttpRequest
.post("/foo")
.header(CONTENT_TYPE, outputMessage.getHeaders().getContentType().toString())
.header(CONTENT_LENGTH, String.valueOf(content.length))
.body(new String(content));
}
private ServerHttpRequest generateErrorMultipartRequest() {
return MockServerHttpRequest
.post("/foo")
.header(CONTENT_TYPE, MULTIPART_FORM_DATA.toString())
.body(Flux.just(new DefaultDataBufferFactory().wrap("invalid content".getBytes())));
}
}