Merge branch '6.0.x'
This commit is contained in:
commit
f4ef057e9e
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
|
|
@ -141,6 +141,13 @@ public interface ServerWebExchange {
|
|||
*/
|
||||
Mono<MultiValueMap<String, Part>> getMultipartData();
|
||||
|
||||
/**
|
||||
* Cleans up any storage used for multipart handling.
|
||||
* @since 6.0.10
|
||||
* @see Part#delete()
|
||||
*/
|
||||
Mono<Void> cleanupMultipart();
|
||||
|
||||
/**
|
||||
* Return the {@link LocaleContext} using the configured
|
||||
* {@link org.springframework.web.server.i18n.LocaleContextResolver}.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
|
|
@ -108,6 +108,11 @@ public class ServerWebExchangeDecorator implements ServerWebExchange {
|
|||
return getDelegate().getMultipartData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> cleanupMultipart() {
|
||||
return getDelegate().cleanupMultipart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNotModified() {
|
||||
return getDelegate().isNotModified();
|
||||
|
|
|
|||
|
|
@ -93,6 +93,8 @@ public class DefaultServerWebExchange implements ServerWebExchange {
|
|||
|
||||
private final Mono<MultiValueMap<String, Part>> multipartDataMono;
|
||||
|
||||
private volatile boolean multipartRead = false;
|
||||
|
||||
@Nullable
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
|
|
@ -131,7 +133,7 @@ public class DefaultServerWebExchange implements ServerWebExchange {
|
|||
this.sessionMono = sessionManager.getSession(this).cache();
|
||||
this.localeContextResolver = localeContextResolver;
|
||||
this.formDataMono = initFormData(request, codecConfigurer, getLogPrefix());
|
||||
this.multipartDataMono = initMultipartData(request, codecConfigurer, getLogPrefix());
|
||||
this.multipartDataMono = initMultipartData(codecConfigurer, getLogPrefix());
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
|
|
@ -154,10 +156,9 @@ public class DefaultServerWebExchange implements ServerWebExchange {
|
|||
.cache();
|
||||
}
|
||||
|
||||
private static Mono<MultiValueMap<String, Part>> initMultipartData(ServerHttpRequest request,
|
||||
ServerCodecConfigurer configurer, String logPrefix) {
|
||||
private Mono<MultiValueMap<String, Part>> initMultipartData(ServerCodecConfigurer configurer, String logPrefix) {
|
||||
|
||||
MediaType contentType = getContentType(request);
|
||||
MediaType contentType = getContentType(this.request);
|
||||
if (contentType == null || !contentType.getType().equalsIgnoreCase("multipart")) {
|
||||
return EMPTY_MULTIPART_DATA;
|
||||
}
|
||||
|
|
@ -168,7 +169,8 @@ public class DefaultServerWebExchange implements ServerWebExchange {
|
|||
}
|
||||
|
||||
return reader
|
||||
.readMono(MULTIPART_DATA_TYPE, request, Hints.from(Hints.LOG_PREFIX_HINT, logPrefix))
|
||||
.readMono(MULTIPART_DATA_TYPE, this.request, Hints.from(Hints.LOG_PREFIX_HINT, logPrefix))
|
||||
.doOnNext(ignored -> this.multipartRead = true)
|
||||
.switchIfEmpty(EMPTY_MULTIPART_DATA)
|
||||
.cache();
|
||||
}
|
||||
|
|
@ -243,6 +245,22 @@ public class DefaultServerWebExchange implements ServerWebExchange {
|
|||
return this.multipartDataMono;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> cleanupMultipart() {
|
||||
if (this.multipartRead) {
|
||||
return getMultipartData()
|
||||
.onErrorResume(t -> Mono.empty()) // ignore errors reading multipart data
|
||||
.flatMapIterable(Map::values)
|
||||
.flatMapIterable(Function.identity())
|
||||
.flatMap(part -> part.delete()
|
||||
.onErrorResume(ex -> Mono.empty()))
|
||||
.then();
|
||||
}
|
||||
else {
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocaleContext getLocaleContext() {
|
||||
return this.localeContextResolver.resolveLocaleContext(this);
|
||||
|
|
|
|||
|
|
@ -16,9 +16,7 @@
|
|||
|
||||
package org.springframework.web.server.adapter;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
|
|
@ -36,7 +34,6 @@ import org.springframework.http.HttpStatus;
|
|||
import org.springframework.http.HttpStatusCode;
|
||||
import org.springframework.http.codec.LoggingCodecSupport;
|
||||
import org.springframework.http.codec.ServerCodecConfigurer;
|
||||
import org.springframework.http.codec.multipart.Part;
|
||||
import org.springframework.http.server.reactive.HttpHandler;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
|
|
@ -305,7 +302,7 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
|
|||
|
||||
return getDelegate().handle(exchange)
|
||||
.transformDeferred(call -> transform(exchange, observationContext, call))
|
||||
.then(cleanupMultipart(exchange))
|
||||
.then(exchange.cleanupMultipart())
|
||||
.then(Mono.defer(response::setComplete));
|
||||
}
|
||||
|
||||
|
|
@ -417,22 +414,4 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
|
|||
return DISCONNECTED_CLIENT_EXCEPTIONS.contains(ex.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
private Mono<Void> cleanupMultipart(ServerWebExchange exchange) {
|
||||
return exchange.getMultipartData()
|
||||
.onErrorResume(t -> Mono.empty()) // ignore errors reading multipart data
|
||||
.flatMapIterable(Map::values)
|
||||
.flatMapIterable(Function.identity())
|
||||
.flatMap(this::deletePart)
|
||||
.then();
|
||||
}
|
||||
|
||||
private Mono<Void> deletePart(Part part) {
|
||||
return part.delete().onErrorResume(ex -> {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Failed to perform cleanup of multipart items", ex);
|
||||
}
|
||||
return Mono.empty();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -324,28 +324,30 @@ class DefaultServerRequestBuilder implements ServerRequest.Builder {
|
|||
|
||||
private final Mono<MultiValueMap<String, Part>> multipartDataMono;
|
||||
|
||||
private volatile boolean multipartRead = false;
|
||||
|
||||
|
||||
DelegatingServerWebExchange(ServerHttpRequest request, Map<String, Object> attributes,
|
||||
ServerWebExchange delegate, List<HttpMessageReader<?>> messageReaders) {
|
||||
|
||||
this.request = request;
|
||||
this.attributes = attributes;
|
||||
this.delegate = delegate;
|
||||
this.formDataMono = initFormData(request, messageReaders);
|
||||
this.formDataMono = initFormData(messageReaders);
|
||||
this.multipartDataMono = initMultipartData(request, messageReaders);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Mono<MultiValueMap<String, String>> initFormData(ServerHttpRequest request,
|
||||
List<HttpMessageReader<?>> readers) {
|
||||
|
||||
private Mono<MultiValueMap<String, String>> initFormData(List<HttpMessageReader<?>> readers) {
|
||||
try {
|
||||
MediaType contentType = request.getHeaders().getContentType();
|
||||
MediaType contentType = this.request.getHeaders().getContentType();
|
||||
if (MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType)) {
|
||||
return ((HttpMessageReader<MultiValueMap<String, String>>) readers.stream()
|
||||
.filter(reader -> reader.canRead(FORM_DATA_TYPE, MediaType.APPLICATION_FORM_URLENCODED))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("No form data HttpMessageReader.")))
|
||||
.readMono(FORM_DATA_TYPE, request, Hints.none())
|
||||
.readMono(FORM_DATA_TYPE, this.request, Hints.none())
|
||||
.doOnNext(ignored -> this.multipartRead = true)
|
||||
.switchIfEmpty(EMPTY_FORM_DATA)
|
||||
.cache();
|
||||
}
|
||||
|
|
@ -398,6 +400,22 @@ class DefaultServerRequestBuilder implements ServerRequest.Builder {
|
|||
return this.multipartDataMono;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> cleanupMultipart() {
|
||||
if (this.multipartRead) {
|
||||
return getMultipartData()
|
||||
.onErrorResume(t -> Mono.empty()) // ignore errors reading multipart data
|
||||
.flatMapIterable(Map::values)
|
||||
.flatMapIterable(Function.identity())
|
||||
.flatMap(part -> part.delete()
|
||||
.onErrorResume(ex -> Mono.empty()))
|
||||
.then();
|
||||
}
|
||||
else {
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
||||
|
||||
// Delegating methods
|
||||
|
||||
@Override
|
||||
|
|
|
|||
Loading…
Reference in New Issue