Подтвердить что ты не робот

Прокси-сервер Jetty WebSocket

Просто интересно, кто-нибудь экспериментировал с прокси-сервером WebSocket (для прозрачного прокси-сервера) с помощью встроенного Jetty?

Примерно через полтора дня, играя с Jetty 9.1.2.v20140210, все, что я могу сказать, это то, что он не может проксировать WebSockets в своей текущей форме, а добавление такой поддержки - нетривиальная задача (по крайней мере, afaict).

В принципе, Jetty ProxyServlet удаляет поля заголовка "Обновление" и "Соединение" независимо от того, является ли он запросом на подтверждение WebSocket. Добавление этих полей назад легко, как показано ниже. Но, когда прокси-сервер вернул ответ с HTTP-кодом 101 (протоколы переключения), на прокси-сервере не выполняется обновление протокола. Итак, когда первый пакет WebSocket прибывает, HttpParser задыхается и видит это как плохой HTTP-запрос.

Если у кого-то уже есть решение для этого или знакомы с Jetty, чтобы предложить, что попробовать, это было бы очень оценено.

Ниже приведен код в моем эксперименте, удаляющий несущественные биты:

public class ProxyServer
{
    public static void main(String[] args) throws Exception
    {
        Server server = new Server();
        ServerConnector connector = new ServerConnector(server);
        connector.setPort(8888);
        server.addConnector(connector);

        // Setup proxy handler to handle CONNECT methods
        ConnectHandler proxy = new ConnectHandler();
        server.setHandler(proxy);

        // Setup proxy servlet
        ServletContextHandler context = new ServletContextHandler(proxy, "/", ServletContextHandler.SESSIONS);
        ServletHolder proxyServlet = new ServletHolder(MyProxyServlet.class);
        context.addServlet(proxyServlet, "/*");

        server.start();
    }
}

@SuppressWarnings("serial")
public class MyProxyServlet extends ProxyServlet
{
    @Override
    protected void customizeProxyRequest(Request proxyRequest, HttpServletRequest request)
    {
        // Pass through the upgrade and connection header fields for websocket handshake request. 
        String upgradeValue = request.getHeader("Upgrade");
        if (upgradeValue != null && upgradeValue.compareToIgnoreCase("websocket") == 0)
        {
            setHeader(proxyRequest, "Upgrade", upgradeValue);
            setHeader(proxyRequest, "Connection", request.getHeader("Connection"));
        }
    }

    @Override
    protected void onResponseHeaders(HttpServletRequest request, HttpServletResponse response, Response proxyResponse)
    {
        super.onResponseHeaders(request, response, proxyResponse);

        // Restore the upgrade and connection header fields for websocket handshake request.
        HttpFields fields = proxyResponse.getHeaders();
        for (HttpField field : fields)
        {
            if (field.getName().compareToIgnoreCase("Upgrade") == 0)
            {
                String upgradeValue = field.getValue();
                if (upgradeValue != null && upgradeValue.compareToIgnoreCase("websocket") == 0)
                {
                    response.setHeader(field.getName(), upgradeValue);
                    for (HttpField searchField : fields)
                    {
                        if (searchField.getName().compareToIgnoreCase("Connection") == 0) {
                            response.setHeader(searchField.getName(), searchField.getValue());
                        }
                    }
                }
            }
        }
    }
}
4b9b3361

Ответ 1

Представьте себе прокси-схему, которую вы пытаетесь построить, у нас есть клиент A, сервер B и прокси P. Теперь позвольте пройти через рабочий процесс connect: 1. A установлено TCP-соединение с прокси P (A-P) 2. A отправляет запрос CONNECT addr (B) с помощью рукопожатия WebSocket

Здесь у вас есть первая проблема: HTTP RFC заголовки, используемые в рукопожатии WS, не являются сквозными заголовками, потому что для HTTP они имеют смысл только на транспортном слое (между двумя прыжками).

  1. P устанавливает TCP-соединение с B (P-B)
  2. P отправляет HTTP-запрос WS handshake в B
  3. B отвечает обновления HTTP- > WS (путем отправки 101)

И вот еще одна проблема: после отправки HTTP 101 сервера B и клиент A теперь будет общаться только через TCP, но серфинг причал не поддерживает распространение простых пакетов TCP, Другими словами, servlet proxy servlet ждет, пока клиент A не начнет передавать HTTP-запрос, который никогда не произойдет после того, как A получит HTTP 101.

Вам нужно будет реализовать это самостоятельно, используя WS-сервер и WS-клиент.