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

我已经有一个可以处理多个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服务器的连接的步骤。

我终于明白了。

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

这是一个有效的代码:

 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

请在下面找到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"); } } } 

谷歌“java中的https服务器”,您可以找到相关的教程 , 相关的RFC和标准文档 。 我希望这个能帮上忙 :)。