2013-06-02 33 views
1

我正尝试使用java和jetty创建代理服务器。我已经管理连接到http(非安全的),但https有问题。在Java中使用SSL的HTTP代理

我一直在做的是:

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; 
} 

我的问题是:

  1. 的代码是不工作(Error code: ssl_error_rx_record_too_long)
  2. 当是关闭套接字连接,和什么类型要使用的套接字。

在此先感谢。

更新的代码:

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; 
} 
+0

下面是我们在Jetty 9中发布的一个:http://download.eclipse.org/jetty/stable-9/xref/org/eclipse/jetty/proxy/ProxyServlet.html –

回答

2

我已经使用由码头提供的ConnectHandler解决了我的连接问题。

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

此代码解决了Https + Http连接问题。我也可以使用身份验证。

1

你不能写一个正确的代理服务器作为一个Servlet,对于一些原因。首先,您引入了太多的延迟,因为在创建上游连接之前,请求是由servlet容器完全组装的。

HTTP代理是一件非常简单的事情,除非您需要查看请求和响应。您只需解析传入的CONNECT命令,形成上游连接,然后开始同时在两个方向复制字节。无论上游连接是HTTP还是HTTPS,代码都是相同的。

为了回答您的具体问题:

  1. 你应该从每一个同行,直到收到EOS阅读。此时您应该关闭套接字到另一个对等端进行输出。如果您已经关闭了套接字,那么您应该关闭两个套接字。

  2. 明文。传入的HTTP CONNECT命令始终处于明文状态,并且您不关心上游连接是什么,因为您只是复制字节。如果有必要的话,同行会协商SSL,但这与你无关。

+0

你是什么意思'关机你的套接字到其他同行的输出'你能否澄清。示例代码? – progrrammer

+0

'Socket.shutdownOutput()'。 – EJP

+0

而我正在使用处理程序作为码头中的代理。好吗 ? – progrrammer