void (@NotNull ChannelHandlerContext context, @NotNull ByteBuf buffer) { ChannelPipeline pipeline = context.pipeline(); if (detectSsl && SslHandler.isEncrypted(buffer)) { SSLEngine engine = SSL_SERVER_CONTEXT.get().newEngine(context.alloc()); engine.setUseClientMode(false); pipeline.addLast(new SslHandler(engine), new ChunkedWriteHandler(), new PortUnificationServerHandler(delegatingHttpRequestHandler, false, detectGzip)); } else { int magic1 = buffer.getUnsignedByte(buffer.readerIndex()); int magic2 = buffer.getUnsignedByte(buffer.readerIndex() + 1); if (detectGzip && magic1 == 31 && magic2 == 139) { pipeline.addLast(ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP), ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP), new PortUnificationServerHandler(delegatingHttpRequestHandler, detectSsl, false)); } else if (isHttp(magic1, magic2)) { NettyUtil.addHttpServerCodec(pipeline); pipeline.addLast("delegatingHttpHandler", delegatingHttpRequestHandler); Logger logger = Logger.getInstance(BuiltInServer.class); if (logger.isDebugEnabled()) { pipeline.addLast(new ChannelOutboundHandlerAdapter() { @Override public void write(ChannelHandlerContext context, Object message, ChannelPromise promise) throws Exception { if (message instanceof HttpResponse response) { logger.debug("OUT HTTP: " + response); } super.write(context, message, promise); } }); } } else if (magic1 == 'C' && magic2 == 'H') { buffer.skipBytes(2); pipeline.addLast(new CustomHandlerDelegator()); } else { Logger.getInstance(BuiltInServer.class).warn("unknown request, first two bytes " + magic1 + " " + magic2); context.close(); } } // must be after new channels handlers addition (netty bug?) pipeline.remove(this); // Buffer will be automatically released after messageReceived, but we pass it to next handler, and next handler will also release, so, we must retain. // We can introduce Decoder.isAutoRelease, but in this case, if error will be thrown while we are executing, buffer will not be released. // So, it is robust solution just always release (Decoder does) and just retain (we - client) if autorelease behavior is not suitable. buffer.retain(); // we must fire channel read - new added handler must read buffer context.fireChannelRead(buffer); }