Jam*_*s G 5 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) { }
}
}
}
Run Code Online (Sandbox Code Playgroud)
和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
...........
}
}
Run Code Online (Sandbox Code Playgroud)
}
我确实尝试过搜索如何,我遇到过SSL隧道,证书,握手,SSLSocket,SSLFactory,trustStore等等.但仍然无法使其工作..我只需要知道我需要什么,以及建立与启用SSL的Web服务器的连接的步骤.
小智 7
请在下面找到创建 HTTPS 代理的 java 代码。它不会修改响应。要将其与 HTTP 集成,请在 else 子句中编写 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");
}
}
}
Run Code Online (Sandbox Code Playgroud)
我终于明白了.
我只需要使用普通套接字并向客户端发送建立连接的消息.然后进行隧道掘进.
这是一个有效的代码:
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
...........
}
Run Code Online (Sandbox Code Playgroud)
这里是代理服务器如何处理CONNECT的一个很好的解释. http://curl.haxx.se/rfc/draft-luotonen-web-proxy-tunneling-01.txt