2017-01-28 6 views
0

Моя цель - сделать простой HTTP-прокси, который может выполнять запросы GET/POST, пытаясь узнать о Java-сокетах. Было бы полезно, если кто-нибудь может указать мне в этом направлении.Извлечение содержимого из InputStream

// This example is from _Java Examples in a Nutshell_. (http://www.oreilly.com) 
// Copyright (c) 1997 by David Flanagan 
// This example is provided WITHOUT ANY WARRANTY either expressed or implied. 
// You may study, use, modify, and distribute it for non-commercial purposes. 
// For any commercial use, see http://www.davidflanagan.com/javaexamples 

import java.io.*; 
import java.net.*; 

/** 
* This class implements a simple single-threaded proxy server. 
**/ 
public class SimpleProxyServer { 
    /** The main method parses arguments and passes them to runServer */ 
    public static void main(String[] args) throws IOException { 
    try { 
     // Check the number of arguments 
     if (args.length != 3) 
     throw new IllegalArgumentException("Wrong number of arguments."); 

     // Get the command-line arguments: the host and port we are proxy for 
     // and the local port that we listen for connections on 
     String host = args[0]; 
     int remoteport = Integer.parseInt(args[1]); 
     int localport = Integer.parseInt(args[2]); 
     // Print a start-up message 
     System.out.println("Starting proxy for " + host + ":" + remoteport + 
         " on port " + localport); 
     // And start running the server 
     runServer(host, remoteport, localport); // never returns 
    } 
    catch (Exception e) { 
     System.err.println(e); 
     System.err.println("Usage: java SimpleProxyServer " + 
         "<host> <remoteport> <localport>"); 
    } 
    } 

    /** 
    * This method runs a single-threaded proxy server for 
    * host:remoteport on the specified local port. It never returns. 
    **/ 
    public static void runServer(String host, int remoteport, int localport) 
     throws IOException { 
    // Create a ServerSocket to listen for connections with 
    ServerSocket ss = new ServerSocket(localport); 

    // Create buffers for client-to-server and server-to-client communication. 
    // We make one final so it can be used in an anonymous class below. 
    // Note the assumptions about the volume of traffic in each direction... 
    final byte[] request = new byte[1024]; 
    byte[] reply = new byte[4096]; 

    // This is a server that never returns, so enter an infinite loop. 
    while(true) { 
     // Variables to hold the sockets to the client and to the server. 
     Socket client = null, server = null; 
     try { 
     // Wait for a connection on the local port 
     client = ss.accept(); 

     // Get client streams. Make them final so they can 
     // be used in the anonymous thread below. 
     final InputStream from_client = client.getInputStream(); 
     final OutputStream to_client= client.getOutputStream(); 

     // Make a connection to the real server 
     // If we cannot connect to the server, send an error to the 
     // client, disconnect, then continue waiting for another connection. 
     try { server = new Socket(host, remoteport); } 
     catch (IOException e) { 
      PrintWriter out = new PrintWriter(new OutputStreamWriter(to_client)); 
      out.println("Proxy server cannot connect to " + host + ":" + 
         remoteport + ":\n" + e); 
      out.flush(); 
      client.close(); 
      continue; 
     } 

     // Get server streams. 
     final InputStream from_server = server.getInputStream(); 
     final OutputStream to_server = server.getOutputStream(); 

     // Make a thread to read the client's requests and pass them to the 
     // server. We have to use a separate thread because requests and 
     // responses may be asynchronous. 
     Thread t = new Thread() { 
      public void run() { 
      int bytes_read; 
      try { 
       while((bytes_read = from_client.read(request)) != -1) { 
       to_server.write(request, 0, bytes_read); 
       to_server.flush(); 
       } 
      } 
      catch (IOException e) {} 

      // the client closed the connection to us, so close our 
      // connection to the server. This will also cause the 
      // server-to-client loop in the main thread exit. 
      try {to_server.close();} catch (IOException e) {} 
      } 
     }; 

     // Start the client-to-server request thread running 
     t.start(); 

     // Meanwhile, in the main thread, read the server's responses 
     // and pass them back to the client. This will be done in 
     // parallel with the client-to-server request thread above. 
     int bytes_read; 
     try { 
      while((bytes_read = from_server.read(reply)) != -1) { 
      to_client.write(reply, 0, bytes_read); 
      to_client.flush(); 
      } 
     } 
     catch(IOException e) {} 

     // The server closed its connection to us, so close our 
     // connection to our client. This will make the other thread exit. 
     to_client.close(); 
     } 
     catch (IOException e) { System.err.println(e); } 
     // Close the sockets no matter what happens each time through the loop. 
     finally { 
     try { 
      if (server != null) server.close(); 
      if (client != null) client.close(); 
     } 
     catch(IOException e) {} 
     } 
    } 
    } 
} 

код, полученный от http://examples.oreilly.com/jenut/SimpleProxyServer.java

мне было интересно, как я смог бы извлечь HOSTNAME из InputStream и использовать эту информацию, извлеченную перейти к описанному ниже методу.

 try { server = new Socket(host, remoteport); } 
     catch (IOException e) { 
      PrintWriter out = new PrintWriter(new OutputStreamWriter(to_client)); 
      out.println("Proxy server cannot connect to " + host + ":" + 
         remoteport + ":\n" + e); 
      out.flush(); 
      client.close(); 
      continue; 
     } 

Я попытался создать метод, который преобразует InputStream в формат строки, но, кажется, чтобы сделать программу застрять после присвоения его переменной. (Пробовал что-то вроде этого здесь - Read/convert an InputStream to a String)

+0

Если вы пытаетесь написать HTTP-прокси не начать здесь. Этот код работает с 1997 года и работает только для HTTP 1.0 без функции 'Connection: keepalive'. В любом случае это не способ написать HTTP-прокси. Вам нужно достаточно прочитать заголовки, чтобы определить цель, а затем просто скопировать байты в обоих направлениях одновременно. – EJP

+0

@EJP Что произойдет, если я не использую threading? Не будет ли это вообще работать? Или это будет просто медленным? – HelloWorld

+0

Это не сработает, если вы не напишете намного больше кода. Вам придется делать гораздо больше работы, анализируя заголовки и, возможно, контент, чтобы знать, где был конец запроса, а затем переключиться на получение ответа, а также узнать, где был конец ответа, а затем переключиться обратно для чтения другого запроса. Это слишком сложно. – EJP

ответ

1

Для получения информации от InputStream вы можете создать отдельный ByteArrayOutputStream.

... 
final OutputStream to_client= client.getOutputStream(); 
ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
... 

А затем в цикле в то время как вы можете написать baos а

... 
    while((bytes_read = from_server.read(reply)) != -1) { 
       to_client.write(reply, 0, bytes_read); 
       to_client.flush(); 
       baos.write(reply, 0, bytes_read); 
       } 
    baos.flush(); 
... 

И наконец, вы можете получить строку из baos.

String requestString = new String(baos.toByteArray()); 

Затем вы можете искать заголовок Host, делая это:

String[] headers = requestString.split("\n"); 
for (int i = 0; i < headers.length; i++) { 
    if (headers[i].startsWith("Host")) { 
     String[] hostHeader = headers[i].split(":"); 
     if (hostHeader.length > 1) { 
      host = hostHeader[1]; 
     } 
    } 
} 
+0

Я ищу специально для извлечения хоста/независимо от того, с кем клиент хочет подключиться: final InputStream from_client = client.getInputStream(); Но по какой-то причине, если я использую этот специфический InputStream и пытаюсь извлечь имя хоста, он зависает. – HelloWorld

+0

Я пробовал этот метод, по какой-то причине он все еще висит. – HelloWorld

+0

В какой строке он висит? – alayor