Search code examples
httpclientnettymicronautsetcookieresponse-headers

Is there a way to set the CookieDecoder to LAX in MICRONAUT using HttpClient?


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


Solution

  • 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