@ -1,5 +1,5 @@
@@ -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 {
@@ -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 {
@@ -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 + "'" ) ;
}
}
}
}
}