Skip to content

Commit 7e2ae2e

Browse files
authored
Add http cookies (micronaut-projects#4000)
* Add support for retrieving cookies from non mutable responses
1 parent aec3a00 commit 7e2ae2e

File tree

8 files changed

+168
-1
lines changed

8 files changed

+168
-1
lines changed

http-client/src/main/java/io/micronaut/http/client/netty/FullNettyClientHttpResponse.java

+15
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,11 @@
3131
import io.micronaut.http.MediaType;
3232
import io.micronaut.http.codec.MediaTypeCodec;
3333
import io.micronaut.http.codec.MediaTypeCodecRegistry;
34+
import io.micronaut.http.cookie.Cookie;
35+
import io.micronaut.http.cookie.Cookies;
3436
import io.micronaut.http.netty.NettyHttpHeaders;
3537
import io.micronaut.http.netty.NettyHttpResponseBuilder;
38+
import io.micronaut.http.netty.cookies.NettyCookies;
3639
import io.netty.buffer.ByteBuf;
3740
import io.netty.buffer.ByteBufAllocator;
3841
import io.netty.buffer.ByteBufUtil;
@@ -60,6 +63,7 @@ public class FullNettyClientHttpResponse<B> implements HttpResponse<B>, Completa
6063

6164
private final HttpStatus status;
6265
private final NettyHttpHeaders headers;
66+
private final NettyCookies nettyCookies;
6367
private final MutableConvertibleValues<Object> attributes;
6468
private final FullHttpResponse nettyHttpResponse;
6569
private final Map<Argument, Optional> convertedBodies = new HashMap<>();
@@ -91,6 +95,7 @@ public class FullNettyClientHttpResponse<B> implements HttpResponse<B>, Completa
9195
this.nettyHttpResponse = fullHttpResponse;
9296
this.mediaTypeCodecRegistry = mediaTypeCodecRegistry;
9397
this.byteBufferFactory = byteBufferFactory;
98+
this.nettyCookies = new NettyCookies(fullHttpResponse.headers(), ConversionService.SHARED);
9499
Class<?> rawBodyType = bodyType != null ? bodyType.getType() : null;
95100
if (rawBodyType != null && !HttpStatus.class.isAssignableFrom(rawBodyType)) {
96101
if (HttpResponse.class.isAssignableFrom(bodyType.getType())) {
@@ -124,6 +129,16 @@ public HttpHeaders getHeaders() {
124129
return headers;
125130
}
126131

132+
@Override
133+
public Cookies getCookies() {
134+
return nettyCookies;
135+
}
136+
137+
@Override
138+
public Optional<Cookie> getCookie(String name) {
139+
return nettyCookies.findCookie(name);
140+
}
141+
127142
@Override
128143
public MutableConvertibleValues<Object> getAttributes() {
129144
return attributes;

http-client/src/main/java/io/micronaut/http/client/netty/NettyStreamedHttpResponse.java

+14
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323
import io.micronaut.core.convert.value.MutableConvertibleValuesMap;
2424
import io.micronaut.http.*;
2525
import io.micronaut.http.cookie.Cookie;
26+
import io.micronaut.http.cookie.Cookies;
2627
import io.micronaut.http.netty.NettyHttpHeaders;
2728
import io.micronaut.http.netty.NettyHttpResponseBuilder;
2829
import io.micronaut.http.netty.cookies.NettyCookie;
30+
import io.micronaut.http.netty.cookies.NettyCookies;
2931
import io.micronaut.http.netty.stream.StreamedHttpResponse;
3032
import io.netty.handler.codec.http.FullHttpResponse;
3133
import io.netty.handler.codec.http.HttpHeaderNames;
@@ -47,6 +49,7 @@ class NettyStreamedHttpResponse<B> implements MutableHttpResponse<B>, NettyHttpR
4749
private final StreamedHttpResponse nettyResponse;
4850
private HttpStatus status;
4951
private final NettyHttpHeaders headers;
52+
private final NettyCookies nettyCookies;
5053
private B body;
5154
private MutableConvertibleValues<Object> attributes;
5255

@@ -58,6 +61,7 @@ class NettyStreamedHttpResponse<B> implements MutableHttpResponse<B>, NettyHttpR
5861
this.nettyResponse = response;
5962
this.status = httpStatus;
6063
this.headers = new NettyHttpHeaders(response.headers(), ConversionService.SHARED);
64+
this.nettyCookies = new NettyCookies(response.headers(), ConversionService.SHARED);
6165
}
6266

6367
/**
@@ -146,6 +150,16 @@ public MutableHttpResponse<B> cookie(Cookie cookie) {
146150
return this;
147151
}
148152

153+
@Override
154+
public Cookies getCookies() {
155+
return nettyCookies;
156+
}
157+
158+
@Override
159+
public Optional<Cookie> getCookie(String name) {
160+
return nettyCookies.findCookie(name);
161+
}
162+
149163
@Override
150164
public <T> MutableHttpResponse<T> body(@Nullable T body) {
151165
this.body = (B) body;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package io.micronaut.http.client.netty
2+
3+
import io.micronaut.http.HttpStatus
4+
import io.micronaut.http.cookie.Cookie
5+
import io.micronaut.http.cookie.Cookies
6+
import io.netty.handler.codec.http.*
7+
import spock.lang.Specification
8+
9+
class FullNettyClientHttpResponseSpec extends Specification {
10+
11+
void "test cookies"() {
12+
given:
13+
String cookieDef = "simple-cookie=avalue; max-age=60; path=/; domain=.micronaut.io";
14+
HttpHeaders httpHeaders = new DefaultHttpHeaders(false).add(HttpHeaderNames.SET_COOKIE, cookieDef);
15+
FullHttpResponse fullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
16+
fullHttpResponse.headers().set(httpHeaders);
17+
18+
when:
19+
FullNettyClientHttpResponse response = new FullNettyClientHttpResponse(fullHttpResponse, HttpStatus.OK, null, null, null, false);
20+
21+
then:
22+
Cookies cookies = response.getCookies();
23+
cookies != null;
24+
cookies.size() == 4;
25+
cookies.contains("simple-cookie");
26+
Optional<Cookie> oCookie = response.getCookie("simple-cookie");
27+
oCookie.isPresent();
28+
oCookie.get().getValue().equals("avalue");
29+
30+
}
31+
32+
}
33+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package io.micronaut.http.client.netty
2+
3+
import io.micronaut.http.HttpStatus
4+
import io.micronaut.http.cookie.Cookie
5+
import io.micronaut.http.cookie.Cookies
6+
import io.micronaut.http.netty.stream.DefaultStreamedHttpResponse
7+
import io.micronaut.http.netty.stream.StreamedHttpResponse
8+
import io.netty.handler.codec.http.*
9+
import spock.lang.Specification
10+
11+
class NettyStreamedHttpResponseSpec extends Specification {
12+
13+
14+
void "test cookies"() {
15+
given:
16+
String cookieDef = "simple-cookie=avalue; max-age=60; path=/; domain=.micronaut.io";
17+
HttpHeaders httpHeaders = new DefaultHttpHeaders(false).add(HttpHeaderNames.SET_COOKIE, cookieDef);
18+
StreamedHttpResponse streamedHttpResponse = new DefaultStreamedHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, null);
19+
streamedHttpResponse.headers().set(httpHeaders);
20+
21+
when:
22+
NettyStreamedHttpResponse response = new NettyStreamedHttpResponse(streamedHttpResponse, HttpStatus.OK);
23+
24+
then:
25+
Cookies cookies = response.getCookies();
26+
cookies != null;
27+
cookies.size() == 4;
28+
cookies.contains("simple-cookie");
29+
Optional<Cookie> oCookie = response.getCookie("simple-cookie");
30+
oCookie.isPresent();
31+
oCookie.get().getValue().equals("avalue");
32+
33+
}
34+
35+
}

http-netty/src/main/java/io/micronaut/http/netty/cookies/NettyCookies.java

+22
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,28 @@ public NettyCookies(String path, HttpHeaders nettyHeaders, ConversionService con
6868
}
6969
}
7070

71+
/**
72+
* @param nettyHeaders The Netty HTTP headers
73+
* @param conversionService The conversion service
74+
*/
75+
public NettyCookies(HttpHeaders nettyHeaders, ConversionService conversionService) {
76+
this.conversionService = conversionService;
77+
if (nettyHeaders != null) {
78+
String value = nettyHeaders.get(HttpHeaderNames.SET_COOKIE);
79+
if (value != null) {
80+
cookies = new LinkedHashMap<>();
81+
Set<io.netty.handler.codec.http.cookie.Cookie> nettyCookies = ServerCookieDecoder.STRICT.decode(value);
82+
for (io.netty.handler.codec.http.cookie.Cookie nettyCookie : nettyCookies) {
83+
cookies.put(nettyCookie.name(), new NettyCookie(nettyCookie));
84+
}
85+
} else {
86+
cookies = Collections.emptyMap();
87+
}
88+
} else {
89+
cookies = Collections.emptyMap();
90+
}
91+
}
92+
7193
@Override
7294
public Set<Cookie> getAll() {
7395
return new HashSet<>(cookies.values());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package io.micronaut.http.netty.cookies
2+
3+
import io.micronaut.core.convert.ConversionService
4+
import io.micronaut.http.cookie.Cookie
5+
import io.netty.handler.codec.http.DefaultHttpHeaders
6+
import io.netty.handler.codec.http.HttpHeaderNames
7+
import io.netty.handler.codec.http.HttpHeaders
8+
import spock.lang.Specification
9+
10+
class NettyCookiesSpec extends Specification {
11+
12+
13+
void "test ctor creates cookies from headers and ConversionSpecification"() {
14+
given:
15+
String cookieDef = "simple-cookie=avalue; max-age=60; path=/; domain=.micronaut.io";
16+
HttpHeaders httpHeaders = new DefaultHttpHeaders(false).add(HttpHeaderNames.SET_COOKIE, cookieDef);
17+
18+
when:
19+
NettyCookies nettyCookies = new NettyCookies(httpHeaders, ConversionService.SHARED);
20+
21+
then:
22+
Cookie cookie = nettyCookies.get("simple-cookie");
23+
cookie != null;
24+
cookie.getValue().equals("avalue");
25+
26+
}
27+
28+
}

http/src/main/java/io/micronaut/http/HttpResponse.java

+20
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@
1515
*/
1616
package io.micronaut.http;
1717

18+
import io.micronaut.http.cookie.Cookie;
19+
import io.micronaut.http.cookie.Cookies;
1820
import io.micronaut.http.exceptions.UriSyntaxException;
1921

2022
import edu.umd.cs.findbugs.annotations.Nullable;
2123
import java.net.URI;
2224
import java.net.URISyntaxException;
25+
import java.util.Optional;
2326
import java.util.Set;
2427

2528
/**
@@ -398,4 +401,21 @@ static URI uri(CharSequence uri) {
398401
throw new UriSyntaxException(e);
399402
}
400403
}
404+
405+
/**
406+
* Helper method for retrieving all Cookies on a response.
407+
* @return The cookies on the response
408+
*/
409+
default Cookies getCookies() {
410+
throw new UnsupportedOperationException("Operation not supported on a " + this.getClass() + " response.");
411+
}
412+
413+
/**
414+
* Helper method for retrieving a single Cookie on a response.
415+
* @param name The name of the Cookie
416+
* @return The Cookie
417+
*/
418+
default Optional<Cookie> getCookie(String name) {
419+
throw new UnsupportedOperationException("Operation not supported on a " + this.getClass() + " response.");
420+
}
401421
}

http/src/main/java/io/micronaut/http/bind/binders/QueryValueArgumentBinder.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
import java.util.Collections;
3232

3333
/**
34-
* A binder for binding arguments annotated with @QueryValue
34+
* A binder for binding arguments annotated with @QueryValue.
3535
*
3636
* @param <T> The argument type
3737
* @author James Kleeh

0 commit comments

Comments
 (0)