Просто интересно, кто-нибудь экспериментировал с прокси-сервером 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());
}
}
}
}
}
}
}