Enable cookie_needed by default in SockJS service

Issue: SPR-10939
This commit is contained in:
Rossen Stoyanchev 2013-09-26 12:39:09 -04:00
parent e756ef5923
commit 77fa8698b3
5 changed files with 46 additions and 78 deletions

View File

@ -44,7 +44,7 @@ public class SockJsServiceRegistration {
private Integer streamBytesLimit;
private Boolean sessionCookieEnabled;
private Boolean sessionCookieNeeded;
private Long heartbeatTime;
@ -105,14 +105,23 @@ public class SockJsServiceRegistration {
}
/**
* Some load balancers do sticky sessions, but only if there is a "JSESSIONID"
* cookie. Even if it is set to a dummy value, it doesn't matter since
* session information is added by the load balancer.
*
* <p>The default value is "false" since Java servers set the session cookie.
* The SockJS protocol requires a server to respond to the initial "/info" request
* from clients with a "cookie_needed" boolean property that indicates whether the use
* of a JSESSIONID cookie is required for the application to function correctly, e.g.
* for load balancing or in Java Servlet containers for the use of an HTTP session.
* <p>
* This is especially important for IE 8,9 that support XDomainRequest -- a modified
* AJAX/XHR -- that can do requests across domains but does not send any cookies. In
* those cases, the SockJS client prefers the "iframe-htmlfile" transport over
* "xdr-streaming" in order to be able to send cookies.
* <p>
* The default value is "true" to maximize the chance for applications to work
* correctly in IE 8,9 with support for cookies (and the JSESSIONID cookie in
* particular). However, an application can choose to set this to "false" if the use
* of cookies (and HTTP session) is not required.
*/
public SockJsServiceRegistration setDummySessionCookieEnabled(boolean sessionCookieEnabled) {
this.sessionCookieEnabled = sessionCookieEnabled;
public SockJsServiceRegistration setSessionCookieNeeded(boolean sessionCookieNeeded) {
this.sessionCookieNeeded = sessionCookieNeeded;
return this;
}
@ -201,8 +210,8 @@ public class SockJsServiceRegistration {
if (this.streamBytesLimit != null) {
service.setStreamBytesLimit(this.streamBytesLimit);
}
if (this.sessionCookieEnabled != null) {
service.setDummySessionCookieEnabled(this.sessionCookieEnabled);
if (this.sessionCookieNeeded != null) {
service.setSessionCookieNeeded(this.sessionCookieNeeded);
}
if (this.heartbeatTime != null) {
service.setHeartbeatTime(this.heartbeatTime);

View File

@ -77,7 +77,7 @@ public abstract class AbstractSockJsService implements SockJsService {
private int streamBytesLimit = 128 * 1024;
private boolean sessionCookieEnabled = false;
private boolean sessionCookieNeeded = true;
private long heartbeatTime = 25 * 1000;
@ -188,22 +188,35 @@ public abstract class AbstractSockJsService implements SockJsService {
}
/**
* Some load balancers do sticky sessions, but only if there is a "JSESSIONID"
* cookie. Even if it is set to a dummy value, it doesn't matter since
* session information is added by the load balancer.
*
* <p>The default value is "false" since Java servers set the session cookie.
* The SockJS protocol requires a server to respond to an initial "/info" request from
* clients with a "cookie_needed" boolean property that indicates whether the use of a
* JSESSIONID cookie is required for the application to function correctly, e.g. for
* load balancing or in Java Servlet containers for the use of an HTTP session.
* <p>
* This is especially important for IE 8,9 that support XDomainRequest -- a modified
* AJAX/XHR -- that can do requests across domains but does not send any cookies. In
* those cases, the SockJS client prefers the "iframe-htmlfile" transport over
* "xdr-streaming" in order to be able to send cookies.
* <p>
* The SockJS protocol also expects a SockJS service to echo back the JSESSIONID
* cookie when this property is set to true. However, when running in a Servlet
* container this is not necessary since the container takes care of it.
* <p>
* The default value is "true" to maximize the chance for applications to work
* correctly in IE 8,9 with support for cookies (and the JSESSIONID cookie in
* particular). However, an application can choose to set this to "false" if
* the use of cookies (and HTTP session) is not required.
*/
public void setDummySessionCookieEnabled(boolean sessionCookieEnabled) {
this.sessionCookieEnabled = sessionCookieEnabled;
public void setSessionCookieNeeded(boolean sessionCookieNeeded) {
this.sessionCookieNeeded = sessionCookieNeeded;
}
/**
* Whether setting JSESSIONID cookie is necessary.
* @see #setDummySessionCookieEnabled(boolean)
* Whether JSESSIONID cookie is required for the application to function. For
* more detail see {@link #setSessionCookieNeeded(boolean)}.
*/
public boolean isDummySessionCookieEnabled() {
return this.sessionCookieEnabled;
public boolean isSessionCookieNeeded() {
return this.sessionCookieNeeded;
}
/**
@ -506,7 +519,7 @@ public abstract class AbstractSockJsService implements SockJsService {
addCorsHeaders(request, response);
addNoCacheHeaders(response);
String content = String.format(INFO_CONTENT, random.nextInt(), isDummySessionCookieEnabled(), isWebSocketEnabled());
String content = String.format(INFO_CONTENT, random.nextInt(), isSessionCookieNeeded(), isWebSocketEnabled());
response.getBody().write(content.getBytes());
}
else if (HttpMethod.OPTIONS.equals(request.getMethod())) {

View File

@ -29,7 +29,6 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.ServerHttpRequest;
@ -306,11 +305,6 @@ public class DefaultSockJsService extends AbstractSockJsService {
addNoCacheHeaders(response);
}
if (transportType.sendsSessionCookie() && isDummySessionCookieEnabled()) {
String cookieValue = getJsessionIdCookieValue(request.getHeaders());
response.getHeaders().set("Set-Cookie", "JSESSIONID=" + cookieValue + ";path=/");
}
if (transportType.supportsCors()) {
addCorsHeaders(request, response);
}
@ -386,20 +380,6 @@ public class DefaultSockJsService extends AbstractSockJsService {
}, getDisconnectDelay());
}
private String getJsessionIdCookieValue(HttpHeaders headers) {
List<String> rawCookies = headers.get("Cookie");
if (!CollectionUtils.isEmpty(rawCookies)) {
for (String rawCookie : rawCookies) {
if (rawCookie.startsWith("JSESSIONID=")) {
int start = "JSESSIONID=".length();
int end = rawCookie.indexOf(';');
return (end != -1) ? rawCookie.substring(start, end) : rawCookie.substring(start);
}
}
}
return "dummy";
}
private final SockJsServiceConfig sockJsServiceConfig = new SockJsServiceConfig() {

View File

@ -149,7 +149,7 @@ public class AbstractSockJsServiceTests extends AbstractHttpRequestTests {
assertEquals(",\"origins\":[\"*:*\"],\"cookie_needed\":false,\"websocket\":true}",
body.substring(body.indexOf(',')));
this.service.setDummySessionCookieEnabled(false);
this.service.setSessionCookieNeeded(false);
this.service.setWebSocketsEnabled(false);
handleRequest("GET", "/a/info", HttpStatus.OK);

View File

@ -151,40 +151,6 @@ public class DefaultSockJsServiceTests extends AbstractHttpRequestTests {
assertEquals("OPTIONS, POST", this.response.getHeaders().getFirst("Access-Control-Allow-Methods"));
}
@Test
public void dummySessionCookieEnabled() throws Exception {
setRequest("POST", sessionUrlPrefix + "xhr");
this.service.setDummySessionCookieEnabled(true);
this.service.handleRequest(this.request, this.response, this.wsHandler);
this.response.flush();
assertEquals(200, this.servletResponse.getStatus());
assertEquals("JSESSIONID=dummy;path=/", this.servletResponse.getHeader("Set-Cookie"));
}
@Test
public void dummySessionCookieDisabled() throws Exception {
setRequest("POST", sessionUrlPrefix + "xhr");
this.service.setDummySessionCookieEnabled(false);
this.service.handleTransportRequest(this.request, this.response, this.wsHandler, sessionId, "xhr");
assertEquals(200, this.servletResponse.getStatus());
assertNull(this.servletResponse.getHeader("Set-Cookie"));
}
@Test
public void dummySessionCookieReuseRequestCookieValue() throws Exception {
setRequest("POST", sessionUrlPrefix + "xhr");
this.servletRequest.addHeader("Cookie", "JSESSIONID=123456789");
this.service.handleTransportRequest(this.request, this.response, this.wsHandler, sessionId, "xhr");
assertEquals(200, this.servletResponse.getStatus());
assertNull(this.servletResponse.getHeader("Set-Cookie"));
}
@Test
public void handleTransportRequestNoSuitableHandler() throws Exception {