Add SockJS path detection

This commit is contained in:
Rossen Stoyanchev
2013-05-05 20:51:37 -04:00
parent 97d225ba75
commit 7845ebc428
25 changed files with 654 additions and 133 deletions

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.socket;
import org.junit.Before;
import org.springframework.http.server.AsyncServletServerHttpRequest;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockHttpServletResponse;
/**
* @author Rossen Stoyanchev
*/
public class AbstractHttpRequestTests {
protected ServerHttpRequest request;
protected ServerHttpResponse response;
protected MockHttpServletRequest servletRequest;
protected MockHttpServletResponse servletResponse;
@Before
public void setUp() {
this.servletRequest = new MockHttpServletRequest();
this.servletResponse = new MockHttpServletResponse();
this.request = new AsyncServletServerHttpRequest(this.servletRequest, this.servletResponse);
this.response = new ServletServerHttpResponse(this.servletResponse);
}
protected void setRequest(String method, String requestUri) {
this.servletRequest.setMethod(method);
this.servletRequest.setRequestURI(requestUri);
}
protected void resetResponse() {
this.servletResponse = new MockHttpServletResponse();
this.response = new ServletServerHttpResponse(this.servletResponse);
}
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.socket.sockjs;
import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.socket.AbstractHttpRequestTests;
import org.springframework.web.socket.WebSocketHandler;
import static org.junit.Assert.*;
/**
* @author Rossen Stoyanchev
*/
public class AbstractSockJsServiceTests extends AbstractHttpRequestTests {
private TestSockJsService service;
private WebSocketHandler handler;
@Before
public void setUp() {
super.setUp();
this.service = new TestSockJsService(new ThreadPoolTaskScheduler());
}
@Test
public void getSockJsPath() throws Exception {
handleRequest("/echo", HttpStatus.OK);
assertEquals("Welcome to SockJS!\n", this.servletResponse.getContentAsString());
handleRequest("/echo/info", HttpStatus.OK);
assertTrue(this.servletResponse.getContentAsString().startsWith("{\"entropy\":"));
handleRequest("/echo/", HttpStatus.OK);
assertEquals("Welcome to SockJS!\n", this.servletResponse.getContentAsString());
handleRequest("/echo/iframe.html", HttpStatus.OK);
assertTrue(this.servletResponse.getContentAsString().startsWith("<!DOCTYPE html>\n"));
handleRequest("/echo/websocket", HttpStatus.OK);
assertNull(this.service.sessionId);
assertSame(this.handler, this.service.handler);
handleRequest("/echo/server1/session2/xhr", HttpStatus.OK);
assertEquals("session2", this.service.sessionId);
assertEquals(TransportType.XHR, this.service.transportType);
assertSame(this.handler, this.service.handler);
handleRequest("/echo/other", HttpStatus.NOT_FOUND);
handleRequest("/echo//", HttpStatus.NOT_FOUND);
handleRequest("/echo///", HttpStatus.NOT_FOUND);
}
@Test
public void getSockJsPathGreetingRequest() throws Exception {
handleRequest("/echo", HttpStatus.OK);
assertEquals("Welcome to SockJS!\n", this.servletResponse.getContentAsString());
}
@Test
public void getSockJsPathInfoRequest() throws Exception {
handleRequest("/echo/info", HttpStatus.OK);
assertTrue(this.servletResponse.getContentAsString().startsWith("{\"entropy\":"));
}
@Test
public void getSockJsPathWithConfiguredPrefix() throws Exception {
this.service.setValidSockJsPrefixes("/echo");
handleRequest("/echo/s1/s2/xhr", HttpStatus.OK);
}
@Test
public void getInfoOptions() throws Exception {
setRequest("OPTIONS", "/echo/info");
this.service.handleRequest(this.request, this.response, this.handler);
assertEquals(204, servletResponse.getStatus());
}
private void handleRequest(String uri, HttpStatus httpStatus) throws IOException {
resetResponse();
setRequest("GET", uri);
this.service.handleRequest(this.request, this.response, this.handler);
assertEquals(httpStatus.value(), this.servletResponse.getStatus());
}
private static class TestSockJsService extends AbstractSockJsService {
private String sessionId;
private TransportType transportType;
private WebSocketHandler handler;
public TestSockJsService(TaskScheduler scheduler) {
super(scheduler);
}
@Override
protected void handleRawWebSocketRequest(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler handler) throws IOException {
this.handler = handler;
}
@Override
protected void handleTransportRequest(ServerHttpRequest request,
ServerHttpResponse response, String sessionId,
TransportType transportType, WebSocketHandler handler)
throws IOException, TransportErrorException {
this.sessionId = sessionId;
this.transportType = transportType;
this.handler = handler;
}
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.socket.sockjs;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
/**
* @author Rossen Stoyanchev
*/
public class StubSockJsConfig implements SockJsConfiguration {
private int streamBytesLimit = 128 * 1024;
private long heartbeatTime = 25 * 1000;
private TaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
public int getStreamBytesLimit() {
return streamBytesLimit;
}
public void setStreamBytesLimit(int streamBytesLimit) {
this.streamBytesLimit = streamBytesLimit;
}
public long getHeartbeatTime() {
return heartbeatTime;
}
public void setHeartbeatTime(long heartbeatTime) {
this.heartbeatTime = heartbeatTime;
}
public TaskScheduler getTaskScheduler() {
return taskScheduler;
}
public void setTaskScheduler(TaskScheduler taskScheduler) {
this.taskScheduler = taskScheduler;
}
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.socket.sockjs;
import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.Delayed;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.Trigger;
/**
* @author Rossen Stoyanchev
*/
public class StubTaskScheduler implements TaskScheduler {
@Override
public ScheduledFuture schedule(Runnable task, Trigger trigger) {
return new StubScheduledFuture();
}
@Override
public ScheduledFuture schedule(Runnable task, Date startTime) {
return new StubScheduledFuture();
}
@Override
public ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period) {
return new StubScheduledFuture();
}
@Override
public ScheduledFuture scheduleAtFixedRate(Runnable task, long period) {
return new StubScheduledFuture();
}
@Override
public ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay) {
return new StubScheduledFuture();
}
@Override
public ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay) {
return new StubScheduledFuture();
}
private static class StubScheduledFuture extends FutureTask implements ScheduledFuture {
@SuppressWarnings("unchecked")
public StubScheduledFuture() {
super(new Callable() {
public Object call() throws Exception {
return null;
}
});
}
@Override
public long getDelay(TimeUnit unit) {
return 0;
}
@Override
public int compareTo(Delayed o) {
return 0;
}
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.socket.sockjs;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* @author Rossen Stoyanchev
*/
public class TransportTypeTests {
@Test
public void testFromValue() {
assertEquals(TransportType.WEBSOCKET, TransportType.fromValue("websocket"));
assertEquals(TransportType.XHR, TransportType.fromValue("xhr"));
assertEquals(TransportType.XHR_SEND, TransportType.fromValue("xhr_send"));
assertEquals(TransportType.JSONP, TransportType.fromValue("jsonp"));
assertEquals(TransportType.JSONP_SEND, TransportType.fromValue("jsonp_send"));
assertEquals(TransportType.XHR_STREAMING, TransportType.fromValue("xhr_streaming"));
assertEquals(TransportType.EVENT_SOURCE, TransportType.fromValue("eventsource"));
assertEquals(TransportType.HTML_FILE, TransportType.fromValue("htmlfile"));
}
}

View File

@@ -18,11 +18,13 @@ package org.springframework.web.socket.sockjs.support;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.socket.AbstractHttpRequestTests;
import org.springframework.web.socket.adapter.TextWebSocketHandlerAdapter;
import org.springframework.web.socket.sockjs.StubTaskScheduler;
import org.springframework.web.socket.sockjs.TransportHandler;
import org.springframework.web.socket.sockjs.TransportType;
import org.springframework.web.socket.sockjs.support.DefaultSockJsService;
import static org.junit.Assert.*;
@@ -32,14 +34,22 @@ import static org.junit.Assert.*;
*
* @author Rossen Stoyanchev
*/
public class DefaultSockJsServiceTests {
public class DefaultSockJsServiceTests extends AbstractHttpRequestTests {
private DefaultSockJsService service;
@Before
public void setUp() {
super.setUp();
this.service = new DefaultSockJsService(new StubTaskScheduler());
this.service.setValidSockJsPrefixes("/echo");
}
@Test
public void testDefaultTransportHandlers() {
public void defaultTransportHandlers() {
DefaultSockJsService sockJsService = new DefaultSockJsService(new ThreadPoolTaskScheduler());
Map<TransportType, TransportHandler> handlers = sockJsService.getTransportHandlers();
Map<TransportType, TransportHandler> handlers = service.getTransportHandlers();
assertEquals(8, handlers.size());
assertNotNull(handlers.get(TransportType.WEBSOCKET));
@@ -52,5 +62,21 @@ public class DefaultSockJsServiceTests {
assertNotNull(handlers.get(TransportType.EVENT_SOURCE));
}
@Test
public void xhrSend() throws Exception {
setRequest("POST", "/echo/000/c5839f69/xhr");
this.service.handleRequest(this.request, this.response, new TextWebSocketHandlerAdapter());
resetResponse();
setRequest("POST", "/echo/000/c5839f69/xhr_send");
this.servletRequest.setContent("[\"x\"]".getBytes("UTF-8"));
this.service.handleRequest(this.request, this.response, new TextWebSocketHandlerAdapter());
assertEquals(204, this.servletResponse.getStatus());
assertEquals("text/plain;charset=UTF-8", this.servletResponse.getContentType());
}
}