Я занимаюсь созданием прокси-сервера на Java; сервер правильно обрабатывает HTTP-трафик, но не может правильно туннелировать HTTPS-трафик. В соответствии с проектом IETF выполняется следующий процесс:
1) Я успешно получаю сообщение CONNECT от браузера, которое содержит HOST для подключения в виде простого текста.
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();
}
}
}
**ВАЖНО: ** Поскольку фактические туннелируемые данные зашифрованы и, следовательно, непрозрачны для прокси-сервера, прокси-сервер должен быть готов к чтению/записи с любой стороны в любое время. Чтобы облегчить этот процесс в одном потоке, я устанавливаю относительно короткий тайм-аут сокета (2 секунды) с обеих сторон и вхожу в цикл, который чередует, с какой стороны он читает и записывает на каждой итерации, где нет доступных данных SocketTimeoutException происходит перехват, в этот момент переключается сторона для чтения, и цикл продолжает выполняться. Может ли эта стратегия, направленная на чтение из двух сокетов в одном потоке, вызывать проблему?