Polish Cookie abstraction in http packge of spring-web
A getCookies method is now available on ServerHttpRequest with one ServletServerCookie implementation that wraps a Servlet cookie. The SockJS service makes use of this to check for an existing session cookie in the request.
This commit is contained in:
parent
c26272cef6
commit
0d5901ffb6
|
|
@ -40,17 +40,13 @@ public class SubProtocolWebSocketHandlerTests {
|
|||
|
||||
private TestWebSocketSession session;
|
||||
|
||||
@Mock
|
||||
SubProtocolHandler stompHandler;
|
||||
@Mock SubProtocolHandler stompHandler;
|
||||
|
||||
@Mock
|
||||
SubProtocolHandler mqttHandler;
|
||||
@Mock SubProtocolHandler mqttHandler;
|
||||
|
||||
@Mock
|
||||
SubProtocolHandler defaultHandler;
|
||||
@Mock SubProtocolHandler defaultHandler;
|
||||
|
||||
@Mock
|
||||
MessageChannel channel;
|
||||
@Mock MessageChannel channel;
|
||||
|
||||
|
||||
@Before
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import java.io.ByteArrayInputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.springframework.http.Cookies;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.util.Assert;
|
||||
|
|
@ -36,8 +35,6 @@ public class MockHttpInputMessage implements HttpInputMessage {
|
|||
|
||||
private final InputStream body;
|
||||
|
||||
private final Cookies cookies = new Cookies();
|
||||
|
||||
|
||||
public MockHttpInputMessage(byte[] contents) {
|
||||
this.body = (contents != null) ? new ByteArrayInputStream(contents) : null;
|
||||
|
|
@ -57,9 +54,4 @@ public class MockHttpInputMessage implements HttpInputMessage {
|
|||
public InputStream getBody() throws IOException {
|
||||
return this.body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cookies getCookies() {
|
||||
return this.cookies ;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import java.io.OutputStream;
|
|||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.springframework.http.Cookies;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpOutputMessage;
|
||||
|
||||
|
|
@ -39,7 +38,6 @@ public class MockHttpOutputMessage implements HttpOutputMessage {
|
|||
|
||||
private final ByteArrayOutputStream body = new ByteArrayOutputStream();
|
||||
|
||||
private final Cookies cookies = new Cookies();
|
||||
|
||||
/**
|
||||
* Return the headers.
|
||||
|
|
@ -87,9 +85,4 @@ public class MockHttpOutputMessage implements HttpOutputMessage {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cookies getCookies() {
|
||||
return this.cookies;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,13 +13,61 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http;
|
||||
|
||||
|
||||
/**
|
||||
* Representation of a cookie value parsed from a "Cookie" request header or a
|
||||
* "Set-Cookie" response header.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.0
|
||||
*
|
||||
* @see http://www.ietf.org/rfc/rfc2109.txt
|
||||
*/
|
||||
public interface Cookie {
|
||||
|
||||
String getName();
|
||||
/**
|
||||
* Returns the name of the cookie.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
String getValue();
|
||||
/**
|
||||
* Returns the value of the cookie.
|
||||
*/
|
||||
String getValue();
|
||||
|
||||
/**
|
||||
* Returns the path on the server to which the browser returns this cookie.
|
||||
*/
|
||||
String getPath();
|
||||
|
||||
/**
|
||||
* Returns the comment describing the purpose of this cookie.
|
||||
*/
|
||||
String getComment();
|
||||
|
||||
/**
|
||||
* Returns the domain name set for this cookie.
|
||||
*/
|
||||
String getDomain();
|
||||
|
||||
/**
|
||||
* Returns the maximum age of the cookie, specified in seconds.
|
||||
*/
|
||||
int getMaxAge();
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the browser is sending cookies only over a
|
||||
* secure protocol, or <code>false</code> if the browser can send cookies
|
||||
* using any protocol.
|
||||
*/
|
||||
boolean isSecure();
|
||||
|
||||
/**
|
||||
* Sets the version of the cookie protocol this cookie complies with.
|
||||
*/
|
||||
int getVersion();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* 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.http;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class Cookies {
|
||||
|
||||
private final List<Cookie> cookies;
|
||||
|
||||
|
||||
public Cookies() {
|
||||
this.cookies = new ArrayList<Cookie>();
|
||||
}
|
||||
|
||||
private Cookies(Cookies cookies) {
|
||||
this.cookies = Collections.unmodifiableList(cookies.getCookies());
|
||||
}
|
||||
|
||||
public static Cookies readOnlyCookies(Cookies cookies) {
|
||||
return new Cookies(cookies);
|
||||
}
|
||||
|
||||
public List<Cookie> getCookies() {
|
||||
return this.cookies;
|
||||
}
|
||||
|
||||
public Cookie getCookie(String name) {
|
||||
for (Cookie c : this.cookies) {
|
||||
if (c.getName().equals(name)) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Cookie addCookie(String name, String value) {
|
||||
DefaultCookie cookie = new DefaultCookie(name, value);
|
||||
this.cookies.add(cookie);
|
||||
return cookie;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* 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.http;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
public class DefaultCookie implements Cookie {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final String value;
|
||||
|
||||
DefaultCookie(String name, String value) {
|
||||
Assert.hasText(name, "cookie name must not be empty");
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -31,9 +31,4 @@ public interface HttpMessage {
|
|||
*/
|
||||
HttpHeaders getHeaders();
|
||||
|
||||
/**
|
||||
* TODO ..
|
||||
*/
|
||||
Cookies getCookies();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package org.springframework.http.client;
|
|||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.springframework.http.Cookies;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
|
@ -47,12 +46,6 @@ public abstract class AbstractClientHttpRequest implements ClientHttpRequest {
|
|||
return getBodyInternal(this.headers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cookies getCookies() {
|
||||
// TODO
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ClientHttpResponse execute() throws IOException {
|
||||
assertNotExecuted();
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ package org.springframework.http.client;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.http.Cookies;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
/**
|
||||
|
|
@ -34,10 +33,4 @@ public abstract class AbstractClientHttpResponse implements ClientHttpResponse {
|
|||
return HttpStatus.valueOf(getRawStatusCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cookies getCookies() {
|
||||
// TODO
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package org.springframework.http.client;
|
|||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import org.springframework.http.Cookies;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.Assert;
|
||||
|
|
@ -60,9 +59,4 @@ final class BufferingClientHttpRequestWrapper extends AbstractBufferingClientHtt
|
|||
return new BufferingClientHttpResponseWrapper(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cookies getCookies() {
|
||||
return this.request.getCookies();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import java.io.ByteArrayInputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.springframework.http.Cookies;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
|
@ -72,11 +71,6 @@ final class BufferingClientHttpResponseWrapper implements ClientHttpResponse {
|
|||
return new ByteArrayInputStream(this.body);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cookies getCookies() {
|
||||
return this.response.getCookies();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.response.close();
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ package org.springframework.http.client.support;
|
|||
|
||||
import java.net.URI;
|
||||
|
||||
import org.springframework.http.Cookies;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpRequest;
|
||||
|
|
@ -77,12 +76,4 @@ public class HttpRequestWrapper implements HttpRequest {
|
|||
return this.request.getHeaders();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cookies of the wrapped request.
|
||||
*/
|
||||
@Override
|
||||
public Cookies getCookies() {
|
||||
return this.request.getCookies();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,8 +25,6 @@ import java.util.List;
|
|||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.http.Cookies;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.HttpOutputMessage;
|
||||
|
|
@ -201,11 +199,6 @@ public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConv
|
|||
public HttpHeaders getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cookies getCookies() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ import java.util.Map;
|
|||
import java.util.Random;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.Cookies;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
|
|
@ -391,12 +390,6 @@ public class FormHttpMessageConverter implements HttpMessageConverter<MultiValue
|
|||
return this.os;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cookies getCookies() {
|
||||
// TODO
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
private void writeHeaders() throws IOException {
|
||||
if (!this.headersWritten) {
|
||||
for (Map.Entry<String, List<String>> entry : this.headers.entrySet()) {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,9 @@
|
|||
package org.springframework.http.server;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.http.Cookie;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
|
@ -35,6 +37,12 @@ public interface ServerHttpRequest extends HttpRequest, HttpInputMessage {
|
|||
*/
|
||||
MultiValueMap<String, String> getQueryParams();
|
||||
|
||||
/**
|
||||
* Return the cookie values parsed from the "Cookie" request header.
|
||||
* @return the cookies
|
||||
*/
|
||||
Map<String, Cookie> getCookies();
|
||||
|
||||
/**
|
||||
* Return a {@link java.security.Principal} instance containing the name of the
|
||||
* authenticated user. If the user has not been authenticated, the method returns
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.http.server;
|
||||
|
||||
import org.springframework.http.Cookie;
|
||||
|
||||
|
||||
/**
|
||||
* A {@link Cookie} that wraps a {@link javax.servlet.http.Cookie}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.0
|
||||
*/
|
||||
public class ServletServerCookie implements Cookie {
|
||||
|
||||
private final javax.servlet.http.Cookie servletCookie;
|
||||
|
||||
|
||||
public ServletServerCookie(javax.servlet.http.Cookie servletCookie) {
|
||||
this.servletCookie = servletCookie;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.servletCookie.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return this.servletCookie.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return this.servletCookie.getPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComment() {
|
||||
return this.servletCookie.getComment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDomain() {
|
||||
return this.servletCookie.getDomain();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxAge() {
|
||||
return this.servletCookie.getMaxAge();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSecure() {
|
||||
return this.servletCookie.getSecure();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return this.servletCookie.getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServletServerCookie [servletCookie=" + this.servletCookie + "]";
|
||||
}
|
||||
}
|
||||
|
|
@ -28,16 +28,16 @@ import java.net.URLEncoder;
|
|||
import java.nio.charset.Charset;
|
||||
import java.security.Principal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.http.Cookies;
|
||||
import org.springframework.http.Cookie;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
|
|
@ -63,7 +63,7 @@ public class ServletServerHttpRequest implements ServerHttpRequest {
|
|||
|
||||
private HttpHeaders headers;
|
||||
|
||||
private Cookies cookies;
|
||||
private Map<String, Cookie> cookies;
|
||||
|
||||
private MultiValueMap<String, String> queryParams;
|
||||
|
||||
|
|
@ -151,14 +151,15 @@ public class ServletServerHttpRequest implements ServerHttpRequest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Cookies getCookies() {
|
||||
public Map<String, Cookie> getCookies() {
|
||||
if (this.cookies == null) {
|
||||
this.cookies = new Cookies();
|
||||
this.cookies = new HashMap<String, Cookie>();
|
||||
if (this.servletRequest.getCookies() != null) {
|
||||
for (Cookie cookie : this.servletRequest.getCookies()) {
|
||||
this.cookies.addCookie(cookie.getName(), cookie.getValue());
|
||||
for (javax.servlet.http.Cookie cookie : this.servletRequest.getCookies()) {
|
||||
this.cookies.put(cookie.getName(), new ServletServerCookie(cookie));
|
||||
}
|
||||
}
|
||||
this.cookies = Collections.unmodifiableMap(this.cookies);
|
||||
}
|
||||
return this.cookies;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,10 +20,9 @@ import java.io.IOException;
|
|||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.http.Cookie;
|
||||
import org.springframework.http.Cookies;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.Assert;
|
||||
|
|
@ -42,8 +41,6 @@ public class ServletServerHttpResponse implements ServerHttpResponse {
|
|||
|
||||
private boolean headersWritten = false;
|
||||
|
||||
private final Cookies cookies = new Cookies();
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new instance of the ServletServerHttpResponse based on the given {@link HttpServletResponse}.
|
||||
|
|
@ -72,28 +69,20 @@ public class ServletServerHttpResponse implements ServerHttpResponse {
|
|||
return (this.headersWritten ? HttpHeaders.readOnlyHttpHeaders(this.headers) : this.headers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cookies getCookies() {
|
||||
return (this.headersWritten ? Cookies.readOnlyCookies(this.cookies) : this.cookies);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getBody() throws IOException {
|
||||
writeCookies();
|
||||
writeHeaders();
|
||||
return this.servletResponse.getOutputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
writeCookies();
|
||||
writeHeaders();
|
||||
this.servletResponse.flushBuffer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
writeCookies();
|
||||
writeHeaders();
|
||||
}
|
||||
|
||||
|
|
@ -116,14 +105,4 @@ public class ServletServerHttpResponse implements ServerHttpResponse {
|
|||
this.headersWritten = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeCookies() {
|
||||
if (!this.headersWritten) {
|
||||
for (Cookie source : this.cookies.getCookies()) {
|
||||
javax.servlet.http.Cookie target = new javax.servlet.http.Cookie(source.getName(), source.getValue());
|
||||
target.setPath("/");
|
||||
this.servletResponse.addCookie(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,8 +31,6 @@ public class MockHttpInputMessage implements HttpInputMessage {
|
|||
|
||||
private final InputStream body;
|
||||
|
||||
private final Cookies cookies = new Cookies();
|
||||
|
||||
|
||||
public MockHttpInputMessage(byte[] contents) {
|
||||
Assert.notNull(contents, "'contents' must not be null");
|
||||
|
|
@ -53,9 +51,4 @@ public class MockHttpInputMessage implements HttpInputMessage {
|
|||
public InputStream getBody() throws IOException {
|
||||
return body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cookies getCookies() {
|
||||
return this.cookies ;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import java.io.IOException;
|
|||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import static org.mockito.BDDMockito.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
|
|
@ -32,9 +32,6 @@ public class MockHttpOutputMessage implements HttpOutputMessage {
|
|||
|
||||
private final ByteArrayOutputStream body = spy(new ByteArrayOutputStream());
|
||||
|
||||
private final Cookies cookies = new Cookies();
|
||||
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
return headers;
|
||||
|
|
@ -53,9 +50,4 @@ public class MockHttpOutputMessage implements HttpOutputMessage {
|
|||
byte[] bytes = getBodyAsBytes();
|
||||
return new String(bytes, charset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cookies getCookies() {
|
||||
return this.cookies;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,6 @@ import java.util.List;
|
|||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.http.Cookies;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpRequest;
|
||||
|
|
@ -254,8 +252,6 @@ public class InterceptingClientHttpRequestFactoryTests {
|
|||
|
||||
private boolean executed = false;
|
||||
|
||||
private Cookies cookies = new Cookies();
|
||||
|
||||
private RequestMock() {
|
||||
}
|
||||
|
||||
|
|
@ -292,11 +288,6 @@ public class InterceptingClientHttpRequestFactoryTests {
|
|||
executed = true;
|
||||
return responseMock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cookies getCookies() {
|
||||
return this.cookies ;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ResponseMock implements ClientHttpResponse {
|
||||
|
|
@ -307,8 +298,6 @@ public class InterceptingClientHttpRequestFactoryTests {
|
|||
|
||||
private HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
private Cookies cookies = new Cookies();
|
||||
|
||||
@Override
|
||||
public HttpStatus getStatusCode() throws IOException {
|
||||
return statusCode;
|
||||
|
|
@ -337,10 +326,5 @@ public class InterceptingClientHttpRequestFactoryTests {
|
|||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cookies getCookies() {
|
||||
return this.cookies ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ public abstract class AbstractSockJsService implements SockJsService {
|
|||
|
||||
private int streamBytesLimit = 128 * 1024;
|
||||
|
||||
private boolean jsessionIdCookieRequired = true;
|
||||
private boolean sessionCookieEnabled = false;
|
||||
|
||||
private long heartbeatTime = 25 * 1000;
|
||||
|
||||
|
|
@ -187,23 +187,22 @@ public abstract class AbstractSockJsService implements SockJsService {
|
|||
}
|
||||
|
||||
/**
|
||||
* Some load balancers do sticky sessions, but only if there is a JSESSIONID
|
||||
* 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>Set this option to indicate if a JSESSIONID cookie should be created. The
|
||||
* default value is "true".
|
||||
* <p>The default value is "false" since Java servers set the session cookie.
|
||||
*/
|
||||
public void setJsessionIdCookieRequired(boolean jsessionIdCookieRequired) {
|
||||
this.jsessionIdCookieRequired = jsessionIdCookieRequired;
|
||||
public void setDummySessionCookieEnabled(boolean sessionCookieEnabled) {
|
||||
this.sessionCookieEnabled = sessionCookieEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether setting JSESSIONID cookie is necessary.
|
||||
* @see #setJsessionIdCookieRequired(boolean)
|
||||
* @see #setDummySessionCookieEnabled(boolean)
|
||||
*/
|
||||
public boolean isJsessionIdCookieRequired() {
|
||||
return this.jsessionIdCookieRequired;
|
||||
public boolean isDummySessionCookieEnabled() {
|
||||
return this.sessionCookieEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -476,7 +475,7 @@ public abstract class AbstractSockJsService implements SockJsService {
|
|||
addCorsHeaders(request, response);
|
||||
addNoCacheHeaders(response);
|
||||
|
||||
String content = String.format(INFO_CONTENT, random.nextInt(), isJsessionIdCookieRequired(), isWebSocketEnabled());
|
||||
String content = String.format(INFO_CONTENT, random.nextInt(), isDummySessionCookieEnabled(), isWebSocketEnabled());
|
||||
response.getBody().write(content.getBytes());
|
||||
}
|
||||
else if (HttpMethod.OPTIONS.equals(request.getMethod())) {
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ public enum TransportType {
|
|||
return this.headerHints.contains("cors");
|
||||
}
|
||||
|
||||
public boolean setsJsessionId() {
|
||||
public boolean sendsSessionCookie() {
|
||||
return this.headerHints.contains("jsessionid");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ public class DefaultSockJsService extends AbstractSockJsService {
|
|||
* @param transportHandlerOverrides zero or more overrides to the default transport
|
||||
* handler types.
|
||||
*/
|
||||
public DefaultSockJsService(TaskScheduler taskScheduler, Set<TransportHandler> transportHandlers,
|
||||
public DefaultSockJsService(TaskScheduler taskScheduler, Collection<TransportHandler> transportHandlers,
|
||||
TransportHandler... transportHandlerOverrides) {
|
||||
|
||||
super(taskScheduler);
|
||||
|
|
@ -254,11 +254,10 @@ public class DefaultSockJsService extends AbstractSockJsService {
|
|||
addNoCacheHeaders(response);
|
||||
}
|
||||
|
||||
if (transportType.setsJsessionId() && isJsessionIdCookieRequired()) {
|
||||
Cookie cookie = request.getCookies().getCookie("JSESSIONID");
|
||||
String jsid = (cookie != null) ? cookie.getValue() : "dummy";
|
||||
// TODO: bypass use of Cookie object (causes Jetty to set Expires header)
|
||||
response.getHeaders().set("Set-Cookie", "JSESSIONID=" + jsid + ";path=/");
|
||||
if (transportType.sendsSessionCookie() && isDummySessionCookieEnabled()) {
|
||||
Cookie cookie = request.getCookies().get("JSESSIONID");
|
||||
String value = (cookie != null) ? cookie.getValue() : "dummy";
|
||||
response.getHeaders().set("Set-Cookie", "JSESSIONID=" + value + ";path=/");
|
||||
}
|
||||
|
||||
if (transportType.supportsCors()) {
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ public class AbstractSockJsServiceTests extends AbstractHttpRequestTests {
|
|||
assertEquals(",\"origins\":[\"*:*\"],\"cookie_needed\":true,\"websocket\":true}",
|
||||
body.substring(body.indexOf(',')));
|
||||
|
||||
this.service.setJsessionIdCookieRequired(false);
|
||||
this.service.setDummySessionCookieEnabled(false);
|
||||
this.service.setWebSocketsEnabled(false);
|
||||
handleRequest("GET", "/a/info", HttpStatus.OK);
|
||||
|
||||
|
|
@ -214,6 +214,7 @@ public class AbstractSockJsServiceTests extends AbstractHttpRequestTests {
|
|||
assertEquals(httpStatus.value(), this.servletResponse.getStatus());
|
||||
}
|
||||
|
||||
|
||||
private static class TestSockJsService extends AbstractSockJsService {
|
||||
|
||||
private String sessionId;
|
||||
|
|
|
|||
|
|
@ -16,26 +16,18 @@
|
|||
|
||||
package org.springframework.web.socket.sockjs.transport.handler;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
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.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.web.socket.AbstractHttpRequestTests;
|
||||
import org.springframework.web.socket.WebSocketHandler;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
import org.springframework.web.socket.sockjs.SockJsProcessingException;
|
||||
import org.springframework.web.socket.sockjs.transport.TransportHandler;
|
||||
import org.springframework.web.socket.sockjs.transport.TransportType;
|
||||
import org.springframework.web.socket.sockjs.transport.handler.DefaultSockJsService;
|
||||
import org.springframework.web.socket.sockjs.transport.handler.SockJsSessionFactory;
|
||||
import org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession;
|
||||
import org.springframework.web.socket.sockjs.transport.session.StubSockJsServiceConfig;
|
||||
import org.springframework.web.socket.sockjs.transport.session.TestSockJsSession;
|
||||
|
||||
|
|
@ -50,10 +42,42 @@ import static org.mockito.Mockito.*;
|
|||
*/
|
||||
public class DefaultSockJsServiceTests extends AbstractHttpRequestTests {
|
||||
|
||||
@Override
|
||||
private static final String sockJsPrefix = "mysockjs";
|
||||
|
||||
private static final String sessionId = "session1";
|
||||
|
||||
private static final String sessionUrlPrefix = "/mysockjs/server1/" + sessionId + "/";
|
||||
|
||||
|
||||
@Mock private SessionCreatingTransportHandler xhrHandler;
|
||||
|
||||
@Mock private TransportHandler xhrSendHandler;
|
||||
|
||||
@Mock private WebSocketHandler wsHandler;
|
||||
|
||||
@Mock private TaskScheduler taskScheduler;
|
||||
|
||||
private TestSockJsSession session;
|
||||
|
||||
private DefaultSockJsService service;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
public void setup() {
|
||||
|
||||
super.setUp();
|
||||
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
this.session = new TestSockJsSession(sessionId, new StubSockJsServiceConfig(), this.wsHandler);
|
||||
|
||||
when(this.xhrHandler.getTransportType()).thenReturn(TransportType.XHR);
|
||||
when(this.xhrHandler.createSession(sessionId, this.wsHandler)).thenReturn(this.session);
|
||||
when(this.xhrSendHandler.getTransportType()).thenReturn(TransportType.XHR_SEND);
|
||||
|
||||
this.service = new DefaultSockJsService(this.taskScheduler,
|
||||
Arrays.<TransportHandler>asList(this.xhrHandler, this.xhrSendHandler));
|
||||
this.service.setValidSockJsPrefixes(sockJsPrefix);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -76,24 +100,14 @@ public class DefaultSockJsServiceTests extends AbstractHttpRequestTests {
|
|||
@Test
|
||||
public void handleTransportRequestXhr() throws Exception {
|
||||
|
||||
setRequest("POST", "/a/server/session/xhr");
|
||||
|
||||
TaskScheduler taskScheduler = mock(TaskScheduler.class);
|
||||
StubXhrTransportHandler xhrHandler = new StubXhrTransportHandler();
|
||||
Set<TransportHandler> transportHandlers = Collections.<TransportHandler>singleton(xhrHandler);
|
||||
WebSocketHandler webSocketHandler = mock(WebSocketHandler.class);
|
||||
|
||||
DefaultSockJsService service = new DefaultSockJsService(taskScheduler, transportHandlers);
|
||||
service.handleTransportRequest(this.request, this.response, webSocketHandler, "123", TransportType.XHR.value());
|
||||
setRequest("POST", sessionUrlPrefix + "xhr");
|
||||
this.service.handleRequest(this.request, this.response, this.wsHandler);
|
||||
|
||||
assertEquals(200, this.servletResponse.getStatus());
|
||||
assertNotNull(xhrHandler.session);
|
||||
assertSame(webSocketHandler, xhrHandler.webSocketHandler);
|
||||
|
||||
verify(this.xhrHandler).handleRequest(this.request, this.response, this.wsHandler, this.session);
|
||||
verify(taskScheduler).scheduleAtFixedRate(any(Runnable.class), eq(service.getDisconnectDelay()));
|
||||
|
||||
assertEquals("no-store, no-cache, must-revalidate, max-age=0", this.response.getHeaders().getCacheControl());
|
||||
assertEquals("JSESSIONID=dummy;path=/", this.response.getHeaders().getFirst("Set-Cookie"));
|
||||
assertEquals("*", this.response.getHeaders().getFirst("Access-Control-Allow-Origin"));
|
||||
assertEquals("true", this.response.getHeaders().getFirst("Access-Control-Allow-Credentials"));
|
||||
}
|
||||
|
|
@ -101,14 +115,8 @@ public class DefaultSockJsServiceTests extends AbstractHttpRequestTests {
|
|||
@Test
|
||||
public void handleTransportRequestXhrOptions() throws Exception {
|
||||
|
||||
setRequest("OPTIONS", "/a/server/session/xhr");
|
||||
|
||||
TaskScheduler taskScheduler = mock(TaskScheduler.class);
|
||||
StubXhrTransportHandler xhrHandler = new StubXhrTransportHandler();
|
||||
Set<TransportHandler> transportHandlers = Collections.<TransportHandler>singleton(xhrHandler);
|
||||
|
||||
DefaultSockJsService service = new DefaultSockJsService(taskScheduler, transportHandlers);
|
||||
service.handleTransportRequest(this.request, this.response, null, "123", TransportType.XHR.value());
|
||||
setRequest("OPTIONS", sessionUrlPrefix + "xhr");
|
||||
this.service.handleRequest(this.request, this.response, this.wsHandler);
|
||||
|
||||
assertEquals(204, this.servletResponse.getStatus());
|
||||
assertEquals("*", this.response.getHeaders().getFirst("Access-Control-Allow-Origin"));
|
||||
|
|
@ -116,14 +124,44 @@ 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);
|
||||
|
||||
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 {
|
||||
|
||||
setRequest("POST", "/a/server/session/xhr");
|
||||
|
||||
Set<TransportHandler> transportHandlers = new HashSet<>();
|
||||
DefaultSockJsService service = new DefaultSockJsService(mock(TaskScheduler.class), transportHandlers);
|
||||
service.handleTransportRequest(this.request, this.response, null, "123", TransportType.XHR.value());
|
||||
setRequest("POST", sessionUrlPrefix + "eventsource");
|
||||
this.service.handleRequest(this.request, this.response, this.wsHandler);
|
||||
|
||||
assertEquals(404, this.servletResponse.getStatus());
|
||||
}
|
||||
|
|
@ -131,71 +169,28 @@ public class DefaultSockJsServiceTests extends AbstractHttpRequestTests {
|
|||
@Test
|
||||
public void handleTransportRequestXhrSend() throws Exception {
|
||||
|
||||
this.servletRequest.setMethod("POST");
|
||||
setRequest("POST", sessionUrlPrefix + "xhr_send");
|
||||
this.service.handleRequest(this.request, this.response, this.wsHandler);
|
||||
|
||||
Set<TransportHandler> transportHandlers = new HashSet<>();
|
||||
transportHandlers.add(new StubXhrTransportHandler());
|
||||
transportHandlers.add(new StubXhrSendTransportHandler());
|
||||
WebSocketHandler wsHandler = mock(WebSocketHandler.class);
|
||||
DefaultSockJsService service = new DefaultSockJsService(mock(TaskScheduler.class), transportHandlers);
|
||||
|
||||
service.handleTransportRequest(this.request, this.response, wsHandler, "123", TransportType.XHR_SEND.value());
|
||||
|
||||
assertEquals(404, this.servletResponse.getStatus()); // dropped (no session)
|
||||
assertEquals(404, this.servletResponse.getStatus()); // no session yet
|
||||
|
||||
resetResponse();
|
||||
service.handleTransportRequest(this.request, this.response, wsHandler, "123", TransportType.XHR.value());
|
||||
setRequest("POST", sessionUrlPrefix + "xhr");
|
||||
this.service.handleRequest(this.request, this.response, this.wsHandler);
|
||||
|
||||
assertEquals(200, this.servletResponse.getStatus());
|
||||
assertEquals(200, this.servletResponse.getStatus()); // session created
|
||||
verify(this.xhrHandler).handleRequest(this.request, this.response, this.wsHandler, this.session);
|
||||
|
||||
resetResponse();
|
||||
service.handleTransportRequest(this.request, this.response, wsHandler, "123", TransportType.XHR_SEND.value());
|
||||
setRequest("POST", sessionUrlPrefix + "xhr_send");
|
||||
this.service.handleRequest(this.request, this.response, this.wsHandler);
|
||||
|
||||
assertEquals(200, this.servletResponse.getStatus());
|
||||
assertEquals(200, this.servletResponse.getStatus()); // session exists
|
||||
verify(this.xhrSendHandler).handleRequest(this.request, this.response, this.wsHandler, this.session);
|
||||
}
|
||||
|
||||
|
||||
private static class StubXhrTransportHandler implements TransportHandler, SockJsSessionFactory {
|
||||
|
||||
WebSocketHandler webSocketHandler;
|
||||
|
||||
WebSocketSession session;
|
||||
|
||||
@Override
|
||||
public TransportType getTransportType() {
|
||||
return TransportType.XHR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequest(ServerHttpRequest request, ServerHttpResponse response,
|
||||
WebSocketHandler handler, WebSocketSession session) throws SockJsProcessingException {
|
||||
|
||||
this.webSocketHandler = handler;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractSockJsSession createSession(String sessionId, WebSocketHandler webSocketHandler) {
|
||||
return new TestSockJsSession(sessionId, new StubSockJsServiceConfig(), webSocketHandler);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class StubXhrSendTransportHandler implements TransportHandler {
|
||||
|
||||
@Override
|
||||
public TransportType getTransportType() {
|
||||
return TransportType.XHR_SEND;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequest(ServerHttpRequest request, ServerHttpResponse response,
|
||||
WebSocketHandler handler, WebSocketSession session) throws SockJsProcessingException {
|
||||
|
||||
if (session == null) {
|
||||
response.setStatusCode(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
}
|
||||
interface SessionCreatingTransportHandler extends TransportHandler, SockJsSessionFactory {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue