From 8fe2c780dfbfe593355044e36401c9e1ca697a00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deleuze?= Date: Wed, 6 Dec 2023 14:55:59 +0100 Subject: [PATCH] Support cookies with the same name with Reactor Netty Ignore the related test with Undertow due to a bug in their cookies handling. Closes gh-28490 --- .../ReactorNetty2ServerHttpRequest.java | 5 +++-- .../reactive/ReactorServerHttpRequest.java | 4 ++-- .../reactive/CookieIntegrationTests.java | 22 ++++++++++++++++++- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorNetty2ServerHttpRequest.java b/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorNetty2ServerHttpRequest.java index 5ae5b41fbfc..d61f634381a 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorNetty2ServerHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorNetty2ServerHttpRequest.java @@ -50,6 +50,7 @@ import org.springframework.util.MultiValueMap; *

This class is based on {@link ReactorServerHttpRequest}. * * @author Violeta Georgieva + * @author Sebastien Deleuze * @since 6.0 */ class ReactorNetty2ServerHttpRequest extends AbstractServerHttpRequest { @@ -144,8 +145,8 @@ class ReactorNetty2ServerHttpRequest extends AbstractServerHttpRequest { @Override protected MultiValueMap initCookies() { MultiValueMap cookies = new LinkedMultiValueMap<>(); - for (CharSequence name : this.request.cookies().keySet()) { - for (HttpCookiePair cookie : this.request.cookies().get(name)) { + for (CharSequence name : this.request.allCookies().keySet()) { + for (HttpCookiePair cookie : this.request.allCookies().get(name)) { CharSequence cookieValue = cookie.value(); HttpCookie httpCookie = new HttpCookie(name.toString(), cookieValue != null ? cookieValue.toString() : null); cookies.add(name.toString(), httpCookie); diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorServerHttpRequest.java b/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorServerHttpRequest.java index ff056e0cf52..b939eee45ac 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorServerHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorServerHttpRequest.java @@ -75,8 +75,8 @@ class ReactorServerHttpRequest extends AbstractServerHttpRequest { @Override protected MultiValueMap initCookies() { MultiValueMap cookies = new LinkedMultiValueMap<>(); - for (CharSequence name : this.request.cookies().keySet()) { - for (Cookie cookie : this.request.cookies().get(name)) { + for (CharSequence name : this.request.allCookies().keySet()) { + for (Cookie cookie : this.request.allCookies().get(name)) { HttpCookie httpCookie = new HttpCookie(name.toString(), cookie.value()); cookies.add(name.toString(), httpCookie); } diff --git a/spring-web/src/test/java/org/springframework/http/server/reactive/CookieIntegrationTests.java b/spring-web/src/test/java/org/springframework/http/server/reactive/CookieIntegrationTests.java index 85550cf4943..6362a97e308 100644 --- a/spring-web/src/test/java/org/springframework/http/server/reactive/CookieIntegrationTests.java +++ b/spring-web/src/test/java/org/springframework/http/server/reactive/CookieIntegrationTests.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. @@ -30,11 +30,14 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; import org.springframework.web.testfixture.http.server.reactive.bootstrap.AbstractHttpHandlerIntegrationTests; import org.springframework.web.testfixture.http.server.reactive.bootstrap.HttpServer; +import org.springframework.web.testfixture.http.server.reactive.bootstrap.UndertowHttpServer; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assumptions.assumeFalse; /** * @author Rossen Stoyanchev + * @author Sebastien Deleuze */ public class CookieIntegrationTests extends AbstractHttpHandlerIntegrationTests { @@ -81,6 +84,23 @@ public class CookieIntegrationTests extends AbstractHttpHandlerIntegrationTests .containsExactlyInAnyOrder("path=/", "domain=example.com"); } + @ParameterizedHttpServerTest + public void cookiesWithSameNameTest(HttpServer httpServer) throws Exception { + assumeFalse(httpServer instanceof UndertowHttpServer, "Bug in Undertow in Cookies with same name handling"); + + startServer(httpServer); + + URI url = new URI("http://localhost:" + port); + String header = "SID=31d4d96e407aad42; lang=en-US; lang=zh-CN"; + new RestTemplate().exchange( + RequestEntity.get(url).header("Cookie", header).build(), Void.class); + + Map> requestCookies = this.cookieHandler.requestCookies; + assertThat(requestCookies.size()).isEqualTo(2); + assertThat(requestCookies.get("SID")).extracting(HttpCookie::getValue).containsExactly("31d4d96e407aad42"); + assertThat(requestCookies.get("lang")).extracting(HttpCookie::getValue).containsExactly("en-US", "zh-CN"); + } + // No client side HttpCookie support yet private List splitCookie(String value) { List list = new ArrayList<>();