diff --git a/http/src/main/java/io/micronaut/http/simple/SimpleHttpRequest.java b/http/src/main/java/io/micronaut/http/simple/SimpleHttpRequest.java index 94b75c59d2..17e9709440 100644 --- a/http/src/main/java/io/micronaut/http/simple/SimpleHttpRequest.java +++ b/http/src/main/java/io/micronaut/http/simple/SimpleHttpRequest.java @@ -77,8 +77,17 @@ public MutableHttpRequest cookie(Cookie cookie) { private void updateCookies() { headers.remove(HttpHeaders.COOKIE); + StringBuilder sb = new StringBuilder(); + int count = 0; for (Cookie cookie : cookies.getAll()) { - headers.add(HttpHeaders.COOKIE, ClientCookieEncoder.INSTANCE.encode(cookie)); + if (count > 0) { + sb.append("; "); + } + sb.append(ClientCookieEncoder.INSTANCE.encode(cookie)); + count++; + } + if (sb.length() > 0) { + headers.set(HttpHeaders.COOKIE, sb.toString()); } } diff --git a/http/src/test/java/io/micronaut/http/cookie/CookieHeaderSingleValueTest.java b/http/src/test/java/io/micronaut/http/cookie/CookieHeaderSingleValueTest.java new file mode 100644 index 0000000000..a26518ae54 --- /dev/null +++ b/http/src/test/java/io/micronaut/http/cookie/CookieHeaderSingleValueTest.java @@ -0,0 +1,93 @@ +package io.micronaut.http.cookie; + +import io.micronaut.http.HttpHeaders; +import io.micronaut.http.MutableHttpRequest; +import io.micronaut.http.cookie.Cookie; +import io.micronaut.http.client.netty.NettyClientHttpRequestFactory; +import io.micronaut.http.simple.SimpleHttpRequestFactory; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CookieHeaderSingleValueTest { + + private static final Set COOKIES = new LinkedHashSet() {{ + add(Cookie.of("a", "1")); + add(Cookie.of("b", "2")); + add(Cookie.of("a", "3")); + }}; + + private static String normalize(String header) { + if (header == null) { + return ""; + } + // remove all whitespace for deterministic comparison (some implementations include a space after semicolon) + return header.replaceAll("\\s+", "").trim(); + } + + private static List headerValues(MutableHttpRequest request, String name) { + Iterable it = request.getHeaders().getAll(name); + return StreamSupport.stream(it.spliterator(), false).collect(Collectors.toList()); + } + + @Test + public void simpleRequestAddsCookiesIntoSingleHeader() { + MutableHttpRequest request = new SimpleHttpRequestFactory().get("/"); + // ensure starting clean + request.getHeaders().remove(HttpHeaders.COOKIE); + + for (Cookie c : COOKIES) { + request.cookie(c); + } + + List all = headerValues(request, HttpHeaders.COOKIE); + assertEquals(1, all.size(), "Expected exactly one Cookie header value for SimpleHttpRequest"); + + String header = request.getHeaders().get(HttpHeaders.COOKIE); + assertEquals("a=3;b=2", normalize(header)); + } + + @Test + public void nettyClientRequestAddsCookiesIntoSingleHeader() { + MutableHttpRequest request = new NettyClientHttpRequestFactory().get("/"); + // ensure starting clean + request.getHeaders().remove(HttpHeaders.COOKIE); + + for (Cookie c : COOKIES) { + request.cookie(c); + } + + List all = headerValues(request, HttpHeaders.COOKIE); + assertEquals(1, all.size(), "Expected exactly one Cookie header value for NettyClientHttpRequest"); + + String header = request.getHeaders().get(HttpHeaders.COOKIE); + assertEquals("a=3;b=2", normalize(header)); + } + + @Test + public void addingCookiesTwiceKeepsSingleHeaderWithLastValueWin() { + MutableHttpRequest request = new SimpleHttpRequestFactory().get("/"); + request.getHeaders().remove(HttpHeaders.COOKIE); + + for (Cookie c : COOKIES) { + request.cookie(c); + } + // add again to exercise mutation + for (Cookie c : COOKIES) { + request.cookie(c); + } + + List all = headerValues(request, HttpHeaders.COOKIE); + assertEquals(1, all.size(), "Expected exactly one Cookie header value after repeated additions"); + + String header = request.getHeaders().get(HttpHeaders.COOKIE); + assertEquals("a=3;b=2", normalize(header)); + } +}