I'm using Micronaut 2.5.3
When I receive a header like Set-Cookie: cookie_name=cookie value; expires=Mon, 17-May-2021 09:32:59 GMT; path=/; secure; HttpOnly; samesite=none
in the response with whitespaces inside the value, the console shows a warning and ends up with a NullPointerException from NettyCookies since it decodes in STRICT mode and fails.
WARN io.netty.channel.DefaultChannelPipeline - An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
java.lang.NullPointerException: null
at io.micronaut.http.netty.cookies.NettyCookies.<init>(NettyCookies.java:78)
at io.micronaut.http.client.netty.FullNettyClientHttpResponse.<init>(FullNettyClientHttpResponse.java:99)
at io.micronaut.http.client.netty.DefaultHttpClient$12.channelReadInstrumented(DefaultHttpClient.java:2204)
And finally shows ReadTimeoutException
io.micronaut.http.client.exceptions.ReadTimeoutException: Read Timeout
at io.micronaut.http.client.exceptions.ReadTimeoutException.<clinit>(ReadTimeoutException.java:26)
at io.micronaut.http.client.netty.DefaultHttpClient.lambda$null$36(DefaultHttpClient.java:1178)
at io.reactivex.internal.operators.flowable.FlowableOnErrorNext$OnErrorNextSubscriber.onError(FlowableOnErrorNext.java:103)
at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onError(RxInstrumentedSubscriber.java:66)
at io.reactivex.internal.operators.flowable.FlowableTimeoutTimed$TimeoutSubscriber.onTimeout(FlowableTimeoutTimed.java:139)
at io.reactivex.internal.operators.flowable.FlowableTimeoutTimed$TimeoutTask.run(FlowableTimeoutTimed.java:170)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
If we inspect the NettyCookies code, the STRICT Decoder is used, which returns a null Cookie in io.netty.handler.codec.http.cookie.Cookie nettyCookie = ClientCookieDecoder.STRICT.decode(value);
. When this.cookies.put(nettyCookie.name(), new NettyCookie(nettyCookie));
runs, NullPointerException
is thrown because nettyCookie
is null
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()) {
this.cookies = new LinkedHashMap();
Iterator var4 = values.iterator();
while(var4.hasNext()) {
String value = (String)var4.next();
io.netty.handler.codec.http.cookie.Cookie nettyCookie = ClientCookieDecoder.STRICT.decode(value);
this.cookies.put(nettyCookie.name(), new NettyCookie(nettyCookie));
}
} else {
this.cookies = Collections.emptyMap();
}
} else {
this.cookies = Collections.emptyMap();
}
}
If I could use the LAX decoder this would not happen
The decoding method cannot be changed as it is a security vulnerability if it was LAX. The issue with the NPE has been fixed for Micronaut 2.5.4