Example usage for io.netty.buffer ByteBuf readableBytes

List of usage examples for io.netty.buffer ByteBuf readableBytes

Introduction

In this page you can find the example usage for io.netty.buffer ByteBuf readableBytes.

Prototype

public abstract int readableBytes();

Source Link

Document

Returns the number of readable bytes which is equal to (this.writerIndex - this.readerIndex) .

Usage

From source file:com.chiorichan.http.HttpHandler.java

License:Mozilla Public License

/**
 * Handles the HTTP request. Each HTTP subsystem will be explicitly activated until a resolve is determined.
 *
 * @throws IOException/*from  www. j a va2s. c o m*/
 *              Universal exception for all Input/Output errors
 * @throws HttpError
 *              for HTTP Errors
 * @throws PermissionException
 *              for permission problems, like access denied
 * @throws MultipleException
 *              for multiple Scripting Factory Evaluation Exceptions
 * @throws ScriptingException
 *              for Scripting Factory Evaluation Exception
 * @throws SessionException
 *              for problems initializing a new or used session
 */
private void handleHttp() throws Exception // IOException, HttpError, SiteException, PermissionException, MultipleException, ScriptingException, SessionException
{
    log.log(Level.INFO, request.methodString() + " " + request.getFullUrl());

    Session sess = request.startSession();

    log.log(Level.FINE, "Session {id=%s,timeout=%s,new=%s}", sess.getSessId(), sess.getTimeout(), sess.isNew());

    if (response.getStage() == HttpResponseStage.CLOSED)
        throw new IOException("Connection reset by peer"); // This is not the only place 'Connection reset by peer' is thrown

    RequestEvent requestEvent = new RequestEvent(request);

    try {
        EventBus.instance().callEventWithException(requestEvent);
    } catch (EventException ex) {
        throw new IOException(
                "Exception encountered during request event call, most likely the fault of a plugin.", ex);
    }

    response.setStatus(requestEvent.getStatus());

    if (requestEvent.isCancelled()) {
        int status = requestEvent.getStatus();
        String reason = requestEvent.getReason();

        if (status == 200) {
            status = 502;
            reason = "Navigation Cancelled by Plugin Event";
        }

        NetworkManager.getLogger().warning("Navigation was cancelled by a Plugin Event");

        throw new HttpError(status, reason);
    }

    if (response.isCommitted())
        return;

    // Throws IOException and HttpError
    fi = new WebInterpreter(request);
    response.annotations.putAll(fi.getAnnotations());

    currentSite = request.getLocation();
    sess.setSite(currentSite);

    if (request.getSubdomain().length() > 0
            && !currentSite.getSubdomain(request.getSubdomain()).isMaped(request.getDomain())) {
        if ("www".equalsIgnoreCase(request.getSubdomain())
                || AppConfig.get().getBoolean("sites.redirectMissingSubDomains")) {
            log.log(Level.SEVERE, "Redirecting non-existent subdomain '%s' to root domain '%s'",
                    request.getSubdomain(), request.getFullUrl(""));
            response.sendRedirect(request.getFullUrl(""));
        } else {
            log.log(Level.SEVERE, "The requested subdomain '%s' is non-existent.", request.getSubdomain(),
                    request.getFullDomain(""));
            response.sendError(HttpResponseStatus.NOT_FOUND, "Subdomain not found");
        }
        return;
    }

    File docRoot = currentSite.getSubdomain(request.getSubdomain()).directory();

    Validate.notNull(docRoot);

    if (sess.isLoginPresent())
        log.log(Level.FINE, "Account {id=%s,displayName=%s}", sess.getId(), sess.getDisplayName());

    /*
     * Start: SSL enforcer
     *
     * Acts on the value of annotation 'SSL'.
     * REQUIRED means a forbidden error will be thrown is it can not be accomplished
     *
     * Options include:
     * Preferred: If SSL is available, we preferred to be switched to it
     * PostOnly: SSL is REQUIRED is this is a POST request
     * GetOnly: SSL is REQUIRED if this is a GET request
     * Required: SSL is REQUIRED, no exceptions!
     * Deny: SSL is DENIED, no exceptions!
     * Ignore: We don't care one way or other, do nothing! DEFAULT
     */
    SslLevel sslLevel = SslLevel.parse(fi.get("ssl"));
    boolean required = false;

    switch (sslLevel) {
    case Preferred:
        if (NetworkManager.isHttpsRunning())
            required = true;
        break;
    case PostOnly:
        if (request.method() == HttpMethod.POST)
            required = true;
        break;
    case GetOnly:
        if (request.method() == HttpMethod.GET)
            required = true;
        break;
    case Required:
        required = true;
        break;
    case Deny:
        if (ssl) {
            if (!response.switchToUnsecure())
                response.sendError(HttpCode.HTTP_FORBIDDEN, "This page requires an unsecure connection.");
            return;
        }
        break;
    case Ignore:
        break;
    }

    if (required && !ssl) {
        if (!response.switchToSecure())
            response.sendError(HttpCode.HTTP_FORBIDDEN, "This page requires a secure connection.");
        return;
    }
    /*
     * End: SSL enforcer
     */

    if (fi.getStatus() != HttpResponseStatus.OK)
        throw new HttpError(fi.getStatus());

    /*
     * Start: Apache Configuration Section
     *
     * Loads a Apache configuration and .htaccess files into a common handler, then parsed for directives like access restrictions and basic auth
     * TODO Load server-wide Apache Configuration then merge with Site Configuration
     */
    ApacheHandler htaccess = new ApacheHandler();
    response.setApacheParser(htaccess);

    try {
        boolean result = htaccess.handleDirectives(currentSite.getApacheConfig(), this);

        if (htaccess.overrideNone() || htaccess.overrideListNone()) // Ignore .htaccess files
        {
            if (fi.hasFile())
                if (!htaccess.handleDirectives(new ApacheConfiguration(fi.getFile().getParentFile()), this))
                    result = false;

            if (!htaccess.handleDirectives(new ApacheConfiguration(docRoot), this))
                result = false;
        }

        if (!result) {
            if (!response.isCommitted())
                response.sendError(500,
                        "Your request was blocked by an internal configuration directive, exact details are unknown.");
            return;
        }
    } catch (ApacheDirectiveException e) {
        log.log(Level.SEVERE, "Caught Apache directive exception: " + e.getMessage());

        // TODO Throw 500 unless told not to
    }
    /*
     * End: Apache Configuration Section
     */

    if (!fi.hasFile() && !fi.hasHTML())
        response.setStatus(HttpResponseStatus.NO_CONTENT);

    sess.setGlobal("__FILE__", fi.getFile());

    request.putRewriteParams(fi.getRewriteParams());
    response.setContentType(fi.getContentType());
    response.setEncoding(fi.getEncoding());

    request.getServer().put(ServerVars.DOCUMENT_ROOT, docRoot);

    request.setGlobal("_SERVER", request.getServer());
    request.setGlobal("_POST", request.getPostMap());
    request.setGlobal("_GET", request.getGetMap());
    request.setGlobal("_REWRITE", request.getRewriteMap());
    request.setGlobal("_FILES", request.getUploadedFiles());

    // TODO Implement NONCE requirement for login page
    NonceLevel level = NonceLevel.parse(fi.get("nonce"));
    boolean nonceProvided = sess.nonce() == null ? false
            : request.getRequestMap().get(sess.nonce().key()) != null;
    boolean processNonce = false;

    switch (level) {
    case Required:
        processNonce = true;
        break;
    case GetOnly:
        processNonce = request.method() == HttpMethod.GET || nonceProvided;
        break;
    case PostOnly:
        processNonce = request.method() == HttpMethod.POST || nonceProvided;
        break;
    case Flexible:
        processNonce = nonceProvided;
        break;
    case Disabled:
    default:
        // Do Nothing
    }

    Map<String, String> nonceMap = Maps.newHashMap();

    if (processNonce) {
        if (!nonceProvided) {
            log.log(Level.SEVERE,
                    "The request has failed NONCE validation, because the nonce key was not present!");
            response.sendError(HttpResponseStatus.FORBIDDEN, "Your request has failed NONCE validation!");
            return;
        }

        Nonce nonce = sess.nonce();

        if (level == NonceLevel.Required)
            // Required NonceLevels are of the highest protected state
            sess.destroyNonce();

        try {
            if (!(request.getRequestMap().get(nonce.key()) instanceof String))
                throw new NonceException("Nonce token is not a string");
            nonce.validateWithException((String) request.getRequestMap().get(nonce.key()));
        } catch (NonceException e) {
            log.log(Level.SEVERE,
                    "The request has failed NONCE validation, because " + e.getMessage().toLowerCase() + "!");
            response.sendError(HttpResponseStatus.FORBIDDEN, "Your request has failed NONCE validation!");
            sess.destroyNonce();
            return;
        } finally {
            log.log(Level.INFO, "The request has passed the NONCE validation!");
            request.nonceProcessed(true);
            nonceMap = nonce.mapValues();
        }
    }

    if (request.validateLogins())
        return;

    if (level != NonceLevel.Disabled)
        request.setGlobal("_NONCE", nonceMap);

    try {
        if (request.getUploadedFiles().size() > 0)
            log.log(Level.INFO,
                    "Uploads {"
                            + StringFunc.limitLength(
                                    Joiner.on(",").skipNulls().join(request.getUploadedFiles().values()), 255)
                            + "}");

        if (request.getGetMap().size() > 0)
            log.log(Level.INFO, "Params GET {" + StringFunc.limitLength(
                    Joiner.on(",").withKeyValueSeparator("=").useForNull("null").join(request.getGetMap()), 255)
                    + "}");

        if (request.getPostMap().size() > 0)
            log.log(Level.INFO, "Params POST {" + StringFunc.limitLength(
                    Joiner.on(",").withKeyValueSeparator("=").useForNull("null").join(request.getPostMap()),
                    255) + "}");

        if (request.getRewriteMap().size() > 0)
            log.log(Level.INFO, "Params REWRITE {" + StringFunc.limitLength(
                    Joiner.on(",").withKeyValueSeparator("=").useForNull("null").join(request.getRewriteMap()),
                    255) + "}");

        if (fi.getAnnotations().size() > 0)
            log.log(Level.INFO, "Params ANNOTATIONS {" + StringFunc.limitLength(
                    Joiner.on(",").withKeyValueSeparator("=").useForNull("null").join(fi.getAnnotations()), 255)
                    + "}");
    } catch (Throwable t) {
        t.printStackTrace();
    }

    if (AppConfig.get().getBoolean("advanced.security.requestMapEnabled", true))
        request.setGlobal("_REQUEST", request.getRequestMap());

    ByteBuf rendered = Unpooled.buffer();

    ScriptingFactory factory = request.getEvalFactory();
    factory.setEncoding(fi.getEncoding());

    NetworkSecurity.isForbidden(htaccess, currentSite, fi);

    String req = fi.get("reqperm");

    if (req == null)
        req = "-1";

    sess.requirePermission(req, currentSite.getId());

    // Enhancement: Allow HTML to be ran under different shells. Default is embedded.
    if (fi.hasHTML()) {
        ScriptingResult result = factory.eval(
                ScriptingContext.fromSource(fi.getHTML(), "<embedded>").request(request).site(currentSite));

        if (result.hasExceptions())
            // TODO Print notices to output like PHP does
            for (ScriptingException e : result.getExceptions()) {
                ExceptionReport.throwExceptions(e);
                log.exceptions(e);
                if (e.reportingLevel().isEnabled())
                    rendered.writeBytes(e.getMessage().getBytes());
            }

        if (result.isSuccessful()) {
            rendered.writeBytes(result.content());
            if (result.getObject() != null && !(result.getObject() instanceof NullObject))
                try {
                    rendered.writeBytes(ObjectFunc.castToStringWithException(result.getObject()).getBytes());
                } catch (Exception e) {
                    log.log(Level.SEVERE, "Exception Excountered: %s", e.getMessage());
                    if (Versioning.isDevelopment())
                        log.log(Level.SEVERE, e.getStackTrace()[0].toString());
                }
        }

        log.log(Level.INFO, "EvalHtml {timing=%sms,success=%s}", Timings.mark(this), result.isSuccessful());
    }

    if (fi.hasFile()) {
        if (fi.isDirectoryRequest()) {
            processDirectoryListing();
            return;
        }

        ScriptingResult result = factory.eval(ScriptingContext.fromFile(fi).request(request).site(currentSite));

        if (result.hasExceptions())
            // TODO Print notices to output like PHP does
            for (ScriptingException e : result.getExceptions()) {
                ExceptionReport.throwExceptions(e);
                log.exceptions(e);
                if (e.reportingLevel().isEnabled() && e.getMessage() != null)
                    rendered.writeBytes(e.getMessage().getBytes());
            }

        if (result.isSuccessful()) {
            rendered.writeBytes(result.content());
            if (result.getObject() != null && !(result.getObject() instanceof NullObject))
                try {
                    rendered.writeBytes(ObjectFunc.castToStringWithException(result.getObject()).getBytes());
                } catch (Exception e) {
                    rendered.writeBytes(result.getObject().toString().getBytes());
                    log.log(Level.SEVERE, "Exception encountered while writing returned object to output. %s",
                            e.getMessage());
                    if (Versioning.isDevelopment())
                        log.log(Level.SEVERE, e.getStackTrace()[0].toString());
                }
        }

        log.log(Level.INFO, "EvalFile {file=%s,timing=%sms,success=%s}", fi.getFilePath(), Timings.mark(this),
                result.isSuccessful());
    }

    // if the connection was in a MultiPart mode, wait for the mode to change then return gracefully.
    if (response.stage == HttpResponseStage.MULTIPART) {
        while (response.stage == HttpResponseStage.MULTIPART)
            // I wonder if there is a better way to handle multipart responses.
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new HttpError(500, "Internal Server Error encountered during multipart execution.");
            }

        return;
    }
    // If the connection was closed from page redirect, return gracefully.
    else if (response.stage == HttpResponseStage.CLOSED || response.stage == HttpResponseStage.WRITTEN)
        return;

    // Allows scripts to directly override interpreter values. For example: Themes, Views, Titles
    for (Entry<String, String> kv : response.annotations.entrySet())
        fi.put(kv.getKey(), kv.getValue());

    RenderEvent renderEvent = new RenderEvent(this, rendered, fi.getEncoding(), fi.getAnnotations());

    try {
        EventBus.instance().callEventWithException(renderEvent);
        if (renderEvent.getSource() != null)
            rendered = renderEvent.getSource();
    } catch (EventException ex) {
        throw new ScriptingException(ReportingLevel.E_ERROR,
                "Caught EventException while trying to fire the RenderEvent", ex.getCause());
    }

    log.log(Level.INFO, "Written {bytes=%s,total_timing=%sms}", rendered.readableBytes(), Timings.finish(this));

    try {
        response.write(rendered);
    } catch (IllegalReferenceCountException e) {
        log.log(Level.SEVERE, "Exception encountered while writting script object to output, %s",
                e.getMessage());
    }
}

From source file:com.chiorichan.http.ssl.SniNegotiator.java

License:Mozilla Public License

@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
    if (!handshaken && in.readableBytes() >= 5) {
        String hostname = sniHostNameFromHandshakeInfo(in);
        if (hostname != null)
            hostname = IDN.toASCII(hostname, IDN.ALLOW_UNASSIGNED).toLowerCase(Locale.US);
        this.hostname = hostname;

        selectedContext = SslManager.instance().map(hostname);

        if (handshaken) {
            SSLEngine engine = selectedContext.newEngine(ctx.alloc());

            List<String> supportedCipherSuites = Arrays.asList(engine.getSupportedCipherSuites());

            if (!supportedCipherSuites.containsAll(enabledCipherSuites))
                for (String cipher : enabledCipherSuites)
                    if (!supportedCipherSuites.contains(cipher)) {
                        NetworkManager.getLogger()
                                .severe(String.format(
                                        "The SSL/TLS cipher suite '%s' is not supported by SSL Provider %s",
                                        cipher, SslContext.defaultServerProvider().name()));
                        enabledCipherSuites.remove(cipher);
                    }/*from  w  ww  . j a  va  2  s . c om*/

            engine.setUseClientMode(false);
            engine.setEnabledCipherSuites(enabledCipherSuites.toArray(new String[0]));

            ctx.pipeline().replace(this, ctx.name(), new SslExceptionHandler(engine));
        }
    }
}

From source file:com.chiorichan.http.ssl.SniNegotiator.java

License:Mozilla Public License

private String sniHostNameFromHandshakeInfo(ByteBuf in) {
    int readerIndex = in.readerIndex();
    try {/*  w w w  .j a v  a2s  . c o m*/
        int command = in.getUnsignedByte(readerIndex);

        // tls, but not handshake command
        switch (command) {
        case SslConstants.SSL_CONTENT_TYPE_CHANGE_CIPHER_SPEC:
        case SslConstants.SSL_CONTENT_TYPE_ALERT:
        case SslConstants.SSL_CONTENT_TYPE_APPLICATION_DATA:
            return null;
        case SslConstants.SSL_CONTENT_TYPE_HANDSHAKE:
            break;
        default:
            //not tls or sslv3, do not try sni
            handshaken = true;
            return null;
        }

        int majorVersion = in.getUnsignedByte(readerIndex + 1);

        // SSLv3 or TLS
        if (majorVersion == 3) {
            int packetLength = in.getUnsignedShort(readerIndex + 3) + 5;

            if (in.readableBytes() >= packetLength) {
                // decode the ssl client hello packet
                // we have to skip some var-length fields
                int offset = readerIndex + 43;

                int sessionIdLength = in.getUnsignedByte(offset);
                offset += sessionIdLength + 1;

                int cipherSuitesLength = in.getUnsignedShort(offset);
                offset += cipherSuitesLength + 2;

                int compressionMethodLength = in.getUnsignedByte(offset);
                offset += compressionMethodLength + 1;

                int extensionsLength = in.getUnsignedShort(offset);
                offset += 2;
                int extensionsLimit = offset + extensionsLength;

                while (offset < extensionsLimit) {
                    int extensionType = in.getUnsignedShort(offset);
                    offset += 2;

                    int extensionLength = in.getUnsignedShort(offset);
                    offset += 2;

                    // SNI
                    if (extensionType == 0) {
                        handshaken = true;
                        int serverNameType = in.getUnsignedByte(offset + 2);
                        if (serverNameType == 0) {
                            int serverNameLength = in.getUnsignedShort(offset + 3);
                            return in.toString(offset + 5, serverNameLength, CharsetUtil.UTF_8);
                        } else
                            // invalid enum value
                            return null;
                    }

                    offset += extensionLength;
                }

                handshaken = true;
                return null;
            } else
                // client hello incomplete
                return null;
        } else {
            handshaken = true;
            return null;
        }
    } catch (Throwable e) {
        // unexpected encoding, ignore sni and use default
        if (logger.isDebugEnabled())
            logger.debug("Unexpected client hello packet: " + ByteBufUtil.hexDump(in), e);
        handshaken = true;
        return null;
    }
}

From source file:com.chiorichan.util.ServerFunc.java

License:Mozilla Public License

public static byte[] byteBuf2Bytes(ByteBuf buf) {
    byte[] bytes = new byte[buf.readableBytes()];
    int readerIndex = buf.readerIndex();
    buf.getBytes(readerIndex, bytes);//from  www .j a  va  2s .  c o  m
    return bytes;
}

From source file:com.chuck.netty4.websocket.WebSocketIndexPageHandler.java

License:Apache License

@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {
    // Handle a bad request.
    if (!req.decoderResult().isSuccess()) {
        sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST));
        return;/*  w w w . j  av  a2  s  .  co m*/
    }

    // Allow only GET methods.
    if (req.method() != GET) {
        sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));
        return;
    }

    // Send the index page
    if ("/".equals(req.uri()) || "/index.html".equals(req.uri())) {
        String webSocketLocation = getWebSocketLocation(ctx.pipeline(), req, websocketPath);
        ByteBuf content = WebSocketServerIndexPage.getContent(webSocketLocation);
        FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, OK, content);

        res.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
        HttpUtil.setContentLength(res, content.readableBytes());

        sendHttpResponse(ctx, req, res);
    } else {
        sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND));
    }
}

From source file:com.cloudera.livy.client.local.rpc.KryoMessageCodec.java

License:Apache License

@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
    if (in.readableBytes() < 4) {
        return;//from   w ww . jav a 2  s  .  com
    }

    in.markReaderIndex();
    int msgSize = in.readInt();
    checkSize(msgSize);

    if (in.readableBytes() < msgSize) {
        // Incomplete message in buffer.
        in.resetReaderIndex();
        return;
    }

    try {
        ByteBuffer nioBuffer = maybeDecrypt(in.nioBuffer(in.readerIndex(), msgSize));
        Object msg = serializer.deserialize(nioBuffer);
        LOG.debug("Decoded message of type {} ({} bytes)", msg != null ? msg.getClass().getName() : msg,
                msgSize);
        out.add(msg);
    } finally {
        in.skipBytes(msgSize);
    }
}

From source file:com.cloudhopper.smpp.pdu.BaseBind.java

License:Apache License

@Override
public void readBody(ByteBuf buffer) throws UnrecoverablePduException, RecoverablePduException {
    this.systemId = ChannelBufferUtil.readNullTerminatedString(buffer);
    this.password = ChannelBufferUtil.readNullTerminatedString(buffer);
    this.systemType = ChannelBufferUtil.readNullTerminatedString(buffer);
    // at this point, we should have at least 3 bytes left
    if (buffer.readableBytes() < 3) {
        throw new NotEnoughDataInBufferException("After parsing systemId, password, and systemType",
                buffer.readableBytes(), 3);
    }/* w w w. jav a2 s .  c o m*/
    this.interfaceVersion = buffer.readByte();
    this.addressRange = ChannelBufferUtil.readAddress(buffer);
}

From source file:com.cloudhopper.smpp.pdu.BufferHelper.java

License:Apache License

static public byte[] createByteArray(ByteBuf buffer) throws Exception {
    byte[] bytes = new byte[buffer.readableBytes()];
    // temporarily read bytes from the buffer
    buffer.getBytes(buffer.readerIndex(), bytes);
    return bytes;
}

From source file:com.cloudhopper.smpp.pdu.Pdu.java

License:Apache License

public void readOptionalParameters(ByteBuf buffer, PduTranscoderContext context)
        throws UnrecoverablePduException, RecoverablePduException {
    // if there is any data left, it's part of an optional parameter
    while (buffer.readableBytes() > 0) {
        Tlv tlv = ChannelBufferUtil.readTlv(buffer);
        if (tlv.getTagName() == null) {
            tlv.setTagName(context.lookupTlvTagName(tlv.getTag()));
        }//from   w w w  .  j  a v a  2 s  . c o m
        this.addOptionalParameter(tlv);
    }
}

From source file:com.cloudhopper.smpp.simulator.SmppSimulatorSessionHandler.java

License:Apache License

@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception {
    // ignore requests with zero bytes
    if (buffer.readableBytes() <= 0) {
        return;/*w w w.ja  v  a2 s.  com*/
    }

    // decode the buffer into a pdu
    Pdu pdu = transcoder.decode(buffer);

    // if the pdu was null, we don't have enough data yet
    if (pdu == null) {
        logger.info("Received data on channel {}, but not enough to parse PDU fully yet", channel.toString());
        logger.info("Bytes in buffer: [{}]", ByteBufUtil.hexDump(buffer));
        return;
    }

    logger.info("Decoded buffer on channel {} into PDU: {}", channel.toString(), pdu);

    // if we have a pdu procesor registered, let's see if it handles it
    boolean processed = false;
    if (this.pduProcessor != null) {
        processed = this.pduProcessor.process(this, channel, pdu);
    }

    if (processed) {
        logger.info("This PDU was processed by the registered PduProcessor");
    } else {
        this.pduQueue.add(pdu);
    }

    // is there a PDU someone wants us to write in response?
    if (this.writePduQueue.size() > 0) {
        Pdu pduToWrite = this.writePduQueue.remove();
        logger.info("Automatically writing back on channel {} the PDU: {}", channel.toString(), pduToWrite);
        ByteBuf writeBuffer = this.transcoder.encode(pduToWrite);
        channel.writeAndFlush(writeBuffer);
    }

    out.add(pdu);
}