All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.muserver.PreReader Maven / Gradle / Ivy

The newest version!
package io.muserver;

import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil;

/**
 * This pre-emptively reads a message from the channel before the HTTP handler has actually asked for it.
 * The reason for this is to force more time waiting on a read at the NIO channel, and therefore detect
 * client disconnections. If there is a better way, it may be revealed here: https://stackoverflow.com/questions/66075288/detecting-closed-channels-when-auto-read-is-false-in-netty-4
 */
class PreReader extends ChannelDuplexHandler {

    private Object pendingMsg;
    private boolean wantsToRead = false;

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        ctx.channel().config().setAutoRead(false);
        ctx.read();
        super.handlerAdded(ctx);
    }

    private void sendItMaybe(ChannelHandlerContext ctx) {
        if (wantsToRead) {
            Object msg = this.pendingMsg;
            if (msg != null) {
                this.pendingMsg = null;
                this.wantsToRead = false;
                ctx.fireChannelRead(msg);
                ReferenceCountUtil.release(msg);
                ctx.read();
            }
        }
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        // A message is available. Set it as pending but only forward to the mu handler if a read
        // has been requested.
        ReferenceCountUtil.retain(msg);
        pendingMsg = msg;
        sendItMaybe(ctx);
    }

    @Override
    public void read(ChannelHandlerContext ctx) throws Exception {
        // The mu handler wants to read. Send it the pending message if it's there; otherwise wait
        wantsToRead = true;
        ctx.executor().submit(() -> sendItMaybe(ctx));
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        if (pendingMsg != null) {
            ReferenceCountUtil.release(pendingMsg);
            ctx.fireChannelRead(pendingMsg); // without this, a reference is leaked
            pendingMsg = null;
        }
        super.channelUnregistered(ctx);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy