netty / netty

Netty project - an event-driven asynchronous network application framework
http://netty.io
Apache License 2.0
33.3k stars 15.89k forks source link

Can not get http response when use ChannelOption.AUTO_READ=false and HttpClientCodec #1489

Closed xmxsuperstar closed 11 years ago

xmxsuperstar commented 11 years ago

When I use netty4 CR6 to download file from http server, I try to do some traffic control by using ChannelOption.AUTO_READ=false and read() opereation, but seems that the client hungs when read server response

My code: main class:

package com.xx_dev.apn.proxy.testclient;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;

import javax.xml.parsers.FactoryConfigurationError;
import java.io.File;
import java.net.MalformedURLException;

public class TestHttpClient {

    private static final Logger logger = Logger.getLogger(TestHttpClient.class);

    private final String host;
    private final int port;

    public TestHttpClient(String host, int port) {
        this.host = host;
        this.port = port;
    }

    public void run() throws Exception {
        // Configure the client.
        Bootstrap b = new Bootstrap();
        NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
        try {
            b.group(eventLoopGroup).channel(NioSocketChannel.class).option(ChannelOption.AUTO_READ, false)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel channel) throws Exception {
                            ChannelPipeline pipeline = channel.pipeline();

                            pipeline.addLast(new LoggingHandler("LOGGER", LogLevel.INFO));

                            pipeline.addLast("codec", new HttpClientCodec());

                            pipeline.addLast("handler", new TestHttpClientHandler());
                        }
                    });

            // Start the client.
            ChannelFuture f = b.connect(host, port);
            f.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if(logger.isInfoEnabled()) {
                        logger.info("connect complete");
                    }
                    future.channel().read();
                }
            });
            f.sync();
            // Wait until the connection is closed.
            f.channel().closeFuture().await();
        } finally {
            // Shut down the event loop to terminate all threads.
            eventLoopGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        new TestHttpClient("img4.cache.netease.com", 80).run();
        // new TestHttpClient("localhost", 8888).run();
    }
}

handler:

package com.xx_dev.apn.proxy.testclient;

import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.MessageList;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpVersion;
import org.apache.log4j.Logger;

public class TestHttpClientHandler extends ChannelInboundHandlerAdapter {

    private static final Logger logger = Logger.getLogger(TestHttpClientHandler.class);

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        logger.info("client channel active");
        DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET,
                "/photo/0025/2013-04-26/s_8TCLN6TM0APS0025.jpg");
        request.headers().add("HOST", "img4.cache.netease.com");
        ctx.write(request).addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                logger.info("request write complete");
                future.channel().read();
            }
        });

    }

    @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageList<Object> msgs) throws Exception {
        logger.info(msgs);
        for (Object msg : msgs) {
            if (msg instanceof HttpResponse) {
                logger.info(((HttpResponse) msg).toString());
            }

            if (msg instanceof HttpContent) {
                logger.info(msg.toString() + ((HttpContent) msg).content().readableBytes());
            }
        }
        msgs.releaseAllAndRecycle();
        ctx.read();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // Close the connection when an exception is raised.
        logger.error(cause.getMessage(), cause);
        ctx.close();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        logger.info("client channel inactive");
    }

}

and the log is:

"D:\Program Files\java\jdk1.7.0_17\bin\java" -Didea.launcher.port=7532 "-Didea.launcher.bin.path=D:\Program Files\JetBrains\IntelliJ IDEA Community Edition 12.1.4\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\java\jdk1.7.0_17\jre\lib\charsets.jar;D:\Program Files\java\jdk1.7.0_17\jre\lib\deploy.jar;D:\Program Files\java\jdk1.7.0_17\jre\lib\javaws.jar;D:\Program Files\java\jdk1.7.0_17\jre\lib\jce.jar;D:\Program Files\java\jdk1.7.0_17\jre\lib\jfr.jar;D:\Program Files\java\jdk1.7.0_17\jre\lib\jfxrt.jar;D:\Program Files\java\jdk1.7.0_17\jre\lib\jsse.jar;D:\Program Files\java\jdk1.7.0_17\jre\lib\management-agent.jar;D:\Program Files\java\jdk1.7.0_17\jre\lib\plugin.jar;D:\Program Files\java\jdk1.7.0_17\jre\lib\resources.jar;D:\Program Files\java\jdk1.7.0_17\jre\lib\rt.jar;D:\Program Files\java\jdk1.7.0_17\jre\lib\ext\access-bridge.jar;D:\Program Files\java\jdk1.7.0_17\jre\lib\ext\dnsns.jar;D:\Program Files\java\jdk1.7.0_17\jre\lib\ext\jaccess.jar;D:\Program Files\java\jdk1.7.0_17\jre\lib\ext\localedata.jar;D:\Program Files\java\jdk1.7.0_17\jre\lib\ext\sunec.jar;D:\Program Files\java\jdk1.7.0_17\jre\lib\ext\sunjce_provider.jar;D:\Program Files\java\jdk1.7.0_17\jre\lib\ext\sunmscapi.jar;D:\Program Files\java\jdk1.7.0_17\jre\lib\ext\sunpkcs11.jar;D:\Program Files\java\jdk1.7.0_17\jre\lib\ext\zipfs.jar;D:\workspace\apn-proxy\target\classes;E:\.m2\repository\io\netty\netty-all\4.0.0.CR6\netty-all-4.0.0.CR6.jar;E:\.m2\repository\commons-beanutils\commons-beanutils\1.8.3\commons-beanutils-1.8.3.jar;E:\.m2\repository\commons-logging\commons-logging\1.1.1\commons-logging-1.1.1.jar;E:\.m2\repository\commons-lang\commons-lang\2.5\commons-lang-2.5.jar;E:\.m2\repository\commons-collections\commons-collections\3.2.1\commons-collections-3.2.1.jar;E:\.m2\repository\commons-codec\commons-codec\1.4\commons-codec-1.4.jar;E:\.m2\repository\commons-io\commons-io\1.4\commons-io-1.4.jar;E:\.m2\repository\commons-pool\commons-pool\1.5.4\commons-pool-1.5.4.jar;E:\.m2\repository\commons-dbcp\commons-dbcp\1.4\commons-dbcp-1.4.jar;E:\.m2\repository\commons-fileupload\commons-fileupload\1.2.2\commons-fileupload-1.2.2.jar;E:\.m2\repository\log4j\log4j\1.2.16\log4j-1.2.16.jar;E:\.m2\repository\net\sf\json-lib\json-lib\2.4\json-lib-2.4-jdk15.jar;E:\.m2\repository\net\sf\ezmorph\ezmorph\1.0.6\ezmorph-1.0.6.jar;E:\.m2\repository\xom\xom\1.2.5\xom-1.2.5.jar;E:\.m2\repository\xml-apis\xml-apis\1.3.03\xml-apis-1.3.03.jar;E:\.m2\repository\xerces\xercesImpl\2.8.0\xercesImpl-2.8.0.jar;E:\.m2\repository\xalan\xalan\2.7.0\xalan-2.7.0.jar;E:\.m2\repository\org\bouncycastle\bcprov-jdk15\1.46\bcprov-jdk15-1.46.jar;E:\.m2\repository\net\sf\ehcache\ehcache-core\2.6.0\ehcache-core-2.6.0.jar;E:\.m2\repository\org\slf4j\slf4j-api\1.6.1\slf4j-api-1.6.1.jar;D:\Program Files\JetBrains\IntelliJ IDEA Community Edition 12.1.4\lib\idea_rt.jar" com.intellij.rt.execution.application.AppMain com.xx_dev.apn.proxy.testclient.TestHttpClient
2013-06-27 13:56:19,521 main io.netty.util.internal.logging.InternalLoggerFactory DEBUG -: Using Log4J as the default logging framework
2013-06-27 13:56:19,527 main io.netty.channel.MultithreadEventLoopGroup DEBUG -: io.netty.eventLoopThreads: 4
2013-06-27 13:56:19,533 main io.netty.util.internal.PlatformDependent DEBUG -: Platform: Windows
2013-06-27 13:56:19,533 main io.netty.util.internal.PlatformDependent DEBUG -: Java version: 7
2013-06-27 13:56:19,535 main io.netty.util.internal.PlatformDependent0 DEBUG -: java.nio.ByteBuffer.cleaner: available
2013-06-27 13:56:19,535 main io.netty.util.internal.PlatformDependent0 DEBUG -: java.nio.Buffer.address: available
2013-06-27 13:56:19,535 main io.netty.util.internal.PlatformDependent0 DEBUG -: sun.misc.Unsafe.theUnsafe: available
2013-06-27 13:56:19,535 main io.netty.util.internal.PlatformDependent0 DEBUG -: sun.misc.Unsafe.copyMemory: available
2013-06-27 13:56:19,536 main io.netty.util.internal.PlatformDependent0 DEBUG -: java.nio.Bits.unaligned: true
2013-06-27 13:56:19,536 main io.netty.util.internal.PlatformDependent DEBUG -: sun.misc.Unsafe: available
2013-06-27 13:56:19,536 main io.netty.util.internal.PlatformDependent DEBUG -: Javassist: unavailable
2013-06-27 13:56:19,537 main io.netty.util.internal.PlatformDependent  INFO -: You don't have Javassist in your class path or you don't have enough permission to load dynamically generated classes.  Please check the configuration for better performance.
2013-06-27 13:56:19,537 main io.netty.util.internal.PlatformDependent DEBUG -: io.netty.noPreferDirect: false
2013-06-27 13:56:19,557 main io.netty.channel.nio.NioEventLoop DEBUG -: io.netty.noKeySetOptimization: false
2013-06-27 13:56:19,557 main io.netty.channel.nio.NioEventLoop DEBUG -: io.netty.selectorAutoRebuildThreshold: 512
2013-06-27 13:56:19,629 main io.netty.buffer.PooledByteBufAllocator DEBUG -: io.netty.allocator.numHeapArenas: 2
2013-06-27 13:56:19,630 main io.netty.buffer.PooledByteBufAllocator DEBUG -: io.netty.allocator.numDirectArenas: 2
2013-06-27 13:56:19,630 main io.netty.buffer.PooledByteBufAllocator DEBUG -: io.netty.allocator.pageSize: 8192
2013-06-27 13:56:19,630 main io.netty.buffer.PooledByteBufAllocator DEBUG -: io.netty.allocator.maxOrder: 11
2013-06-27 13:56:19,630 main io.netty.buffer.PooledByteBufAllocator DEBUG -: io.netty.allocator.chunkSize: 16777216
2013-06-27 13:56:19,671 nioEventLoopGroup-2-1 io.netty.util.ResourceLeakDetector DEBUG -: io.netty.noResourceLeakDetection: false
2013-06-27 13:56:19,677 nioEventLoopGroup-2-1 LOGGER  INFO -: [id: 0x830b47db] REGISTERED
2013-06-27 13:56:19,678 nioEventLoopGroup-2-1 LOGGER  INFO -: [id: 0x830b47db] CONNECT(img4.cache.netease.com/183.136.195.50:80, null)
2013-06-27 13:56:19,693 nioEventLoopGroup-2-1 com.xx_dev.apn.proxy.testclient.TestHttpClient  INFO -: connect complete
2013-06-27 13:56:19,693 nioEventLoopGroup-2-1 LOGGER  INFO -: [id: 0x830b47db, /10.14.109.16:64387 => img4.cache.netease.com/183.136.195.50:80] ACTIVE
2013-06-27 13:56:19,693 nioEventLoopGroup-2-1 com.xx_dev.apn.proxy.testclient.TestHttpClientHandler  INFO -: client channel active
2013-06-27 13:56:19,716 nioEventLoopGroup-2-1 LOGGER  INFO -: [id: 0x830b47db, /10.14.109.16:64387 => img4.cache.netease.com/183.136.195.50:80] WRITE(1/1, 92B)
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 47 45 54 20 2f 70 68 6f 74 6f 2f 30 30 32 35 2f |GET /photo/0025/|
|00000010| 32 30 31 33 2d 30 34 2d 32 36 2f 73 5f 38 54 43 |2013-04-26/s_8TC|
|00000020| 4c 4e 36 54 4d 30 41 50 53 30 30 32 35 2e 6a 70 |LN6TM0APS0025.jp|
|00000030| 67 20 48 54 54 50 2f 31 2e 31 0d 0a 48 4f 53 54 |g HTTP/1.1..HOST|
|00000040| 3a 20 69 6d 67 34 2e 63 61 63 68 65 2e 6e 65 74 |: img4.cache.net|
|00000050| 65 61 73 65 2e 63 6f 6d 0d 0a 0d 0a             |ease.com....    |
+--------+-------------------------------------------------+----------------+
2013-06-27 13:56:19,717 nioEventLoopGroup-2-1 com.xx_dev.apn.proxy.testclient.TestHttpClientHandler  INFO -: request write complete
2013-06-27 13:56:19,741 nioEventLoopGroup-2-1 LOGGER  INFO -: [id: 0x830b47db, /10.14.109.16:64387 => img4.cache.netease.com/183.136.195.50:80] RECEIVED(1/1, 1024B)
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d |HTTP/1.1 200 OK.|
|00000010| 0a 53 65 72 76 65 72 3a 20 6e 67 69 6e 78 0d 0a |.Server: nginx..|
|00000020| 44 61 74 65 3a 20 4d 6f 6e 2c 20 32 34 20 4a 75 |Date: Mon, 24 Ju|
|00000030| 6e 20 32 30 31 33 20 31 31 3a 30 35 3a 35 34 20 |n 2013 11:05:54 |
|00000040| 47 4d 54 0d 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 |GMT..Content-Typ|
|00000050| 65 3a 20 69 6d 61 67 65 2f 6a 70 65 67 0d 0a 43 |e: image/jpeg..C|
|00000060| 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68 3a 20 34 |ontent-Length: 4|
|00000070| 30 38 35 0d 0a 4c 61 73 74 2d 4d 6f 64 69 66 69 |085..Last-Modifi|
|00000080| 65 64 3a 20 46 72 69 2c 20 32 36 20 41 70 72 20 |ed: Fri, 26 Apr |
|00000090| 32 30 31 33 20 30 32 3a 30 34 3a 31 34 20 47 4d |2013 02:04:14 GM|
|000000a0| 54 0d 0a 45 78 70 69 72 65 73 3a 20 46 72 69 2c |T..Expires: Fri,|
|000000b0| 20 32 33 20 41 75 67 20 32 30 31 33 20 31 31 3a | 23 Aug 2013 11:|
|000000c0| 30 35 3a 35 34 20 47 4d 54 0d 0a 43 61 63 68 65 |05:54 GMT..Cache|
|000000d0| 2d 43 6f 6e 74 72 6f 6c 3a 20 6d 61 78 2d 61 67 |-Control: max-ag|
|000000e0| 65 3d 35 31 38 34 30 30 30 0d 0a 58 5f 63 61 63 |e=5184000..X_cac|
|000000f0| 68 65 3a 20 48 49 54 20 66 72 6f 6d 20 77 65 62 |he: HIT from web|
|00000100| 2d 62 61 63 6b 65 6e 64 35 2e 63 68 61 6e 6e 65 |-backend5.channe|
|00000110| 6c 2e 63 6e 63 2e 62 6a 0d 0a 41 63 63 65 70 74 |l.cnc.bj..Accept|
|00000120| 2d 52 61 6e 67 65 73 3a 20 62 79 74 65 73 0d 0a |-Ranges: bytes..|
|00000130| 41 67 65 3a 20 32 34 30 36 32 35 0d 0a 50 6f 77 |Age: 240625..Pow|
|00000140| 65 72 65 64 2d 42 79 2d 43 68 69 6e 61 43 61 63 |ered-By-ChinaCac|
|00000150| 68 65 3a 20 48 49 54 20 66 72 6f 6d 20 30 31 30 |he: HIT from 010|
|00000160| 35 37 34 34 33 53 4d 0d 0a 0d 0a ff d8 ff e0 00 |57443SM.........|
|00000170| 10 4a 46 49 46 00 01 01 01 00 48 00 48 00 00 ff |.JFIF.....H.H...|
|00000180| db 00 43 00 04 02 03 03 03 02 04 03 03 03 04 04 |..C.............|
|00000190| 04 04 05 09 06 05 05 05 05 0b 08 08 06 09 0d 0b |................|
|000001a0| 0d 0d 0d 0b 0c 0c 0e 10 14 11 0e 0f 13 0f 0c 0c |................|
|000001b0| 12 18 12 13 15 16 17 17 17 0e 11 19 1b 19 16 1a |................|
|000001c0| 14 16 17 16 ff db 00 43 01 04 04 04 05 05 05 0a |.......C........|
|000001d0| 06 06 0a 16 0f 0c 0f 16 16 16 16 16 16 16 16 16 |................|
|000001e0| 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 |................|
|000001f0| 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 |................|
|00000200| 16 16 16 16 16 16 16 16 16 ff c0 00 11 08 00 4b |...............K|
|00000210| 00 64 03 01 22 00 02 11 01 03 11 01 ff c4 00 1c |.d.."...........|
|00000220| 00 00 01 05 01 01 01 00 00 00 00 00 00 00 00 00 |................|
|00000230| 00 05 00 03 04 06 07 02 08 01 ff c4 00 3a 10 00 |.............:..|
|00000240| 02 01 03 03 02 05 02 05 02 04 05 05 00 00 00 01 |................|
|00000250| 02 03 04 05 11 00 12 21 06 31 07 13 22 41 51 14 |.......!.1.."AQ.|
|00000260| 61 08 15 32 71 81 23 91 42 52 a1 f0 09 16 24 b1 |a..2q.#.BR....$.|
|00000270| d1 33 43 62 c1 e1 ff c4 00 1a 01 00 02 03 01 01 |.3Cb............|
|00000280| 00 00 00 00 00 00 00 00 00 00 00 01 02 03 04 05 |................|
|00000290| 00 06 ff c4 00 21 11 00 02 02 02 03 00 03 01 01 |.....!..........|
|000002a0| 00 00 00 00 00 00 00 00 01 02 11 03 21 04 12 31 |............!..1|
|000002b0| 22 41 71 61 13 ff da 00 0c 03 01 00 02 11 03 11 |"Aqa............|
|000002c0| 00 3f 00 e6 c5 e1 3f 40 f4 b7 84 9d 49 55 d6 16 |.?....?@....IU..|
|000002d0| 9b c5 c6 be d3 2d 3d 43 2a 8a 7f cc 22 a7 a8 46 |.....-=C*..."..F|
|000002e0| 89 0a c7 4f 5a eb 81 23 c3 26 e9 06 08 c6 03 02 |...OZ..#.&......|
|000002f0| 48 37 e0 a7 82 1e 18 df fc 09 b2 f5 4d df a6 1a |H7..........M...|
|00000300| e3 58 e2 69 26 9e aa ae a2 99 ea fc ba da c8 c4 |.X.i&...........|
|00000310| 40 79 cb 12 39 48 a3 50 17 04 1c 12 de fa c9 2d |@y..9H.P.......-|
|00000320| df 89 1e be 87 c4 64 ea b9 ad 7d 3f 5d 13 d2 9a |......d...}?]...|
|00000330| 2a ab 2a da 96 18 25 84 ac 41 50 91 fd 47 2b e5 |*.*...%..AP..G+.|
|00000340| 44 55 99 98 8d aa 07 19 07 be 9a f1 ea f1 62 e9 |DU............b.|
|00000350| 08 3a 78 f4 c5 96 58 e8 6a 22 9e 95 cd 45 52 38 |.:x...X.j"...ER8|
|00000360| 74 ac 9e ac 7e 99 14 ff 00 eb 4c 4f 04 12 ab 8c |t...~.....LO....|
|00000370| 9f 6c f9 3c 51 f9 34 6a c2 1c 87 a4 c3 dd 6b e0 |.l.<Q.4j......k.|
|00000380| 7f 48 2f 8a 37 0a 7a 28 a0 a3 b4 c3 d1 10 f5 4d |.H/.7.z(.......M|
|00000390| 45 25 25 f2 58 22 a5 44 85 04 b9 9b c8 ab 69 77 |E%%.X".D......iw|
|000003a0| 13 23 a8 5c e0 11 83 db 32 ff 00 12 5e 15 74 1d |.#.\....2...^.t.|
|000003b0| 8b a6 ee dd 53 d3 76 52 f4 f6 ab 4d 9e 37 89 2f |....S.vR...M.7./|
|000003c0| f3 13 13 55 00 cb 22 c3 25 27 ab 38 6c ff 00 58 |...U..".%'.8l..X|
|000003d0| 0c 31 3b 14 80 35 4e eb 8f 1c 7a 8a fd d7 97 5b |.1;..5N...z....[|
|000003e0| 8d 1d ba d5 1d d7 a9 7a 75 ac 37 36 a7 85 99 27 |.......zu.76...'|
|000003f0| 8a 44 45 69 4e 5c 85 90 22 2a fa 46 d0 00 e3 23 |.DEiN\.."*.F...#|
+--------+-------------------------------------------------+----------------+

the messageReceived method of TestHttpClientHandler never been invoked and no more server response can be recived

normanmaurer commented 11 years ago

@xmxsuperstar just fixed it in master. Can you verify ?

xmxsuperstar commented 11 years ago

It works now, thanks a lot!

xmxsuperstar commented 11 years ago

It seems that this issue occurs in netty4 final. The following is my test code for netty4 final:

package com.xx_dev.apn.proxy.testclient;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;

import javax.xml.parsers.FactoryConfigurationError;
import java.io.File;
import java.net.MalformedURLException;

public class TestHttpClient {

    private static final Logger logger = Logger.getLogger(TestHttpClient.class);

    private final String host;
    private final int port;

    public TestHttpClient(String host, int port) {
        this.host = host;
        this.port = port;
    }

    public void run() throws Exception {
        // Configure the client.
        Bootstrap b = new Bootstrap();
        NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
        try {
            b.group(eventLoopGroup).channel(NioSocketChannel.class).option(ChannelOption.AUTO_READ, false)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel channel) throws Exception {
                            ChannelPipeline pipeline = channel.pipeline();

                            pipeline.addLast(new LoggingHandler("LOGGER", LogLevel.INFO));

                            pipeline.addLast("codec", new HttpClientCodec());

                            pipeline.addLast("handler", new TestHttpClientHandler());
                        }
                    });

            // Start the client.
            ChannelFuture f = b.connect(host, port);
            f.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (logger.isInfoEnabled()) {
                        logger.info("connect complete");
                    }
                    future.channel().read();
                }
            });
            f.sync();
            // Wait until the connection is closed.
            f.channel().closeFuture().await();
        } finally {
            // Shut down the event loop to terminate all threads.
            eventLoopGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        new TestHttpClient("www.baidu.com", 80).run();
        // new TestHttpClient("localhost", 8888).run();
    }
}

and handler:

package com.xx_dev.apn.proxy.testclient;

import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.ReferenceCountUtil;
import org.apache.log4j.Logger;

public class TestHttpClientHandler extends ChannelInboundHandlerAdapter {

    private static final Logger logger = Logger.getLogger(TestHttpClientHandler.class);

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        logger.info("client channel active");
        DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET,
                "/");
        request.headers().add("HOST", "www.baidu.com");
        ctx.write(request).addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                logger.info("request write complete");
                future.channel().read();
            }
        });

    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        logger.info(msg);
        if (msg instanceof HttpResponse) {
            logger.info(((HttpResponse) msg).toString());
        }

        if (msg instanceof HttpContent) {
            logger.info(msg.toString() + ((HttpContent) msg).content().readableBytes());
        }

        ReferenceCountUtil.release(msg);
        ctx.read();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // Close the connection when an exception is raised.
        logger.error(cause.getMessage(), cause);
        ctx.close();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        logger.info("client channel inactive");
    }

}