How to write http proxy using netty

I want to write a simple program using netty to proxy an HTTP request from a browser. I think it can be divided into 3 steps.

  • receive request send by browser
  • send it to the website
  • Receive data from the website and send it back to the browser.

Question:

  • How to translate url to host and port when I use Bootstrap.connect (host, port);
  • When I use HttpServerResponseHandler.connect and ChannelHandlerContext.writeAndFlush (httpMessage); to send data to a website, how can I get response data from a website and send it back to the browser?

This is my first day studying netty, so please try to answer as easily as possible. Thank you very much.

public class Server {
    public static void main(String[] args) throws InterruptedException {
        final int port = 8888;

        // copy from https://github.com/netty/netty/wiki/User-guide-for-4.x
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new HttpRequestDecoder(), new HttpServerRequestHandler());
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            // Bind and start to accept incoming connections.
            ChannelFuture f = b.bind(port).sync();

            // Wait until the server socket is closed.
            // In this example, this does not happen, but you can do that to gracefully
            // shut down your server.
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
} 
 
public class HttpServerRequestHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        // step 1 get data from browser
        if (msg instanceof LastHttpContent) {
            ctx.close();
            return;
        }
        DefaultHttpRequest httpMessage = (DefaultHttpRequest) msg;
        System.out.println("浏览器请求====================");
        System.out.println(msg);
        System.out.println();
        doWork(ctx, httpMessage);
    }

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

    private void doWork(ChannelHandlerContext ctx, final DefaultHttpRequest msg) {
        // step 2 send data to website
        // translate url into host and port
        String host = msg.uri();
        int port = 80;
        if (host.startsWith("https://")) {
            host = host.replaceFirst("https://", "");
            port = 443;
        } else if (host.startsWith("http://")) {
            host = host.replaceFirst("http://", "");
            port = 80;
        }
        if (host.contains(":443")) {
            host = host.replace(":443", "");
            port = 443;
        }

        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(workerGroup);
            b.channel(NioSocketChannel.class);
            //b.option(ChannelOption.AUTO_READ, true);
            b.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new HttpServerResponseHandler(msg), new HttpRequestEncoder());
                }
            });

            // question 1
            ChannelFuture f = b.connect(host, port).sync();
            //ChannelFuture f = b.connect("www.baidu.com", 443).sync();
            f.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            workerGroup.shutdownGracefully();
        }
    }
}
public class HttpServerResponseHandler extends ChannelOutboundHandlerAdapter {

    private Object httpMessage;

    public HttpServerResponseHandler(Object o) {
        this.httpMessage = o;
    }


    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
        System.out.println("网页请求结果=========================");
        System.out.println(httpMessage);
        System.out.println();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)
        cause.printStackTrace();
        ctx.close();
    }

    @Override
    public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress,
                        SocketAddress localAddress, ChannelPromise promise) throws Exception {
        System.out.println("connect !!!!!!!!!!!");
        // question 2
        ctx.writeAndFlush(httpMessage);
    }
}
+4
1

, - Netty . , GitHub, . Netty - , .

(FYI, ).

:

- , , , . , . EventLoop, , , . , , Channel Channel.

URL-

, HttpObjectAggregator, HttpMessage HttpContents single FullHttpRequest FullHttpResponse ( , ). URL- : FullHttpRequest.setUri.

, Channel.remoteAddress() SocketAddress InetSocketAddress, . reset Host, .

( ) . . , .

+1

Source: https://habr.com/ru/post/1685463/


All Articles