Java代理隧道HTTPS

时间:2015-07-12 07:36:21

标签: java sockets proxy

我正在使用Java构建代理服务器;服务器正确处理HTTP流量但无法正确隧道传输HTTPS流量。根据{{​​3}},进行以下过程:

1)我成功从包含要以纯文本连接的HOST的浏览器收到CONNECT消息。

2)我解析此消息以提取主机详细信息并成功建立与远程主机的连接。

3)然后我将HTTP / 1.0 200连接已建立的消息发送回客户端,然后立即尝试使用以下代码从连接的任一侧中继流量。

问题是在我返回上述200条消息而不是发送HTTPS数据后,浏览器似乎进入无限循环并继续向代理发送更多CONNECT消息。这是我用来在客户端和主机之间中继数据的代码:

 public static void stageTunnelledConnection(Socket clientSocket,Socket targetHostSocket) throws IOException{

     //set client socket read timeout to 2 seconds. The targethost connection will ALREADY have been
     //set to this value at the time this method is called.
     clientSocket.setSoTimeout(2000);

     InputStream[] socketInputStreamsArr = new InputStream[]{clientSocket.getInputStream(),targetHostSocket.getInputStream()};

     OutputStream[] socketOutputStreamsArr = new OutputStream[]{clientSocket.getOutputStream(),targetHostSocket.getOutputStream()};

     //holds current socket index to read from, this will be switched between the two sockets
     //at 0 and 1 indexes of the sockets array respectively.
     int curReadIndex = 0;
     //this will be set according to the "curReadIndex" value and will typically be
     //the logical NOT of that value; that is, where curReadIndex equals 0 the curWriteIndex to will equal 1 and visa versa.
     int curWriteIndex = 1; 
     while(true){

        try{

         //attempt to read from socket stream at current index and write
         //to the socket at the alternate index.
         byte[] dataBuff = new byte[2048];

         int bytesRead = 0;
         //we read into the dataBuff this operation will block for
         //a max of 2 seconds should no data be available to read
         while((bytesRead = socketInputStreamsArr[curReadIndex].read(dataBuff)) != -1){

            //ByteArrayInputStream bais = new ByteArrayInputStream(dataBuff);

            //BufferedReader br = new BufferedReader(new InputStreamReader(bais));

            //System.out.println(br.readLine());

            //write the buffer to the outputsteam at the index 
            //computed and stored to the "curWriteIndex" var above.
            socketOutputStreamsArr[curWriteIndex].write(dataBuff);
            socketOutputStreamsArr[curWriteIndex].flush();

             //System.out.println("Bytes read=".concat(String.valueOf(dataBuff)));
            //System.out.println("wroteBytes: "+bytesRead);

         }



        }

        catch(SocketTimeoutException ste){

         //we switch read/write index each time a read timeout error occurs. I.e 
         //were there is no further data to read from the socket at the currrent read index.
         if(ste.getMessage().contains("Read")){
         //System.out.println("Switching connection.");
         curReadIndex = (curReadIndex == 0) ? 1 : 0;
         curWriteIndex = (curReadIndex == 0) ? 1 : 0;
         }
         else{

            //clientSocket.close();
            //targetHostSocket.close();
            ste.printStackTrace();
         }

        }
        catch(SocketException ioe){

            //if an input/output exception occurs we must close both sockets
             clientSocket.close();
             targetHostSocket.close();

             ioe.printStackTrace();

        }



     }


 }

**重要提示:** 由于被隧道化的实际数据是加密的,因此对代理是不透明的,因此代理必须准备好随时从任何一方读/写。为了在单个线程中促进这个过程,我在两侧设置了一个相对较短的Socket Timeout(2秒)并进入一个循环,该循环交替显示每次迭代读取和写入的哪一侧,其中没有数据可用SocketTimeoutException发生被捕获,此时要切换读取的一侧并且循环继续执行。这个旨在从单个线程中的两个套接字读取的策略是否会导致问题?

1 个答案:

答案 0 :(得分:1)

socketOutputStreamsArr[curWriteIndex].write(dataBuff);

那应该是

socketOutputStreamsArr[curWriteIndex].write(dataBuff, 0, bytesRead);
  

为了在单个线程中促进此过程,我在两侧设置了一个相对较短的Socket Timeout(2秒)并进入一个循环,该循环交替显示每次迭代读取和写入的哪一侧,其中没有数据如果发生SocketTimeoutException,则会捕获,此时要切换读取的一侧并继续执行循环。这个旨在从单个线程中的两个套接字读取的策略是否会导致问题?

是。您应该使用两个线程或非阻塞NIO。否则你只是增加了许多不必要的延迟。

相关问题