2014-02-13 3 views
9

Мне нужно уметь отключить подключение к веб-соединению во время рукопожатия, если запрос HTTP не соответствует определенным критериям. Насколько я понимаю, подходящее место для этого - внутри метода ServerEndpointConfig.Configurator.modifyHandshake() моей собственной реализации Configurator. Я просто не могу понять, что делать, чтобы прервать соединение. Есть параметр HandshakeResponse, который позволяет добавлять заголовки в ответ, но я не смог найти заголовок, который выполняет задание.JSR-356: Как прервать соединение веб-соединения во время рукопожатия?

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

ответ

1

вы правы, используйте'modifyHandShake() для обновления заголовков ответа, вам нужно точно, чтобы удалить или установить значение заголовка Sec-WebSocket-Accept, проверить это из the spec

| Sec-WebSocket -accept | заголовок поля указывает, будет ли сервер принимать соединение. Если присутствует, это поле заголовка должно содержать хэш не-отправителя клиента, отправленный в | Sec-WebSocket-Key | наряду с предопределенным GUID. Любое другое значение не должно интерпретироваться как принятие соединения сервером .

HTTP/1.1 101 Switching Protocols 
    Upgrade: websocket 
    Connection: Upgrade 
    Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= 

Эти поля проверяются клиентом WebSocket для скриптовых страниц. Если | Sec-WebSocket-Accept | значение не соответствует ожидаемому значению , если поле заголовка отсутствует, или если код состояния HTTP равен , а не 101, соединение не будет установлено, а кадры WebSocket не будут отправлены.

ваш код будет выглядеть следующим образом:

@Override 
public void modifyHandshake(ServerEndpointConfig sec, 
    HandshakeRequest request, HandshakeResponse response) { 
    super.modifyHandshake(sec, request, response); 
    response.getHeaders().put(HandshakeResponse.SEC_WEBSOCKET_ACCEPT, new ArrayList<String>()); 
} 

браузер будет интерпретировать это как сервер не принял подключение. например, в хроме я получаю сообщение

Ошибка при WebSocket рукопожатия

+0

это должно сработать, но только для более чистой реализации я бы предложил внедрить фильтр сервлета и проверить там запрос. –

+1

Привет @Leo, я уже пробовал этот подход раньше, но он не работает (по крайней мере, на Кот). Мне кажется, что код сервера устанавливает заголовок 'Sec-WebSocket-Accept' после вызова' modifyHandshake() '. При печати заголовков ответа внутри 'modifyHandshake()', как это: 'logger.info ("response.getHeaders() =>" + response.getHeaders());' Мы получаем это: 'ответ. getHeaders() => {} ' –

+0

ну, я тестировал его с wildfly, который использует swow, я полагаю, это может быть деталь реализации. – Leo

1

Я знаю - старый нить, но я не вижу каких-либо улучшений по этому поводу. Поэтому, возможно, кто-то может обсудить мое решение этой проблемы.

Я попробовал версию Леос, работает Wildfly 8.0, Undertow 1.0

final ArrayList<String> finalEmpty = new ArrayList<String>(); 
response.getHeaders().put(HandshakeResponse.SEC_WEBSOCKET_ACCEPT,finalEmpty); 

Это вызовет некоторое забавное поведение:

Даже если ваш браузер должен закрыть соединение, все они будут проходить через onOpen() процедуры ,

  • Хром: активирует onOpen(), затем триггеры onError(). В моем случае , я делаю некоторую регистрацию об отключенных клиентах, поэтому я всегда звоню onClose() при возникновении ошибки.
  • IE: Будет действовать как Chrome
  • Firefox: Firefox просто запустит процедуру onOpen(). И не будет запускать onError(). Поэтому ваш сервер даже не знает, что клиент отключен.

Не испортите свои заголовки и не позволяйте клиенту выполнять работу по плотности.

Вместо этого вы должны добавить данные аутентификации в конфигурацию.

/** some verification foo code...**/ 

config.getUserProperties().put("isValid",true); 

в onOpen() вы затем проверить для значения IsValid. Если это не так, вы вызываете onClose(session,null);. и сессия будет закрыта.

Это не лучшее решение, но это потому, что аутентификация websocket отстойна, и каждый браузер иногда действует по-разному. См.: Websocket: Closing browser triggers onError() in chrome but onClose() event in Firefox

2

Самый простой способ - установить простой веб-фильтр в вашем web.xml, который будет выполнен до установления связи.

Smth как:

public class MyHandshakeFilter implements Filter { 

@Override 
public void init(FilterConfig config) throws ServletException { 
    // do nothing 
} 

/** 
* Passes request to chain when request port is equal to specified in the allowedPort property 
* and returns HttpServletResponse.SC_NOT_FOUND in other case. 
*/ 
@Override 
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, 
     ServletException { 

    if (<your validation here based on http request>) { 
     // request conditions are met. continue handshake... 
     chain.doFilter(request, response); 
    } else { 
     // request conditions are NOT met. reject handshake... 
     ((HttpServletResponse) response).setStatus(HttpServletResponse.SC_FORBIDDEN); 
    } 
} 
} 

и в web.xml:

<filter> 
    <filter-name>yourHandshakeFilter</filter-name> 
    <filter-class>com....MyHandshakeFilter</filter-class> 
</filter> 
<filter-mapping> 
    <filter-name>yourHandshakeFilter</filter-name> 
    <url-pattern>/yourEndpointUrl</url-pattern> 
</filter-mapping> 

и ваш ServerEndpoint должен быть чем-л, как:

@ServerEndpoint("/yourEndpointUrl") 
public class MyServerEndpoint { 
... 
} 
+0

К сожалению, это не работает для меня (на Jetty 9.4) – fRoStBiT

1

Другой метод:

Когда молодежь row a RuntimeException от ServerEndpointConfig.Configurator#modifyHandshake, тогда соединение не установлено.

Это работает в Tomcat 8. Получил идею от Jetty example, поэтому я думаю, что она также работает в Jetty.

Смежные вопросы