@Override protected void extendTypedWriters(List<HttpMessageWriter<?>> typedWriters) { FormHttpMessageWriter formWriter = new FormHttpMessageWriter(); formWriter.setEnableLoggingRequestDetails(isEnableLoggingRequestDetails()); MultipartHttpMessageWriter multipartWriter = new MultipartHttpMessageWriter(getPartWriters(), formWriter); multipartWriter.setEnableLoggingRequestDetails(isEnableLoggingRequestDetails()); typedWriters.add(multipartWriter); }
private Flux<DataBuffer> encodePartValues(byte[] boundary, String name, List<?> values) { return Flux.concat(values.stream().map(v -> encodePart(boundary, name, v)).collect(Collectors.toList())); }
private Mono<Void> writeMultipart( MultiValueMap<String, ?> map, ReactiveHttpOutputMessage outputMessage, Map<String, Object> hints) { byte[] boundary = generateMultipartBoundary(); Map<String, String> params = new HashMap<>(2); params.put("boundary", new String(boundary, StandardCharsets.US_ASCII)); params.put("charset", getCharset().name()); outputMessage.getHeaders().setContentType(new MediaType(MediaType.MULTIPART_FORM_DATA, params)); LogFormatUtils.traceDebug(logger, traceOn -> Hints.getLogPrefix(hints) + "Encoding " + (isEnableLoggingRequestDetails() ? LogFormatUtils.formatValue(map, !traceOn) : "parts " + map.keySet() + " (content masked)")); Flux<DataBuffer> body = Flux.fromIterable(map.entrySet()) .concatMap(entry -> encodePartValues(boundary, entry.getKey(), entry.getValue())) .concatWith(Mono.just(generateLastLine(boundary))); return outputMessage.writeWith(body); }
@SuppressWarnings("unchecked") private <T> Flux<DataBuffer> encodePart(byte[] boundary, String name, T value) { MultipartHttpOutputMessage outputMessage = new MultipartHttpOutputMessage(this.bufferFactory, getCharset()); HttpHeaders outputHeaders = outputMessage.getHeaders(); return Flux.concat(Mono.just(generateBoundaryLine(boundary)), partContent, Mono.just(generateNewLine()));
@Before public void createContext() { final List<HttpMessageWriter<?>> messageWriters = new ArrayList<>(); messageWriters.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder())); messageWriters.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.textPlainOnly())); messageWriters.add(new ResourceHttpMessageWriter()); messageWriters.add(new EncoderHttpMessageWriter<>(new Jaxb2XmlEncoder())); Jackson2JsonEncoder jsonEncoder = new Jackson2JsonEncoder(); messageWriters.add(new EncoderHttpMessageWriter<>(jsonEncoder)); messageWriters.add(new ServerSentEventHttpMessageWriter(jsonEncoder)); messageWriters.add(new FormHttpMessageWriter()); messageWriters.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.allMimeTypes())); messageWriters.add(new MultipartHttpMessageWriter(messageWriters)); this.context = new BodyInserter.Context() { @Override public List<HttpMessageWriter<?>> messageWriters() { return messageWriters; } @Override public Optional<ServerHttpRequest> serverRequest() { return Optional.empty(); } @Override public Map<String, Object> hints() { return hints; } }; this.hints = new HashMap<>(); }
private ServerWebExchange exchangeMultipart(MultiValueMap<String, ?> multipartData) { MockClientHttpRequest request = new MockClientHttpRequest(HttpMethod.POST, "/"); new MultipartHttpMessageWriter().write(Mono.just(multipartData), forClass(MultiValueMap.class), MediaType.MULTIPART_FORM_DATA, request, Collections.emptyMap()).block(); return MockServerWebExchange.from(MockServerHttpRequest .post("/") .contentType(request.getHeaders().getContentType()) .body(request.getBody())); }
private Mono<Void> writeMultipart(MultiValueMap<String, ?> map, ReactiveHttpOutputMessage outputMessage) { byte[] boundary = generateMultipartBoundary(); Map<String, String> params = new HashMap<>(2); params.put("boundary", new String(boundary, StandardCharsets.US_ASCII)); params.put("charset", getCharset().name()); outputMessage.getHeaders().setContentType(new MediaType(MediaType.MULTIPART_FORM_DATA, params)); Flux<DataBuffer> body = Flux.fromIterable(map.entrySet()) .concatMap(entry -> encodePartValues(boundary, entry.getKey(), entry.getValue())) .concatWith(Mono.just(generateLastLine(boundary))); return outputMessage.writeWith(body); }
return Flux.concat(Mono.just(generateBoundaryLine(boundary)), partContent, Mono.just(generateNewLine()));
/** * Constructor with explicit list of writers for serializing parts and a * writer for plain form data to fall back when no media type is specified * and the actual map consists of String values only. * @param partWriters the writers for serializing parts * @param formWriter the fallback writer for form data, {@code null} by default */ public MultipartHttpMessageWriter(List<HttpMessageWriter<?>> partWriters, @Nullable HttpMessageWriter<MultiValueMap<String, String>> formWriter) { this.partWriters = partWriters; this.formWriter = formWriter; this.supportedMediaTypes = initMediaTypes(formWriter); }
@Before public void setup() throws Exception { List<HttpMessageReader<?>> readers = ServerCodecConfigurer.create().getReaders(); ReactiveAdapterRegistry registry = ReactiveAdapterRegistry.getSharedInstance(); this.resolver = new RequestPartMethodArgumentResolver(readers, registry); List<HttpMessageWriter<?>> writers = ClientCodecConfigurer.create().getWriters(); this.writer = new MultipartHttpMessageWriter(writers); }
@SuppressWarnings("unchecked") private <T> Flux<DataBuffer> encodePart(byte[] boundary, String name, T value) { MultipartHttpOutputMessage outputMessage = new MultipartHttpOutputMessage(this.bufferFactory, getCharset()); HttpHeaders outputHeaders = outputMessage.getHeaders(); return Flux.concat(Mono.just(generateBoundaryLine(boundary)), partContent, Mono.just(generateNewLine()));
private ServerHttpRequest generateMultipartRequest() { MultipartBodyBuilder partsBuilder = new MultipartBodyBuilder(); partsBuilder.part("fooPart", new ClassPathResource("org/springframework/http/codec/multipart/foo.txt")); partsBuilder.part("barPart", "bar"); MockClientHttpRequest outputMessage = new MockClientHttpRequest(HttpMethod.POST, "/"); new MultipartHttpMessageWriter() .write(Mono.just(partsBuilder.build()), null, MediaType.MULTIPART_FORM_DATA, outputMessage, null) .block(Duration.ofSeconds(5)); return MockServerHttpRequest.post("/") .contentType(outputMessage.getHeaders().getContentType()) .body(outputMessage.getBody()); }
/** * Constructor with explicit list of writers for serializing parts and a * writer for plain form data to fall back when no media type is specified * and the actual map consists of String values only. * @param partWriters the writers for serializing parts * @param formWriter the fallback writer for form data, {@code null} by default */ public MultipartHttpMessageWriter(List<HttpMessageWriter<?>> partWriters, @Nullable HttpMessageWriter<MultiValueMap<String, String>> formWriter) { this.partWriters = partWriters; this.formWriter = formWriter; this.supportedMediaTypes = initMediaTypes(formWriter); }
private Mono<Void> writeMultipart( MultiValueMap<String, ?> map, ReactiveHttpOutputMessage outputMessage, Map<String, Object> hints) { byte[] boundary = generateMultipartBoundary(); Map<String, String> params = new HashMap<>(2); params.put("boundary", new String(boundary, StandardCharsets.US_ASCII)); params.put("charset", getCharset().name()); outputMessage.getHeaders().setContentType(new MediaType(MediaType.MULTIPART_FORM_DATA, params)); LogFormatUtils.traceDebug(logger, traceOn -> Hints.getLogPrefix(hints) + "Encoding " + (isEnableLoggingRequestDetails() ? LogFormatUtils.formatValue(map, !traceOn) : "parts " + map.keySet() + " (content masked)")); Flux<DataBuffer> body = Flux.fromIterable(map.entrySet()) .concatMap(entry -> encodePartValues(boundary, entry.getKey(), entry.getValue())) .concatWith(Mono.just(generateLastLine(boundary))); return outputMessage.writeWith(body); }
@Override protected void extendTypedWriters(List<HttpMessageWriter<?>> typedWriters) { FormHttpMessageWriter formWriter = new FormHttpMessageWriter(); formWriter.setEnableLoggingRequestDetails(isEnableLoggingRequestDetails()); MultipartHttpMessageWriter multipartWriter = new MultipartHttpMessageWriter(getPartWriters(), formWriter); multipartWriter.setEnableLoggingRequestDetails(isEnableLoggingRequestDetails()); typedWriters.add(multipartWriter); }
private static String getBody(ClientRequest request) { final List<HttpMessageWriter<?>> messageWriters = new ArrayList<>(); messageWriters.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder())); messageWriters.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.textPlainOnly())); messageWriters.add(new ResourceHttpMessageWriter()); Jackson2JsonEncoder jsonEncoder = new Jackson2JsonEncoder(); messageWriters.add(new EncoderHttpMessageWriter<>(jsonEncoder)); messageWriters.add(new ServerSentEventHttpMessageWriter(jsonEncoder)); messageWriters.add(new FormHttpMessageWriter()); messageWriters.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.allMimeTypes())); messageWriters.add(new MultipartHttpMessageWriter(messageWriters)); BodyInserter.Context context = new BodyInserter.Context() { @Override public List<HttpMessageWriter<?>> messageWriters() { return messageWriters; } @Override public Optional<ServerHttpRequest> serverRequest() { return Optional.empty(); } @Override public Map<String, Object> hints() { return new HashMap<>(); } }; MockClientHttpRequest body = new MockClientHttpRequest(HttpMethod.GET, "/"); request.body().insert(body, context).block(); return body.getBodyAsString().block(); }
@SuppressWarnings("unchecked") private <T> Flux<DataBuffer> encodePart(byte[] boundary, String name, T value) { MultipartHttpOutputMessage outputMessage = new MultipartHttpOutputMessage(this.bufferFactory, getCharset()); HttpHeaders outputHeaders = outputMessage.getHeaders(); return Flux.concat(Mono.just(generateBoundaryLine(boundary)), partContent, Mono.just(generateNewLine()));
/** * Constructor with explicit list of writers for serializing parts and a * writer for plain form data to fall back when no media type is specified * and the actual map consists of String values only. * @param partWriters the writers for serializing parts * @param formWriter the fallback writer for form data, {@code null} by default */ public MultipartHttpMessageWriter(List<HttpMessageWriter<?>> partWriters, @Nullable HttpMessageWriter<MultiValueMap<String, String>> formWriter) { this.partWriters = partWriters; this.formWriter = formWriter; this.supportedMediaTypes = initMediaTypes(formWriter); }
private Flux<DataBuffer> encodePartValues(byte[] boundary, String name, List<?> values) { return Flux.concat(values.stream().map(v -> encodePart(boundary, name, v)).collect(Collectors.toList())); }
private Mono<Void> writeMultipart( MultiValueMap<String, ?> map, ReactiveHttpOutputMessage outputMessage, Map<String, Object> hints) { byte[] boundary = generateMultipartBoundary(); Map<String, String> params = new HashMap<>(2); params.put("boundary", new String(boundary, StandardCharsets.US_ASCII)); params.put("charset", getCharset().name()); outputMessage.getHeaders().setContentType(new MediaType(MediaType.MULTIPART_FORM_DATA, params)); LogFormatUtils.traceDebug(logger, traceOn -> Hints.getLogPrefix(hints) + "Encoding " + (isEnableLoggingRequestDetails() ? LogFormatUtils.formatValue(map, !traceOn) : "parts " + map.keySet() + " (content masked)")); Flux<DataBuffer> body = Flux.fromIterable(map.entrySet()) .concatMap(entry -> encodePartValues(boundary, entry.getKey(), entry.getValue())) .concatWith(Mono.just(generateLastLine(boundary))); return outputMessage.writeWith(body); }