简体   繁体   English

在Java中使用SSL的HTTP代理

[英]HTTP Proxy with SSL in java

I am trying to create a proxy server using java and jetty. 我正在尝试使用java和jetty创建代理服务器。 I've managet to connect to http (non secured one) but there is problem with https. 我已经设法连接到http(非安全的),但https存在问题。

What I've been doing is as: 我一直在做的是:

    private boolean handleConnect(HttpServletRequest req,HttpServletResponse response){
    String uri=req.getRequestURI();
    System.out.println("--Handle--Connect-");
    String port="";
    String host="";
    int c=uri.indexOf(":");
    if (c >= 0){
        port = uri.substring(c + 1);
        host = uri.substring(0,c);
        if (host.indexOf('/') > 0)
            host = host.substring(host.indexOf('/') + 1);
    }
    boolean isBlocked;
    isBlocked=false;
    SocketChannel sock = null;
    InputStream in=null;
    OutputStream out=null;
    try {
        sock = SocketChannel.open();
        in=req.getInputStream();
        out=response.getOutputStream();

    } catch (IOException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
    try{
         InetSocketAddress inetAddress = new InetSocketAddress(host,req.getRemotePort());
         sock.connect(inetAddress);
         InputStreamReader inputstreamreader = new InputStreamReader(req.getInputStream());
         BufferedReader bufferedreader = new BufferedReader(inputstreamreader);

         OutputStreamWriter outputstreamwriter = new OutputStreamWriter(sock.socket().getOutputStream());
         BufferedWriter bufferedwriter = new BufferedWriter(outputstreamwriter);
         response.setStatus(200);
         response.setHeader("Connection", req.getHeader("Connection"));
         String string = null;

         while ((string = bufferedreader.readLine()) != null) {
                bufferedwriter.write(string );
                bufferedwriter.flush();
         }


        sock.configureBlocking(false);
        sock.connect(new InetSocketAddress(host,Integer.parseInt(port)) );
        while(!sock.finishConnect()){
            // Wait for connecting
        }

            response.setStatus(200);
            response.setHeader("Connection", req.getHeader("Connection"));
            response.flushBuffer();

        ByteBuffer bb=ByteBuffer.allocate(1024*1024);
        bb.clear();
        in.mark(0);

        if(in.available()>0){

             byte by[]=new byte[in.available()];
             bb.put(by);
                if(sock.isConnected()){
                    sock.write(bb);
                }

        }

    }
    catch(Exception ex){
        ex.printStackTrace();
        isBlocked=true;
        try {
        //  sock.close();
            throw new IOException("Hello World");
        } catch (IOException e) {
            e.printStackTrace();
        }

        return false;
    }
    finally{
        try {
            out.close();
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return true;
}

My Questions are: 我的问题是:

  1. The code is not working (Error code: ssl_error_rx_record_too_long) 代码不起作用(Error code: ssl_error_rx_record_too_long)
  2. When is to close the socket connection, and what type of socket to use. 何时关闭套接字连接,以及使用什么类型的套接字。

Thanks in Advance. 提前致谢。

UPDATED CODE: 更新的代码:

private boolean handleConnect(HttpServletRequest req,HttpServletResponse response){
    String uri=req.getRequestURI();
    System.out.println("--Handle--Connect-");
    String port="";
    String host="";
    int c=uri.indexOf(":");
    if (c >= 0){
        port = uri.substring(c + 1);
        host = uri.substring(0,c);
        if (host.indexOf('/') > 0)
            host = host.substring(host.indexOf('/') + 1);
    }
    boolean isBlocked;
    isBlocked=false;
    Socket sock = null;
    IORedirect c2s, s2c;

    // Make Asyncronous connection
    try{
            sock=new Socket(host,Integer.parseInt(port));

            OutputStream os = response.getOutputStream();

            byte[] msg = new String("HTTP/1.0 200 Connection established\r\nProxy-agent: RPS-Proxy/1.0\r\n\r\n").getBytes();
            os.write(msg);
            os.flush();

            c2s=new IORedirect(req.getInputStream(),sock.getOutputStream());
            c2s.setName("Client to Server");
            c2s.start();
            Thread.sleep(500);

            s2c=new IORedirect(sock.getInputStream(), os);
            s2c.setName("Server to Client");
            s2c.start();
            Thread.sleep(500);
            System.err.println("A");

    }
    catch(Exception ex){
        ex.printStackTrace();
        isBlocked=true;
        try {
            sock.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }
    while(c2s.isAlive() || s2c.isAlive()){

    }
    try {
        sock.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return true;
}

I've Solved my connect problem by using ConnectHandler provided by jetty. 我通过使用ConnectHandler提供的ConnectHandler解决了我的连接问题。

    HandlerCollection coll=new HandlerCollection();
    ConnectHandler aa=new ConnectHandler();
    coll.addHandler(aa);
    server.addConnector(http);
    server.setHandler(coll);

This code solves Https + Http connection problem. 此代码解决了Https + Http连接问题。 And I can use authentication too. 我也可以使用身份验证。

You can't write a proper proxy as a Servlet, for a number of reasons. 出于多种原因,您无法将适当的代理编写为Servlet。 For one thing, you are introducing far too much latency, as the request is completely assembled by the servlet container before you get to create the upstream connection. 首先,您引入了太多的延迟,因为在创建上游连接之前,请求由servlet容器完全组装。

An HTTP proxy is a very simple thing, unless you need to look into the requests and responses. HTTP代理是一件非常简单的事情,除非您需要查看请求和响应。 All you have to do is parse the incoming CONNECT command, form the upstream connection, and then start copying bytes in both directions simultaneously. 您所要做的就是解析传入的CONNECT命令,形成上游连接,然后同时开始在两个方向上复制字节。 It doesn't matter whether the upstream connection is HTTP or HTTPS, the code is the same. 上游连接是HTTP还是HTTPS并不重要,代码是相同的。

To answer your specific questions: 回答您的具体问题:

  1. You should read from each peer until you receive EOS. 您应该从每个对等方读取,直到您收到EOS。 At that point you should shutdown the socket to the other peer for output. 此时,您应该将套接字关闭到另一个对等体以进行输出。 If you have already shutdown the socket you read the EOS from, you should then close both sockets. 如果您已经关闭了从中读取EOS的套接字,则应关闭两个套接字。

  2. Plaintext. 纯文本。 The incoming HTTP CONNECT command is always in plaintext, and you don't care what the upstream connection is, as you are just copying bytes. 传入的HTTP CONNECT命令始终是纯文本,并且您不关心上游连接是什么,因为您只是复制字节。 The peers will negotiate SSL if necessary, but that's nothing to do with you. 如有必要,对等方将协商SSL,但这与您无关。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM