HttpRequest using netty ChannelPool is always returning 400 response

39 views Asked by At

I'm trying to understand netty ChannelPool. I'm following the tutorial https://www.programmerall.com/article/74872253762/ to for that.

Below is the http URL that is working fine in curl cli.

curl --location 'https://httpbin.org/get'
{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Host": "httpbin.org",
    "User-Agent": "curl/8.1.2",
    "X-Amzn-Trace-Id": "Root=1-6500a506-7e7997ac222e1bc56e85a4e6"
  },
  "origin": "52.34.203.106",
  "url": "https://httpbin.org/get"
}

I modified the code in the above tutorial to invoke this service. Just the URL and host and port part of the ChannelPool.

Below is the complete code -


NettyClientHandler.java is  -

```java
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.util.CharsetUtil;
import java.util.concurrent.atomic.AtomicInteger;

public class NettyClientHandler extends ChannelInboundHandlerAdapter {
    static AtomicInteger count = new AtomicInteger(1);

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        FullHttpResponse response = (FullHttpResponse) msg;
        ByteBuf content = response.content();
        System.out.println(count.getAndIncrement()+": content:"+content.toString(CharsetUtil.UTF_8));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
    }
}

NettyChannelPoolHandler is -

import io.netty.channel.Channel;
import io.netty.channel.pool.ChannelPoolHandler;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpContentDecompressor;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.timeout.IdleStateHandler;

public class NettyChannelPoolHandler implements ChannelPoolHandler {
    @Override
    public void channelReleased(Channel channel) throws Exception {
        System.out.println("channelReleased. Channel ID:"+channel.id());
    }

    @Override
    public void channelAcquired(Channel channel) throws Exception {
        System.out.println("channelAcquired. Channel ID:"+channel.id());
    }

    @Override
    public void channelCreated(Channel channel) throws Exception {
        System.out.println("channelCreated. Channel ID:"+channel.id());
        SocketChannel socketChannel = (SocketChannel) channel;
        socketChannel.config().setKeepAlive(true);
        socketChannel.config().setTcpNoDelay(true);
        socketChannel.pipeline()
                .addLast(new HttpClientCodec())
                .addLast(new HttpObjectAggregator(1024 * 10 * 1024))
                .addLast(new HttpContentDecompressor())
                .addLast(new NettyClientHandler());
        channel.pipeline().addFirst(new IdleStateHandler(5, 5, 10));
    }
}

Finally the main program ChannelPoolDemo is -

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.pool.AbstractChannelPoolMap;
import io.netty.channel.pool.ChannelPoolMap;
import io.netty.channel.pool.FixedChannelPool;
import io.netty.channel.pool.SimpleChannelPool;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URL;
import java.nio.charset.Charset;

public class ChannelPoolDemo {
    final EventLoopGroup group = new NioEventLoopGroup();
    final Bootstrap bootstrap = new Bootstrap();
    ChannelPoolMap<InetSocketAddress, SimpleChannelPool> poolMap;

    public void build() throws Exception{
        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                //Connection timeout
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
                .option(ChannelOption.TCP_NODELAY,true)
                .option(ChannelOption.SO_KEEPALIVE,true)
                .handler(new LoggingHandler(LogLevel.ERROR));


        poolMap = new AbstractChannelPoolMap<InetSocketAddress, SimpleChannelPool>() {
            @Override
            protected SimpleChannelPool newPool(InetSocketAddress inetSocketAddress) {
                return new FixedChannelPool(bootstrap.remoteAddress(inetSocketAddress),new NettyChannelPoolHandler(),2);
            }
        };
    }

    public static void main(String[] args) {
        testHttp();
    }

    public static void testHttp(){
        try {
            ChannelPoolDemo client = new ChannelPoolDemo();
            client.build();
            String url = "https://httpbin.org/get";

            HttpRequest fullHttpRequest = buildRequest(url, true);
            SimpleChannelPool pool = client.poolMap.get(new InetSocketAddress("httpbin.org", 80));
            Future<Channel> f = pool.acquire();
            f.addListener((FutureListener<Channel>) f1->{
                if(f1.isSuccess()){
                    Channel ch = f1.getNow();
                    System.out.println(fullHttpRequest);
                    fullHttpRequest.headers().forEach(x -> System.out.println(x.getKey() + "\t" + x.getValue()));
                    ChannelFuture channelFuture = ch.writeAndFlush(fullHttpRequest);
                    channelFuture.addListener(new ChannelFutureListener() {
                        @Override
                        public void operationComplete(ChannelFuture future) {}
                    });
                    pool.release(ch);
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public static HttpRequest buildRequest(String url, boolean isKeepAlive) throws Exception {
        URL netUrl = new URL(url);
        URI uri = new URI(netUrl.getPath());
        System.out.println(uri.toASCIIString());
        DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri.toASCIIString());
        return request;
    }
}

when I run the program I get the below response always -

/get
request content:
channelCreated. Channel ID:76f0e7e9
channelAcquired. Channel ID:76f0e7e9
DefaultFullHttpRequest(decodeResult: success, version: HTTP/1.1, content: UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 0, cap: 0))
GET /get HTTP/1.1
channelReleased. Channel ID:76f0e7e9
1: content:<html>
<head><title>400 Bad Request</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
</body>
</html>

What is wrong with my program? Why it is always returning 404 when it works in curl?

I think probably I'm not correctly creating InetSocketAddress for ChannelPool correctly. How can I fix this?

0

There are 0 answers