package io.micronaut.http.netty.cookies;
import io.micronaut.core.convert.ArgumentConversionContext;
import io.micronaut.core.convert.ConversionService;
import io.micronaut.http.cookie.Cookie;
import io.micronaut.http.cookie.Cookies;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.cookie.ClientCookieDecoder;
import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
import java.util.*;
public class NettyCookies implements Cookies {
private final ConversionService<?> conversionService;
private final Map<CharSequence, Cookie> cookies;
public NettyCookies(String path, HttpHeaders nettyHeaders, ConversionService conversionService) {
this.conversionService = conversionService;
String value = nettyHeaders.get(HttpHeaderNames.COOKIE);
if (value != null) {
cookies = new LinkedHashMap<>();
Set<io.netty.handler.codec.http.cookie.Cookie> nettyCookies = ServerCookieDecoder.LAX.decode(value);
for (io.netty.handler.codec.http.cookie.Cookie nettyCookie : nettyCookies) {
String cookiePath = nettyCookie.path();
if (cookiePath != null) {
if (path.startsWith(cookiePath)) {
cookies.put(nettyCookie.name(), new NettyCookie(nettyCookie));
}
} else {
cookies.put(nettyCookie.name(), new NettyCookie(nettyCookie));
}
}
} else {
cookies = Collections.emptyMap();
}
}
public NettyCookies(HttpHeaders nettyHeaders, ConversionService conversionService) {
this.conversionService = conversionService;
if (nettyHeaders != null) {
List<String> values = nettyHeaders.getAll(HttpHeaderNames.SET_COOKIE);
if (values != null && !values.isEmpty()) {
cookies = new LinkedHashMap<>();
for (String value: values) {
io.netty.handler.codec.http.cookie.Cookie nettyCookie = ClientCookieDecoder.STRICT.decode(value);
cookies.put(nettyCookie.name(), new NettyCookie(nettyCookie));
}
} else {
cookies = Collections.emptyMap();
}
} else {
cookies = Collections.emptyMap();
}
}
@Override
public Set<Cookie> getAll() {
return new HashSet<>(cookies.values());
}
@Override
public Optional<Cookie> findCookie(CharSequence name) {
Cookie cookie = cookies.get(name);
return cookie != null ? Optional.of(cookie) : Optional.empty();
}
@Override
public <T> Optional<T> get(CharSequence name, Class<T> requiredType) {
if (requiredType == Cookie.class || requiredType == Object.class) {
return (Optional<T>) findCookie(name);
} else {
return findCookie(name).flatMap((cookie -> conversionService.convert(cookie.getValue(), requiredType)));
}
}
@Override
public <T> Optional<T> get(CharSequence name, ArgumentConversionContext<T> conversionContext) {
return findCookie(name).flatMap((cookie -> conversionService.convert(cookie.getValue(), conversionContext)));
}
@Override
public Collection<Cookie> values() {
return Collections.unmodifiableCollection(cookies.values());
}
}