Merge branch '6.0.x'

This commit is contained in:
Arjen Poutsma
2023-06-08 14:42:24 +02:00
5 changed files with 63 additions and 36 deletions

View File

@@ -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}.

View File

@@ -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();

View File

@@ -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);

View File

@@ -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();
});
}
}