Прокси-сервер Java HTTP/HTTPS

Я пишу свой собственный прокси-сервер Java. Когда я пытаюсь использовать его, у меня правильный вывод (я вижу все команды, которые проходят через прокси-сервер), но любой веб-сайт, который я хочу посетить, вообще не работает, и у меня есть следующая ошибка в моем браузере: ERR_TUNNEL_CONNECTION_FAILED . На самом деле я плохо разбираюсь в сетевых вопросах, и есть некоторые вещи, которых я не понимаю. Итак, мой код ниже, и я буду очень рад, если кто-нибудь скажет мне, в чем проблема:

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

public class ProxyServer
{
    private String host;
    private int localPort;
    private int remotePort;
    private ProxyServer(String host, int localPort, int remotePort)
    {
        this.host=host;
        this.localPort=localPort;
        this.remotePort=remotePort;
    }
    public static void main(String[] args) throws IOException
    {
        new ProxyServer("localhost", 8080, 9001).start();
    }
    public void start() throws IOException
    {
        System.out.println("Starting the proxy server for "+this.host+":"+this.localPort+"...");
        ServerSocket ss=new ServerSocket(this.localPort);
        final byte[] request=new byte[4096];
        byte[] response=new byte[4096];
        while(true)
        {
            Socket client=null;
            Socket server=null;
            try
            {
                client=ss.accept();
                final InputStream streamFromClient=client.getInputStream();
                OutputStream streamToClient=client.getOutputStream();
                System.out.println(new BufferedReader(new InputStreamReader(streamFromClient)).readLine());
                try
                {
                    server=new Socket(host, this.remotePort);
                }
                catch(IOException exc)
                {
                    PrintWriter out=new PrintWriter(streamToClient);
                    out.println("Proxy server cannot connect to "+host+":"+this.remotePort+"\n"+exc);
                    out.flush();
                    client.close();
                    continue;
                }
                InputStream streamFromServer=server.getInputStream();
                final OutputStream streamToServer=server.getOutputStream();
                System.out.println(new BufferedReader(new InputStreamReader(streamFromServer)).readLine());
                new Thread
                (
                    ()->
                    {
                        int bytesRead;
                        try
                        {
                            while((bytesRead=streamFromClient.read(request))!=-1)
                            {
                                streamToServer.write(request, 0, bytesRead);
                                streamToServer.flush();
                            }
                        }
                        catch(IOException exc){}
                        try
                        {
                            streamToServer.close();
                        }
                        catch(IOException exc){}
                    }
                ).start();
                int bytesRead;
                try
                {
                    while((bytesRead=streamFromServer.read(response))!=-1)
                    {
                        streamToClient.write(response, 0, bytesRead);
                        streamToClient.flush();
                    }
                }
                catch(IOException exc){}
                streamToClient.close();
            }
            catch(IOException exc)
            {
                System.out.println(exc.getMessage());
            }
            finally
            {
                try
                {
                    if(server!=null) server.close();
                    if(client!=null) client.close();
                }
                catch(IOException exc){}
            }
        }
    }
}

person mclich    schedule 27.11.2019    source источник


Ответы (1)


Вы сделали простой tcp-прокси с предопределенной целью: host:remote_port

Это не HTTP-прокси.

Итак, ваше решение должно работать в случае:

  1. вы используете squid или какой-либо правильный HTTP-прокси на локальном хосте: 9001.
  2. И используйте его только как HTTP-прокси (я имею в виду, что при настройке браузера вы не должны указывать ему, что ваше приложение является https-прокси).

Если вы планируете сделать автономный прокси, вам необходимо проанализировать HTTP-запрос и получить хост, порт и протокол из запроса, чтобы узнать, к какому серверу вы должны подключиться (включая порт) и какой протокол вы должны использовать (например, http или https). Когда браузер запрашивает службу напрямую (без прокси), он отправляет только URI, а когда браузер отправляет запрос через прокси, он использует полный URL-адрес в запросе.

поэтому первая строка в запросе будет примерно такой:

GET http://google.com[:80]/blah-blah-blah HTTP/1.1
...headers here...

Ваш прокси должен проанализировать URL-адрес и получить из него хост, порт и URI. Таким образом, вам нужно будет разрешить доменное имя и подключиться к хосту на требуемый порт с измененной первой строкой. Это будет выглядеть так:

GET /blah-blah-blah HTTP/1.1
...headers here...

И если вы используете дополнительный прокси-сервер http, который прослушивает порт 9001, проверьте, находится ли он в рабочем состоянии.

person Maxim Sagaydachny    schedule 29.11.2019