创建接受HTTPS的Java代理服务器

时间:2012-02-20 07:28:38

标签: java ssl https proxy

我已经有了一个可以处理多个HTTP请求的HTTP代理服务器。现在我的问题是如何处理https请求?

这是我正在使用的简化代码:

class Daemon
{
    public static void main(String[] args)
    {
        ServerSocket cDaemonSocket = new ServerSocket(3128);

        while(true)
        {
          try
          {
             Socket ClientSocket = cDaemonSocket.accept();
             (new ClientHandler(ClientSocket )).start();
          }catch(Exception e) { }
        }
    }

}

和ClientHandler

class ClientHandler extends Thread
{
        private Socket socket = null;
        private Socket remoteSocket = null;
        private HTTPReqHeader request = null;
        ClientHandler(Socket socket)
        {
           this.socket = socket;
           request = new HTTPReqHeader();
           request.parse(socket); // I read and parse the HTTP request here
        }

       public void run()
       {
            if(!request.isSecure() )
            {
              remoteSocket = new Socket(request.url,request.port);
            }
            else
            {
              // now what should I do to established a secured socket?
            }

            // start connecting remoteSocket and clientSocket 
            ...........
       }
}

}

我确实尝试过如何搜索,我遇到过SSL隧道,证书,握手,SSLSocket,SSLFactory,trustStore等等类似的东西,但仍然无法使其工作..我只需要知道我是什么东西需要以及建立与启用SSL的Web服务器的连接的步骤。

3 个答案:

答案 0 :(得分:6)

我终于明白了。

我只需要使用普通套接字并向客户端发送建立连接的消息。然后进入隧道。

这是一个有效的代码:

private Socket socket = null;
        private Socket remoteSocket = null;
        private HTTPReqHeader request = null;
        ClientHandler(Socket socket)
        {
           this.socket = socket;
           request = new HTTPReqHeader();
           request.parse(socket); // I read and parse the HTTP request here
        }

       public void run()
       {

            remoteSocket = new Socket(request.url,request.port);

            if(request.isSecure() )
            {
                 // send ok message to client
                 String ConnectResponse = "HTTP/1.0 200 Connection established\n" +
                                          "Proxy-agent: ProxyServer/1.0\n" +
                                          "\r\n";
                try
                {
           DataOutputStream out =  new DataOutputStream(socket.getOutputStream());
                   out.writeByte(ConnectResponse);
                    out.flush();
                } catch(Exception e) {} 

            }

            // start connecting remoteSocket and clientSocket 
            ...........
       }

这里有一个很好的解释代理服务器如何处理CONNECT。 http://curl.haxx.se/rfc/draft-luotonen-web-proxy-tunneling-01.txt

答案 1 :(得分:3)

请在下面找到java代码来创建HTTPS代理。它不会修改响应。在else子句中将它与HTTP写入HTTP代码集成。您可以在许多地方找到代理的HTTP代码。

基本上发生的事情是当客户端向代理发送HTTPS请求时,它带有CONNECT关键字。在与上游服务器建立连接后,您必须向客户端发送HTTP / 1.1 200 OK。之后,您必须向上游服务器提供没有头/主机等的客户端传入输入流以及从上游服务器到客户端的传入流。

您根本不需要考虑SSL。

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created for http://stackoverflow.com/q/16351413/1266906.
 */
public class Server extends Thread {

    public static void main(String[] args) {
        (new Server()).run();
    }

    public Server() {
        super("Server Thread");
    }

    @Override
    public void run() {
        try (ServerSocket serverSocket = new ServerSocket(9999)) {
            Socket socket;
            try {
                while ((socket = serverSocket.accept()) != null) {
                    (new Handler(socket)).start();
                }
            } catch (IOException e) {
                e.printStackTrace();  // TODO: implement catch
            }
        } catch (IOException e) {
            e.printStackTrace();  // TODO: implement catch
            return;
        }
    }

    public static class Handler extends Thread {
        public static final Pattern CONNECT_PATTERN = Pattern.compile("CONNECT (.+):(.+) HTTP/(1\\.[01])",
                                                                      Pattern.CASE_INSENSITIVE);
        private final Socket clientSocket;
        private boolean previousWasR = false;

        public Handler(Socket clientSocket) {
            this.clientSocket = clientSocket;
        }

        @Override
        public void run() {
            try {
                String request = readLine(clientSocket);
                System.out.println(request);
                Matcher matcher = CONNECT_PATTERN.matcher(request);
                if (matcher.matches()) {
                    String header;
                    do {
                        header = readLine(clientSocket);
                    } while (!"".equals(header));
                    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(clientSocket.getOutputStream(),
                                                                                   "ISO-8859-1");

                    final Socket forwardSocket;
                    try {
                        forwardSocket = new Socket(matcher.group(1), Integer.parseInt(matcher.group(2)));
                        System.out.println(forwardSocket);
                    } catch (IOException | NumberFormatException e) {
                        e.printStackTrace();  // TODO: implement catch
                        outputStreamWriter.write("HTTP/" + matcher.group(3) + " 502 Bad Gateway\r\n");
                        outputStreamWriter.write("Proxy-agent: Simple/0.1\r\n");
                        outputStreamWriter.write("\r\n");
                        outputStreamWriter.flush();
                        return;
                    }
                    try {
                        outputStreamWriter.write("HTTP/" + matcher.group(3) + " 200 Connection established\r\n");
                        outputStreamWriter.write("Proxy-agent: Simple/0.1\r\n");
                        outputStreamWriter.write("\r\n");
                        outputStreamWriter.flush();

                        Thread remoteToClient = new Thread() {
                            @Override
                            public void run() {
                                forwardData(forwardSocket, clientSocket);
                            }
                        };
                        remoteToClient.start();
                        try {
                            if (previousWasR) {
                                int read = clientSocket.getInputStream().read();
                                if (read != -1) {
                                    if (read != '\n') {
                                        forwardSocket.getOutputStream().write(read);
                                    }
                                    forwardData(clientSocket, forwardSocket);
                                } else {
                                    if (!forwardSocket.isOutputShutdown()) {
                                        forwardSocket.shutdownOutput();
                                    }
                                    if (!clientSocket.isInputShutdown()) {
                                        clientSocket.shutdownInput();
                                    }
                                }
                            } else {
                                forwardData(clientSocket, forwardSocket);
                            }
                        } finally {
                            try {
                                remoteToClient.join();
                            } catch (InterruptedException e) {
                                e.printStackTrace();  // TODO: implement catch
                            }
                        }
                    } finally {
                        forwardSocket.close();
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();  // TODO: implement catch
            } finally {
                try {
                    clientSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();  // TODO: implement catch
                }
            }
        }

        private static void forwardData(Socket inputSocket, Socket outputSocket) {
            try {
                InputStream inputStream = inputSocket.getInputStream();
                try {
                    OutputStream outputStream = outputSocket.getOutputStream();
                    try {
                        byte[] buffer = new byte[4096];
                        int read;
                        do {
                            read = inputStream.read(buffer);
                            if (read > 0) {
                                outputStream.write(buffer, 0, read);
                                if (inputStream.available() < 1) {
                                    outputStream.flush();
                                }
                            }
                        } while (read >= 0);
                    } finally {
                        if (!outputSocket.isOutputShutdown()) {
                            outputSocket.shutdownOutput();
                        }
                    }
                } finally {
                    if (!inputSocket.isInputShutdown()) {
                        inputSocket.shutdownInput();
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();  // TODO: implement catch
            }
        }

        private String readLine(Socket socket) throws IOException {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            int next;
            readerLoop:
            while ((next = socket.getInputStream().read()) != -1) {
                if (previousWasR && next == '\n') {
                    previousWasR = false;
                    continue;
                }
                previousWasR = false;
                switch (next) {
                    case '\r':
                        previousWasR = true;
                        break readerLoop;
                    case '\n':
                        break readerLoop;
                    default:
                        byteArrayOutputStream.write(next);
                        break;
                }
            }
            return byteArrayOutputStream.toString("ISO-8859-1");
        }
    }
}

答案 2 :(得分:1)

Google“java中的https服务器”,您可能会发现a relevant tutoriala related RFCstandard documentation。我希望这会有所帮助:)。