diff --git a/vraptor-core/src/main/java/br/com/caelum/vraptor/VRaptor.java b/vraptor-core/src/main/java/br/com/caelum/vraptor/VRaptor.java index 5447b5acc..dd0376da2 100644 --- a/vraptor-core/src/main/java/br/com/caelum/vraptor/VRaptor.java +++ b/vraptor-core/src/main/java/br/com/caelum/vraptor/VRaptor.java @@ -104,7 +104,12 @@ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) final HttpServletRequest baseRequest = (HttpServletRequest) req; final HttpServletResponse baseResponse = (HttpServletResponse) res; - + + if (isWebsocketRequest(baseRequest)) { + chain.doFilter(req, res); + return; + } + if (staticHandler.requestingStaticFile(baseRequest)) { staticHandler.deferProcessingToContainer(chain, baseRequest, baseResponse); } else { @@ -172,4 +177,14 @@ private void validateIfCdiIsFound() throws ServletException { throw new ServletException("Dependencies were not set. Do you have a Weld/CDI listener setup in your web.xml?"); } } + + /** + * According to the Websocket spec (https://tools.ietf.org/html/rfc6455): The WebSocket Protocol + * 5. The request MUST contain an |Upgrade| header field whose value MUST include the "websocket" keyword. + */ + private boolean isWebsocketRequest(HttpServletRequest request) { + String upgradeHeader = request.getHeader("Upgrade"); + return upgradeHeader != null && upgradeHeader.toLowerCase().contains("websocket"); + } + } diff --git a/vraptor-core/src/test/java/br/com/caelum/vraptor/VRaptorTest.java b/vraptor-core/src/test/java/br/com/caelum/vraptor/VRaptorTest.java index cf994c886..726aacc9d 100644 --- a/vraptor-core/src/test/java/br/com/caelum/vraptor/VRaptorTest.java +++ b/vraptor-core/src/test/java/br/com/caelum/vraptor/VRaptorTest.java @@ -16,9 +16,12 @@ */ package br.com.caelum.vraptor; - import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; import javax.inject.Inject; import javax.servlet.FilterChain; @@ -39,8 +42,10 @@ public class VRaptorTest { @Rule public ExpectedException exception = ExpectedException.none(); - @Inject private VRaptor vRaptor; - @Inject private MockStaticContentHandler handler; + @Inject + private VRaptor vRaptor; + @Inject + private MockStaticContentHandler handler; @Test public void shoudlComplainIfNotInAServletEnviroment() throws Exception { @@ -52,7 +57,7 @@ public void shoudlComplainIfNotInAServletEnviroment() throws Exception { } @Test - public void shouldDeferToContainerIfStaticFile() throws Exception{ + public void shouldDeferToContainerIfStaticFile() throws Exception { HttpServletRequest request = mock(HttpServletRequest.class); HttpServletResponse response = mock(HttpServletResponse.class); FilterChain chain = mock(FilterChain.class); @@ -60,4 +65,20 @@ public void shouldDeferToContainerIfStaticFile() throws Exception{ vRaptor.doFilter(request, response, chain); assertThat(handler.isDeferProcessingToContainerCalled(), is(true)); } + + @Test + public void shouldBypassWebsocketRequests() throws Exception { + HttpServletRequest request = mock(HttpServletRequest.class); + HttpServletResponse response = mock(HttpServletResponse.class); + FilterChain chain = mock(FilterChain.class); + + when(request.getHeader("Upgrade")).thenReturn("Websocket"); + + vRaptor.doFilter(request, response, chain); + verify(request).getHeader("Upgrade"); + verify(chain).doFilter(request, response); + + verifyNoMoreInteractions(request, response); + } + }