Skip to content

Commit 4721a92

Browse files
qnnnspencergibb
authored andcommitted
Fix potential memory leak when using ReadBodyRoutePredicateFactory
Fixes gh-3465
1 parent a8dc086 commit 4721a92

File tree

3 files changed

+26
-22
lines changed

3 files changed

+26
-22
lines changed

spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/RemoveCachedBodyFilter.java

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,37 +16,17 @@
1616

1717
package org.springframework.cloud.gateway.filter;
1818

19-
import org.apache.commons.logging.Log;
20-
import org.apache.commons.logging.LogFactory;
2119
import reactor.core.publisher.Mono;
2220

21+
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
2322
import org.springframework.core.Ordered;
24-
import org.springframework.core.io.buffer.PooledDataBuffer;
2523
import org.springframework.web.server.ServerWebExchange;
2624

27-
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR;
28-
2925
public class RemoveCachedBodyFilter implements GlobalFilter, Ordered {
3026

31-
private static final Log log = LogFactory.getLog(RemoveCachedBodyFilter.class);
32-
3327
@Override
3428
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
35-
return chain.filter(exchange).doFinally(s -> {
36-
Object attribute = exchange.getAttributes().remove(CACHED_REQUEST_BODY_ATTR);
37-
if (attribute != null && attribute instanceof PooledDataBuffer) {
38-
PooledDataBuffer dataBuffer = (PooledDataBuffer) attribute;
39-
if (dataBuffer.isAllocated()) {
40-
if (log.isTraceEnabled()) {
41-
log.trace("releasing cached body in exchange attribute");
42-
}
43-
// ensure proper release
44-
while (!dataBuffer.release()) {
45-
// release() counts down until zero, will never be infinite loop
46-
}
47-
}
48-
}
49-
});
29+
return chain.filter(exchange).doFinally(s -> ServerWebExchangeUtils.clearCachedRequestBody(exchange));
5030
}
5131

5232
@Override

spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/RoutePredicateHandlerMapping.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.springframework.cloud.gateway.config.GlobalCorsProperties;
2525
import org.springframework.cloud.gateway.route.Route;
2626
import org.springframework.cloud.gateway.route.RouteLocator;
27+
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
2728
import org.springframework.core.env.Environment;
2829
import org.springframework.web.cors.CorsConfiguration;
2930
import org.springframework.web.reactive.handler.AbstractHandlerMapping;
@@ -99,6 +100,7 @@ protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
99100
})
100101
.switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
101102
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
103+
ServerWebExchangeUtils.clearCachedRequestBody(exchange);
102104
if (logger.isTraceEnabled()) {
103105
logger.trace("No RouteDefinition found for [" + getExchangeDesc(exchange) + "]");
104106
}

spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtils.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.springframework.core.io.buffer.DataBufferUtils;
4141
import org.springframework.core.io.buffer.DefaultDataBuffer;
4242
import org.springframework.core.io.buffer.NettyDataBuffer;
43+
import org.springframework.core.io.buffer.PooledDataBuffer;
4344
import org.springframework.http.HttpStatus;
4445
import org.springframework.http.server.reactive.AbstractServerHttpResponse;
4546
import org.springframework.http.server.reactive.ServerHttpRequest;
@@ -379,6 +380,27 @@ private static <T> Mono<T> cacheRequestBody(ServerWebExchange exchange, boolean
379380
.flatMap(function);
380381
}
381382

383+
/**
384+
* clear the request body in a ServerWebExchange attribute. The attribute is
385+
* {@link #CACHED_REQUEST_BODY_ATTR}.
386+
* @param exchange the available ServerWebExchange.
387+
*/
388+
public static void clearCachedRequestBody(ServerWebExchange exchange) {
389+
Object attribute = exchange.getAttributes().remove(CACHED_REQUEST_BODY_ATTR);
390+
if (attribute != null && attribute instanceof PooledDataBuffer) {
391+
PooledDataBuffer dataBuffer = (PooledDataBuffer) attribute;
392+
if (dataBuffer.isAllocated()) {
393+
if (log.isTraceEnabled()) {
394+
log.trace("releasing cached body in exchange attribute");
395+
}
396+
// ensure proper release
397+
while (!dataBuffer.release()) {
398+
// release() counts down until zero, will never be infinite loop
399+
}
400+
}
401+
}
402+
}
403+
382404
private static ServerHttpRequest decorate(ServerWebExchange exchange, DataBuffer dataBuffer,
383405
boolean cacheDecoratedRequest) {
384406
if (dataBuffer.readableByteCount() > 0) {

0 commit comments

Comments
 (0)