creating a Java Proxy Server that accepts HTTPS

前端 未结 3 1772
离开以前
离开以前 2020-12-13 16:43

i already have a working HTTP proxy server that can handle multiple HTTP request. now my problem is how do I handle https request?

here\'s a simplified code i am us

相关标签:
3条回答
  • 2020-12-13 17:08

    I finally got it.

    I only need to use normal socket and send a message to client that a connection is established. then proceed to tunneling.

    here is a working code:

    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 
                ...........
           }
    

    here's a good explanation on how proxy server handles CONNECT. http://curl.haxx.se/rfc/draft-luotonen-web-proxy-tunneling-01.txt

    0 讨论(0)
  • 2020-12-13 17:08

    Google "https server in java" and you may find a relevant tutorial, a related RFC and standard documentation. I hope this will help :).

    0 讨论(0)
  • 2020-12-13 17:10

    Please find below java code to create HTTPS proxy. It doesn't modify the response. To integrate it with HTTP write HTTP code in else clause. You can find HTTP code for proxy at a number of places.

    Basically what is happening is when the client sends an HTTPS request to proxy it comes with CONNECT keyword. You have to send HTTP/1.1 200 OK to client after establishing connection with upstream server. After that you have to supply client's incoming input stream without headers/host etc to upstream server and incoming stream from upstream server to client.

    You don't need to think about SSL at all.

    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");
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题