diff --git a/spring-web/src/main/java/org/springframework/http/codec/multipart/DefaultPartHttpMessageReader.java b/spring-web/src/main/java/org/springframework/http/codec/multipart/DefaultPartHttpMessageReader.java index 637adc1590..4e1bc3068b 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/multipart/DefaultPartHttpMessageReader.java +++ b/spring-web/src/main/java/org/springframework/http/codec/multipart/DefaultPartHttpMessageReader.java @@ -144,7 +144,7 @@ public class DefaultPartHttpMessageReader extends LoggingCodecSupport implements * changing it to an externally managed scheduler. *

Note that this property is ignored when * {@link #setMaxInMemorySize(int) maxInMemorySize} is set to -1. - * @see Schedulers#newBoundedElastic + * @see Schedulers#boundedElastic */ public void setBlockingOperationScheduler(Scheduler blockingOperationScheduler) { Assert.notNull(blockingOperationScheduler, "'blockingOperationScheduler' must not be null"); diff --git a/spring-web/src/main/java/org/springframework/web/server/session/CookieWebSessionIdResolver.java b/spring-web/src/main/java/org/springframework/web/server/session/CookieWebSessionIdResolver.java index 1bb7e4fa6d..df661f2e93 100644 --- a/spring-web/src/main/java/org/springframework/web/server/session/CookieWebSessionIdResolver.java +++ b/spring-web/src/main/java/org/springframework/web/server/session/CookieWebSessionIdResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 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. @@ -42,11 +42,11 @@ public class CookieWebSessionIdResolver implements WebSessionIdResolver { private Duration cookieMaxAge = Duration.ofSeconds(-1); @Nullable - private Consumer cookieInitializer = null; + private Consumer initializer = null; /** - * Set the name of the cookie to use for the session ID. + * Set the name for the session id cookie. *

By default set to "SESSION". * @param cookieName the cookie name */ @@ -63,32 +63,32 @@ public class CookieWebSessionIdResolver implements WebSessionIdResolver { } /** - * Set the value for the "Max-Age" attribute of the cookie that holds the - * session ID. - *

For the range of values see {@link ResponseCookie#getMaxAge()}. - *

By default set to -1. + * Set the "Max-Age" attribute for the session id cookie. + *

By default set to -1 in which case the cookie is removed when the + * browser is closed. * @param maxAge the maxAge duration value + * @see ResponseCookie#getMaxAge() */ public void setCookieMaxAge(Duration maxAge) { this.cookieMaxAge = maxAge; } /** - * Get the configured "Max-Age" attribute value for the session cookie. + * Get the configured "Max-Age" for the session id cookie. */ public Duration getCookieMaxAge() { return this.cookieMaxAge; } /** - * Add a {@link Consumer} for a {@code ResponseCookieBuilder} that will be invoked - * for each cookie being built, just before the call to {@code build()}. - * @param initializer consumer for a cookie builder + * Add a {@link Consumer} to further initialize the session id cookie + * after {@link #getCookieName()} and {@link #getCookieMaxAge()} are applied. + * @param initializer consumer to initialize the cookie with * @since 5.1 */ public void addCookieInitializer(Consumer initializer) { - this.cookieInitializer = this.cookieInitializer != null ? - this.cookieInitializer.andThen(initializer) : initializer; + this.initializer = this.initializer != null ? + this.initializer.andThen(initializer) : initializer; } @@ -105,31 +105,29 @@ public class CookieWebSessionIdResolver implements WebSessionIdResolver { @Override public void setSessionId(ServerWebExchange exchange, String id) { Assert.notNull(id, "'id' is required"); - ResponseCookie cookie = initSessionCookie(exchange, id, getCookieMaxAge()); + ResponseCookie cookie = initCookie(exchange, id).build(); exchange.getResponse().getCookies().set(this.cookieName, cookie); } @Override public void expireSession(ServerWebExchange exchange) { - ResponseCookie cookie = initSessionCookie(exchange, "", Duration.ZERO); + ResponseCookie cookie = initCookie(exchange, "").maxAge(0).build(); exchange.getResponse().getCookies().set(this.cookieName, cookie); } - private ResponseCookie initSessionCookie( - ServerWebExchange exchange, String id, Duration maxAge) { - - ResponseCookie.ResponseCookieBuilder cookieBuilder = ResponseCookie.from(this.cookieName, id) + private ResponseCookie.ResponseCookieBuilder initCookie(ServerWebExchange exchange, String id) { + ResponseCookie.ResponseCookieBuilder builder = ResponseCookie.from(this.cookieName, id) .path(exchange.getRequest().getPath().contextPath().value() + "/") - .maxAge(maxAge) + .maxAge(getCookieMaxAge()) .httpOnly(true) .secure("https".equalsIgnoreCase(exchange.getRequest().getURI().getScheme())) .sameSite("Lax"); - if (this.cookieInitializer != null) { - this.cookieInitializer.accept(cookieBuilder); + if (this.initializer != null) { + this.initializer.accept(builder); } - return cookieBuilder.build(); + return builder; } } diff --git a/spring-web/src/test/java/org/springframework/web/server/session/CookieWebSessionIdResolverTests.java b/spring-web/src/test/java/org/springframework/web/server/session/CookieWebSessionIdResolverTests.java index 60b5716a06..c1c37caeae 100644 --- a/spring-web/src/test/java/org/springframework/web/server/session/CookieWebSessionIdResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/server/session/CookieWebSessionIdResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 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. @@ -20,6 +20,7 @@ import org.junit.jupiter.api.Test; import org.springframework.http.ResponseCookie; import org.springframework.util.MultiValueMap; +import org.springframework.web.server.ServerWebExchange; import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest; import org.springframework.web.testfixture.server.MockServerWebExchange; @@ -33,18 +34,14 @@ public class CookieWebSessionIdResolverTests { private final CookieWebSessionIdResolver resolver = new CookieWebSessionIdResolver(); + private final ServerWebExchange exchange = + MockServerWebExchange.from(MockServerHttpRequest.get("https://example.org/path")); + @Test public void setSessionId() { - MockServerHttpRequest request = MockServerHttpRequest.get("https://example.org/path").build(); - MockServerWebExchange exchange = MockServerWebExchange.from(request); - this.resolver.setSessionId(exchange, "123"); - - MultiValueMap cookies = exchange.getResponse().getCookies(); - assertThat(cookies).hasSize(1); - ResponseCookie cookie = cookies.getFirst(this.resolver.getCookieName()); - assertThat(cookie).isNotNull(); - assertThat(cookie.toString()).isEqualTo("SESSION=123; Path=/; Secure; HttpOnly; SameSite=Lax"); + this.resolver.setSessionId(this.exchange, "123"); + assertCookieValue("SESSION=123; Path=/; Secure; HttpOnly; SameSite=Lax"); } @Test @@ -52,16 +49,26 @@ public class CookieWebSessionIdResolverTests { this.resolver.addCookieInitializer(builder -> builder.domain("example.org")); this.resolver.addCookieInitializer(builder -> builder.sameSite("Strict")); this.resolver.addCookieInitializer(builder -> builder.secure(false)); + this.resolver.setSessionId(this.exchange, "123"); - MockServerHttpRequest request = MockServerHttpRequest.get("https://example.org/path").build(); - MockServerWebExchange exchange = MockServerWebExchange.from(request); - this.resolver.setSessionId(exchange, "123"); + assertCookieValue("SESSION=123; Path=/; Domain=example.org; HttpOnly; SameSite=Strict"); + } + + @Test + public void expireSessionWhenMaxAgeSetViaInitializer() { + this.resolver.addCookieInitializer(builder -> builder.maxAge(600)); + this.resolver.expireSession(this.exchange); + + assertCookieValue("SESSION=; Path=/; Max-Age=0; " + + "Expires=Thu, 01 Jan 1970 00:00:00 GMT; Secure; HttpOnly; SameSite=Lax"); + } - MultiValueMap cookies = exchange.getResponse().getCookies(); + private void assertCookieValue(String expected) { + MultiValueMap cookies = this.exchange.getResponse().getCookies(); assertThat(cookies).hasSize(1); ResponseCookie cookie = cookies.getFirst(this.resolver.getCookieName()); assertThat(cookie).isNotNull(); - assertThat(cookie.toString()).isEqualTo("SESSION=123; Path=/; Domain=example.org; HttpOnly; SameSite=Strict"); + assertThat(cookie.toString()).isEqualTo(expected); } }