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:
Rossen Stoyanchev
2013-08-02 12:23:48 -04:00
parent c26272cef6
commit 0d5901ffb6
26 changed files with 258 additions and 353 deletions

View File

@@ -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();
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -31,9 +31,4 @@ public interface HttpMessage {
*/
HttpHeaders getHeaders();
/**
* TODO ..
*/
Cookies getCookies();
}

View File

@@ -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();

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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();

View File

@@ -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();
}
}

View File

@@ -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;
}
});
}
});

View File

@@ -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()) {

View File

@@ -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

View File

@@ -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 + "]";
}
}

View File

@@ -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;
}

View File

@@ -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);
}
}
}
}