Merge branch '5.1.x'
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 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.
|
||||
@@ -59,12 +59,18 @@ public final class ResponseCookie extends HttpCookie {
|
||||
|
||||
super(name, value);
|
||||
Assert.notNull(maxAge, "Max age must not be null");
|
||||
|
||||
this.maxAge = maxAge;
|
||||
this.domain = domain;
|
||||
this.path = path;
|
||||
this.secure = secure;
|
||||
this.httpOnly = httpOnly;
|
||||
this.sameSite = sameSite;
|
||||
|
||||
Rfc6265Utils.validateCookieName(name);
|
||||
Rfc6265Utils.validateCookieValue(value);
|
||||
Rfc6265Utils.validateDomain(domain);
|
||||
Rfc6265Utils.validatePath(path);
|
||||
}
|
||||
|
||||
|
||||
@@ -308,4 +314,89 @@ public final class ResponseCookie extends HttpCookie {
|
||||
ResponseCookie build();
|
||||
}
|
||||
|
||||
|
||||
private static class Rfc6265Utils {
|
||||
|
||||
private static final String SEPARATOR_CHARS = new String(new char[] {
|
||||
'(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}', ' '
|
||||
});
|
||||
|
||||
private static final String DOMAIN_CHARS =
|
||||
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-";
|
||||
|
||||
|
||||
public static void validateCookieName(String name) {
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
char c = name.charAt(i);
|
||||
// CTL = <US-ASCII control chars (octets 0 - 31) and DEL (127)>
|
||||
if (c <= 0x1F || c == 0x7F) {
|
||||
throw new IllegalArgumentException(
|
||||
name + ": RFC2616 token cannot have control chars");
|
||||
}
|
||||
if (SEPARATOR_CHARS.indexOf(c) >= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
name + ": RFC2616 token cannot have separator chars such as '" + c + "'");
|
||||
}
|
||||
if (c >= 0x80) {
|
||||
throw new IllegalArgumentException(
|
||||
name + ": RFC2616 token can only have US-ASCII: 0x" + Integer.toHexString(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void validateCookieValue(@Nullable String value) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
int start = 0;
|
||||
int end = value.length();
|
||||
if (end > 1 && value.charAt(0) == '"' && value.charAt(end - 1) == '"') {
|
||||
start = 1;
|
||||
end--;
|
||||
}
|
||||
char[] chars = value.toCharArray();
|
||||
for (int i = start; i < end; i++) {
|
||||
char c = chars[i];
|
||||
if (c < 0x21 || c == 0x22 || c == 0x2c || c == 0x3b || c == 0x5c || c == 0x7f) {
|
||||
throw new IllegalArgumentException(
|
||||
"RFC2616 cookie value cannot have '" + c + "'");
|
||||
}
|
||||
if (c >= 0x80) {
|
||||
throw new IllegalArgumentException(
|
||||
"RFC2616 cookie value can only have US-ASCII chars: 0x" + Integer.toHexString(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void validateDomain(@Nullable String domain) {
|
||||
if (!StringUtils.hasLength(domain)) {
|
||||
return;
|
||||
}
|
||||
int char1 = domain.charAt(0);
|
||||
int charN = domain.charAt(domain.length() - 1);
|
||||
if (char1 == '.' || char1 == '-' || charN == '.' || charN == '-') {
|
||||
throw new IllegalArgumentException("Invalid first/last char in cookie domain: " + domain);
|
||||
}
|
||||
for (int i = 0, c = -1; i < domain.length(); i++) {
|
||||
int p = c;
|
||||
c = domain.charAt(i);
|
||||
if (DOMAIN_CHARS.indexOf(c) == -1 || (p == '.' && (c == '.' || c == '-')) || (p == '-' && c == '.')) {
|
||||
throw new IllegalArgumentException(domain + ": invalid cookie domain char '" + c + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void validatePath(@Nullable String path) {
|
||||
if (path == null) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < path.length(); i++) {
|
||||
char c = path.charAt(i);
|
||||
if (c < 0x20 || c > 0x7E || c == ';') {
|
||||
throw new IllegalArgumentException(path + ": Invalid cookie path char '" + c + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,10 +17,9 @@
|
||||
package org.springframework.http.server.reactive;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.http.cookie.Cookie;
|
||||
import io.netty.handler.codec.http.cookie.DefaultCookie;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
@@ -91,21 +90,11 @@ class ReactorServerHttpResponse extends AbstractServerHttpResponse implements Ze
|
||||
|
||||
@Override
|
||||
protected void applyCookies() {
|
||||
for (String name : getCookies().keySet()) {
|
||||
for (ResponseCookie httpCookie : getCookies().get(name)) {
|
||||
Cookie cookie = new DefaultCookie(name, httpCookie.getValue());
|
||||
if (!httpCookie.getMaxAge().isNegative()) {
|
||||
cookie.setMaxAge(httpCookie.getMaxAge().getSeconds());
|
||||
}
|
||||
if (httpCookie.getDomain() != null) {
|
||||
cookie.setDomain(httpCookie.getDomain());
|
||||
}
|
||||
if (httpCookie.getPath() != null) {
|
||||
cookie.setPath(httpCookie.getPath());
|
||||
}
|
||||
cookie.setSecure(httpCookie.isSecure());
|
||||
cookie.setHttpOnly(httpCookie.isHttpOnly());
|
||||
this.response.addCookie(cookie);
|
||||
// Netty Cookie doesn't support sameSite. When this is resolved, we can adapt to it again:
|
||||
// https://github.com/netty/netty/issues/8161
|
||||
for (List<ResponseCookie> cookies : getCookies().values()) {
|
||||
for (ResponseCookie cookie : cookies) {
|
||||
this.response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,13 +19,13 @@ package org.springframework.http.server.reactive;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.AsyncEvent;
|
||||
import javax.servlet.AsyncListener;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.WriteListener;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.reactivestreams.Processor;
|
||||
@@ -142,21 +142,19 @@ class ServletServerHttpResponse extends AbstractListenerServerHttpResponse {
|
||||
|
||||
@Override
|
||||
protected void applyCookies() {
|
||||
for (String name : getCookies().keySet()) {
|
||||
for (ResponseCookie httpCookie : getCookies().get(name)) {
|
||||
Cookie cookie = new Cookie(name, httpCookie.getValue());
|
||||
if (!httpCookie.getMaxAge().isNegative()) {
|
||||
cookie.setMaxAge((int) httpCookie.getMaxAge().getSeconds());
|
||||
}
|
||||
if (httpCookie.getDomain() != null) {
|
||||
cookie.setDomain(httpCookie.getDomain());
|
||||
}
|
||||
if (httpCookie.getPath() != null) {
|
||||
cookie.setPath(httpCookie.getPath());
|
||||
}
|
||||
cookie.setSecure(httpCookie.isSecure());
|
||||
cookie.setHttpOnly(httpCookie.isHttpOnly());
|
||||
this.response.addCookie(cookie);
|
||||
|
||||
// Servlet Cookie doesn't support same site:
|
||||
// https://github.com/eclipse-ee4j/servlet-api/issues/175
|
||||
|
||||
// For Jetty, starting 9.4.21+ we could adapt to HttpCookie:
|
||||
// https://github.com/eclipse/jetty.project/issues/3040
|
||||
|
||||
// For Tomcat it seems to be a global option only:
|
||||
// https://tomcat.apache.org/tomcat-8.5-doc/config/cookie-processor.html
|
||||
|
||||
for (List<ResponseCookie> cookies : getCookies().values()) {
|
||||
for (ResponseCookie cookie : cookies) {
|
||||
this.response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +115,7 @@ class UndertowServerHttpResponse extends AbstractListenerServerHttpResponse impl
|
||||
}
|
||||
cookie.setSecure(httpCookie.isSecure());
|
||||
cookie.setHttpOnly(httpCookie.isHttpOnly());
|
||||
cookie.setSameSiteMode(httpCookie.getSameSite());
|
||||
this.exchange.getResponseCookies().putIfAbsent(name, cookie);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user