2011-02-01 5 views
1

Я несколько раз пытаюсь использовать несколько разных методов, чтобы заставить мой пользовательский прокси работать, и единственным способом, которым я был до сих пор, является использование HttpClient от Apache. Однако, ради познания, я задавался вопросом, почему у меня возникают проблемы с моей собственной реализации прокси-ручки ниже:Проблемы с входным/выходным потоком прокси в Java


public void processProxyRequest (Socket client, String request) throws Exception { 

     if (!request.equals("")) { 

      String[] requestHeaders = request.split("\\r\\n"); 
      Pattern p = Pattern.compile("([A-Z]*)\\s*([^:\\/]*):\\/\\/([^\\s]*)\\s*(?:HTTP.*)"); 
      Matcher m = p.matcher(requestHeaders[0]); 

      if (m.matches()) { 
       String method = m.group(1).toUpperCase(); 
       String proto = m.group(2).toLowerCase(); 
       String[] requestInfo = m.group(3).split("\\/", 2); 

       String host = requestInfo[0]; 
       host = (host.split("\\.").length < 3) ? "www." + host : host; 
       String page = "/"; 
       if (requestInfo.length == 2 && !requestInfo[1].equals("")) { 
        page += requestInfo[1]; 
       } 

       int remotePort = 80; 

       if (proto.equals("https")) { 
        remotePort = 443; 
       } 
       else if (proto.equals("ftp")) { 
        remotePort = 21; 
       } 
       this.sendAndReceive(client, request, host, remotePort); 
      } 
     } 

    } 

    public void sendAndReceive (Socket client, String request, String host, int port) throws Exception { 
     Socket target = new Socket(host, port); 
     System.out.println("Connected to server"); 

     ByteArrayInputStream inStream = new ByteArrayInputStream(request.getBytes()); 

     this.inToOut(inStream, target.getOutputStream()); 
     System.out.println("Sent"); 
     this.inToOut(target.getInputStream(), client.getOutputStream()); 
     System.out.println("Received"); 
     target.close(); 
    } 

    public void inToOut (InputStream input, OutputStream output) throws IOException { 
     byte[] buffer = new byte[1024]; // Adjust if you want 
     int bytesRead; 
     System.out.println("reading"); 
     while ((bytesRead = input.read(buffer)) != -1) { 
      output.write(buffer, 0, bytesRead); 
     } 
    } 

В двух словах (и игнорируя мой заголовок запроса синтаксического анализа недостатков), приведенный выше код компилируется и однако, метод inToOut(), похоже, немного борется и блокируется во время ввода.read(), и я не слишком уверен в этом. Я действительно знаю, что исходный сокет, который я передаю, действителен и открыт без ошибок. Кроме того, System.out в функции inToOut() печатает «чтение», но никогда не проходит мимо части read().

Благодарим за любые предложения!

ответ

1

Это не способ написать прокси. В случае HTTP вам нужно обработать только первую строку, которая сообщает целевому узлу. Все остальное просто копирует байты взад и вперед, подчиняясь нескольким небольшим уточнениям, таким как сообщения о восходящем соединении ошибок, корректно обрабатывающих выключения. Случай FTP сложнее, и его нужно обрабатывать отдельно, но снова, как только вы пройдете фазу подключения, он просто копирует байты. Чем меньше усилий вы пытаетесь понять протокол, тем проще и лучше.

+0

Я понимаю, поэтому строка запроса на самом деле уже передана в метод processRequest() для начала. Я сделал несколько дополнительных синтаксических разборок для более поздних функций регистрации, тогда как я хотел бы отслеживать определенные свойства заголовка запроса и ответа. Что касается «простого» копирования байтов взад и вперед, что, по-видимому, неверно в приведенном выше? Я был уверен, что это то, что я делал, копируя поток в потоке от клиента к выходному потоку цели, а затем от целевой в потоке к клиенту в потоке. И все же, никакого успеха. – jerluc

+0

Невозможно прокомментировать, не увидев код копирования. Если вы не используете NIO, вам нужно два потока на соединение, один для копирования в каждом направлении. Тот же код для обоих, конечно, они просто читают и записывают байты до EOS. – EJP

+0

Уже существует код, а именно метод 'inToOut()', который пытается скопировать байты из входного потока клиента в выходной поток целевого сервера. Конечно, я не смог разместить их в отдельных потоках, но сейчас я попытался использовать потоки, а затем попытался использовать NIO, но обе попытки, похоже, записывают данные на целевой сервер (для моих тестов просто google.com), но они всегда замерзают, когда пытаются прочитать ответ. – jerluc

0

В вашей sendAndReceive функции, возможно, попробуйте использовать DataInputStream и DataOutputStream

public void sendAndReceive (Socket client, String request, String host, int port) throws Exception { 
    Socket target = new Socket(host, port); 
    System.out.println("Connected to server"); 

    this.inToOut(new DataInputStream(client.getInputStream()), new DataOutputStream(target.getOutputStream())); 
    System.out.println("Sent"); 
    this.inToOut(new DataInputStream(target.getInputStream()), new DataOutputStream(client.getOutputStream())); 
    System.out.println("Received"); 
    target.close(); 
} 

Проблема не кажется, что в функции inToOut - Я попытался с помощью inToOut() и она отлично работает (это на самом деле помог мне исправить проблему, с которой я столкнулся с чем-то подобным - Спасибо)

Смежные вопросы