diff --git a/.classpath b/.classpath
deleted file mode 100644
index 9c8395b..0000000
--- a/.classpath
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.gitignore b/.gitignore
index 4de0f79..10809b8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,9 @@
/node_modules
/bower_components
/release.properties
-/pom.xml.releaseBackup
\ No newline at end of file
+/pom.xml.releaseBackup
+*.iml
+.idea
+.project
+.classpath
+.settings
\ No newline at end of file
diff --git a/.project b/.project
deleted file mode 100644
index b77bffc..0000000
--- a/.project
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
- Java Cookie
-
-
-
-
-
- org.eclipse.wst.common.project.facet.core.builder
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
- org.eclipse.m2e.core.maven2Builder
-
-
-
-
-
- org.eclipse.m2e.core.maven2Nature
- org.eclipse.jdt.core.javanature
- org.eclipse.wst.common.project.facet.core.nature
-
-
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
deleted file mode 100644
index cdfe4f1..0000000
--- a/.settings/org.eclipse.core.resources.prefs
+++ /dev/null
@@ -1,5 +0,0 @@
-eclipse.preferences.version=1
-encoding//src/main/java=UTF-8
-encoding//src/test/java=UTF-8
-encoding//src/test/resources=UTF-8
-encoding/=UTF-8
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
deleted file mode 100644
index 443e085..0000000
--- a/.settings/org.eclipse.jdt.core.prefs
+++ /dev/null
@@ -1,8 +0,0 @@
-eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
-org.eclipse.jdt.core.compiler.compliance=1.7
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
-org.eclipse.jdt.core.compiler.source=1.7
diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs
deleted file mode 100644
index f897a7f..0000000
--- a/.settings/org.eclipse.m2e.core.prefs
+++ /dev/null
@@ -1,4 +0,0 @@
-activeProfiles=
-eclipse.preferences.version=1
-resolveWorkspaceProjects=true
-version=1
diff --git a/.settings/org.eclipse.wst.common.project.facet.core.xml b/.settings/org.eclipse.wst.common.project.facet.core.xml
deleted file mode 100644
index e06acaa..0000000
--- a/.settings/org.eclipse.wst.common.project.facet.core.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/.travis.yml b/.travis.yml
index 88ccde2..5af472f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,7 @@
language: java
jdk:
- - oraclejdk7
- - openjdk6
\ No newline at end of file
+ - oraclejdk8
+ - oraclejdk11
+ - openjdk10
+ - openjdk11
\ No newline at end of file
diff --git a/Gruntfile.js b/Gruntfile.js
deleted file mode 100644
index db99085..0000000
--- a/Gruntfile.js
+++ /dev/null
@@ -1,18 +0,0 @@
-module.exports = function (grunt) {
-
- grunt.initConfig({
- bower_postinst: {
- all: {
- options: {
- components: {
- 'js-cookie': ['npm', 'grunt']
- }
- }
- }
- }
- });
-
- grunt.loadNpmTasks('grunt-bower-postinst');
-
- grunt.registerTask('default', ['bower_postinst']);
-};
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..68eb935
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,14 @@
+{
+ "name": "java-cookie",
+ "version": "1.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "bower": {
+ "version": "1.8.8",
+ "resolved": "https://registry.npmjs.org/bower/-/bower-1.8.8.tgz",
+ "integrity": "sha512-1SrJnXnkP9soITHptSO+ahx3QKp3cVzn8poI6ujqc5SeOkg5iqM1pK9H+DSc2OQ8SnO0jC/NG4Ur/UIwy7574A==",
+ "dev": true
+ }
+ }
+}
diff --git a/package.json b/package.json
index 4edcf21..cffb38a 100644
--- a/package.json
+++ b/package.json
@@ -1,14 +1,12 @@
{
"name": "java-cookie",
"version": "1.0.0",
+ "license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/js-cookie/java-cookie.git"
},
"devDependencies": {
- "bower": "1.4.1",
- "grunt": "0.4.5",
- "grunt-bower-postinst": "0.2.1",
- "grunt-cli": "0.1.13"
+ "bower": "1.8.8"
}
}
diff --git a/pom.xml b/pom.xml
index d5637e3..104d88c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,4 +1,5 @@
-
+
4.0.0
com.github.js-cookie
java-cookie
@@ -35,8 +36,8 @@
- RedHat
- https://maven.repository.redhat.com/earlyaccess/all
+ RedHat GA
+ https://maven.repository.redhat.com/ga/
@@ -64,13 +65,12 @@
-
- org.jboss.arquillian
- arquillian-bom
- 1.1.8.Final
- import
- pom
-
+
+ org.jboss.arquillian
+ arquillian-bom
+ 1.4.1.Final
+ pom
+
@@ -83,12 +83,12 @@
joda-time
joda-time
- 2.7
+ 2.10.1
com.fasterxml.jackson.core
jackson-databind
- 2.8.11.1
+ 2.9.8
junit
@@ -123,25 +123,32 @@
org.jboss.arquillian.junit
arquillian-junit-container
+ 1.4.1.Final
test
org.jboss.shrinkwrap.resolver
- shrinkwrap-resolver-bom
- 2.2.0-beta-2
- pom
- import
+ shrinkwrap-resolver-impl-maven
+ 3.1.3
+ test
org.apache.httpcomponents
httpclient
- 4.3.3
+ 4.5.7
test
org.apache.httpcomponents
fluent-hc
- 4.3.3
+ 4.5.7
+ test
+
+
+ org.jboss.as
+ jboss-as-dist
+ 7.5.7.Final-redhat-3
+ pom
test
@@ -153,30 +160,6 @@
-
- maven-dependency-plugin
-
-
- unpack
- process-test-classes
-
- unpack
-
-
-
-
- org.jboss.as
- jboss-as-dist
- 7.5.0.Final-redhat-15
- zip
- false
- target
-
-
-
-
-
-
org.codehaus.mojo
failsafe-maven-plugin
@@ -193,22 +176,22 @@
com.github.eirslett
frontend-maven-plugin
- 0.0.23
+ 1.5
install node and npm
- install-node-and-npm
+ install-node-and-npm
- v0.10.18
- 1.3.8
+ v11.10.0
+ 6.8.0
npm install
- npm
+ npm
@@ -217,12 +200,6 @@
bower
-
- grunt build
-
- grunt
-
-
@@ -245,7 +222,7 @@
org.apache.maven.plugins
maven-javadoc-plugin
- 2.10.3
+ 3.0.1
attach-javadocs
@@ -258,7 +235,7 @@
org.apache.maven.plugins
maven-source-plugin
- 2.4
+ 3.0.1
attach-sources
@@ -271,7 +248,7 @@
org.sonatype.plugins
nexus-staging-maven-plugin
- 1.6.5
+ 1.6.8
true
ossrh
diff --git a/src/main/java/com/github/jscookie/javacookie/Cookies.java b/src/main/java/com/github/jscookie/javacookie/Cookies.java
index a8abe7f..22da112 100644
--- a/src/main/java/com/github/jscookie/javacookie/Cookies.java
+++ b/src/main/java/com/github/jscookie/javacookie/Cookies.java
@@ -1,491 +1,495 @@
package com.github.jscookie.javacookie;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.ResourceBundle;
-import java.util.Set;
+import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
public final class Cookies implements CookiesDefinition {
- private static String UTF_8 = "UTF-8";
- private HttpServletRequest request;
- private HttpServletResponse response;
- private AttributesDefinition defaults = Attributes.empty();
- private ConverterStrategy converter;
- private ObjectMapper mapper = new ObjectMapper();
-
- private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";
- private static ResourceBundle lStrings = ResourceBundle.getBundle( LSTRING_FILE );
-
- private Cookies( HttpServletRequest request, HttpServletResponse response, ConverterStrategy converter ) {
- this.request = request;
- this.response = response;
- this.converter = converter;
- }
-
- public static Cookies initFromServlet( HttpServletRequest request, HttpServletResponse response ) {
- return new Cookies( request, response, null );
- }
-
- @Override
- public synchronized String get( String name ) {
- if ( name == null || name.length() == 0 ) {
- throw new IllegalArgumentException( lStrings.getString( "err.cookie_name_blank" ) );
- }
-
- String cookieHeader = request.getHeader( "cookie" );
- if ( cookieHeader == null ) {
- return null;
- }
-
- Map cookies = getCookies( cookieHeader );
- for ( String decodedName : cookies.keySet() ) {
- if ( !name.equals( decodedName ) ) {
- continue;
- }
- return cookies.get( decodedName );
- }
-
- return null;
- }
-
- @Override
- public T get( String name, Class dataType ) throws CookieParseException {
- String value = get( name );
- try {
- return mapper.readValue( value, dataType );
- } catch ( IOException e ) {
- throw new CookieParseException( e );
- }
- }
-
- @Override
- public T get( String name, TypeReference typeRef ) throws CookieParseException {
- String value = get( name );
- try {
- return mapper.readValue( value, typeRef );
- } catch ( IOException e ) {
- throw new CookieParseException( e );
- }
- }
-
- @Override
- public Map get() {
- Map result = new HashMap();
-
- String cookieHeader = request.getHeader( "cookie" );
- if ( cookieHeader == null ) {
- return result;
- }
-
- return getCookies( cookieHeader );
- }
-
- @Override
- public synchronized void set( String name, String value, AttributesDefinition attributes ) {
- if ( name == null || name.length() == 0 ) {
- throw new IllegalArgumentException( lStrings.getString( "err.cookie_name_blank" ) );
- }
- if ( value == null ) {
- throw new IllegalArgumentException();
- }
- if ( attributes == null ) {
- throw new IllegalArgumentException();
- }
-
- String encodedName = encode( name );
- String encodedValue = encodeValue( value );
-
- StringBuilder header = new StringBuilder();
- header.append( encodedName );
- header.append( '=' );
- header.append( encodedValue );
-
- attributes = extend( Attributes.empty().path( "/" ), defaults, attributes );
-
- String path = attributes.path();
- if ( path != null && !path.isEmpty() ) {
- header.append( "; Path=" + path );
- }
-
- Expiration expires = attributes.expires();
- if ( expires != null ) {
- header.append( "; Expires=" + expires.toExpiresString() );
- }
-
- String domain = attributes.domain();
- if ( domain != null ) {
- header.append( "; Domain=" + domain );
- }
-
- Boolean secure = attributes.secure();
- if ( Boolean.TRUE.equals( secure ) ) {
- header.append( "; Secure" );
- }
-
- Boolean httpOnly = attributes.httpOnly();
- if ( Boolean.TRUE.equals( httpOnly ) ) {
- header.append( "; HttpOnly" );
- }
-
- if ( response.isCommitted() ) {
- return;
- }
-
- setCookie( header.toString(), response );
- }
-
- @Override
- public void set( String name, int value, AttributesDefinition attributes ) throws CookieSerializationException {
- set( name, String.valueOf( value ), attributes );
- }
-
- @Override
- public void set( String name, boolean value, AttributesDefinition attributes ) throws CookieSerializationException {
- set( name, String.valueOf( value ), attributes );
- }
-
- @Override
- public void set( String name, List value, AttributesDefinition attributes ) throws CookieSerializationException {
- try {
- set( name, mapper.writeValueAsString( value ), attributes );
- } catch ( JsonProcessingException e ) {
- throw new CookieSerializationException( e );
- }
- }
-
- @Override
- public void set( String name, CookieValue value, AttributesDefinition attributes ) throws CookieSerializationException {
- try {
- set( name, mapper.writeValueAsString( value ), attributes );
- } catch ( JsonProcessingException e ) {
- throw new CookieSerializationException( e );
- }
- }
-
- @Override
- public void set( String name, String value ) {
- if ( name == null || name.length() == 0 ) {
- throw new IllegalArgumentException( lStrings.getString( "err.cookie_name_blank" ) );
- }
- if ( value == null ) {
- throw new IllegalArgumentException();
- }
- set( name, value, defaults );
- }
-
- @Override
- public void set( String name, int value ) throws CookieSerializationException {
- set( name, value, Attributes.empty() );
- }
-
- @Override
- public void set( String name, boolean value ) {
- set( name, String.valueOf( value ) );
- }
-
- @Override
- public void set( String name, List value ) throws CookieSerializationException {
- set( name, value, Attributes.empty() );
- }
-
- @Override
- public void set( String name, CookieValue value ) throws CookieSerializationException {
- set( name, value, Attributes.empty() );
- }
-
- @Override
- public void remove( String name, AttributesDefinition attributes ) {
- if ( name == null || name.length() == 0 ) {
- throw new IllegalArgumentException( lStrings.getString( "err.cookie_name_blank" ) );
- }
- if ( attributes == null ) {
- throw new IllegalArgumentException();
- }
-
- set( name, "", extend( attributes, Attributes.empty()
- .expires( Expiration.days( -1 ) ))
- );
- }
-
- @Override
- public void remove( String name ) {
- if ( name == null || name.length() == 0 ) {
- throw new IllegalArgumentException( lStrings.getString( "err.cookie_name_blank" ) );
- }
- remove( name, Attributes.empty() );
- }
-
- @Override
- public AttributesDefinition defaults() {
- return this.defaults;
- }
-
- @Override
- public Cookies withConverter( ConverterStrategy converter ) {
- return new Cookies( request, response, converter );
- }
-
- private Attributes extend( AttributesDefinition... mergeables ) {
- Attributes result = Attributes.empty();
- for ( AttributesDefinition mergeable : mergeables ) {
- result.merge( mergeable );
- }
- return result;
- }
-
- private void setCookie( String cookieValue, HttpServletResponse response ) {
- response.addHeader( "Set-Cookie", cookieValue );
- }
-
- private String encode( String decoded ) {
- return encode( decoded, new HashSet() );
- }
-
- private String encode( String decoded, Set exceptions ) {
- String encoded = decoded;
- for ( int i = 0; i < decoded.length(); ) {
- int codePoint = decoded.codePointAt( i );
- i += Character.charCount( codePoint );
-
- boolean isDigit = codePoint >= codePoint( "0" ) && codePoint <= codePoint( "9" );
- if ( isDigit ) {
- continue;
- }
-
- boolean isAsciiUppercaseLetter = codePoint >= codePoint( "A" ) && codePoint <= codePoint( "Z" );
- if ( isAsciiUppercaseLetter ) {
- continue;
- }
-
- boolean isAsciiLowercaseLetter = codePoint >= codePoint( "a" ) && codePoint <= codePoint( "z" );
- if ( isAsciiLowercaseLetter ) {
- continue;
- }
-
- boolean isAllowed =
- codePoint == codePoint( "!" ) || codePoint == codePoint( "#" ) ||
- codePoint == codePoint( "$" ) || codePoint == codePoint( "&" ) ||
- codePoint == codePoint( "'" ) || codePoint == codePoint( "*" ) ||
- codePoint == codePoint( "+" ) || codePoint == codePoint( "-" ) ||
- codePoint == codePoint( "." ) || codePoint == codePoint( "^" ) ||
- codePoint == codePoint( "_" ) || codePoint == codePoint( "`" ) ||
- codePoint == codePoint( "|" ) || codePoint == codePoint( "~" );
- if ( isAllowed ) {
- continue;
- }
-
- if ( exceptions.contains( codePoint ) ) {
- continue;
- }
-
- try {
- String character = new String( Character.toChars( codePoint ) );
- CharArrayWriter hexSequence = new CharArrayWriter();
- byte[] bytes = character.getBytes( UTF_8 );
- for ( int bytesIndex = 0; bytesIndex < bytes.length; bytesIndex++ ) {
- char left = Character.forDigit( bytes[ bytesIndex ] >> 4 & 0xF, 16 );
- char right = Character.forDigit( bytes[ bytesIndex ] & 0xF, 16 );
- hexSequence
- .append( '%' )
- .append( left )
- .append( right );
- }
- String target = character.toString();
- String sequence = hexSequence.toString().toUpperCase();
- encoded = encoded.replace( target, sequence );
- } catch ( UnsupportedEncodingException e ) {
- e.printStackTrace();
- }
- }
- return encoded;
- }
-
- private String decode( String encoded ) {
- String decoded = encoded;
- Pattern pattern = Pattern.compile( "(%[0-9A-Z]{2})+" );
- Matcher matcher = pattern.matcher( encoded );
- while ( matcher.find() ) {
- String encodedChar = matcher.group();
- String[] encodedBytes = encodedChar.split( "%" );
- byte[] bytes = new byte[ encodedBytes.length - 1 ];
- for ( int i = 1; i < encodedBytes.length; i++ ) {
- String encodedByte = encodedBytes[ i ];
- bytes[ i - 1 ] = ( byte )Integer.parseInt( encodedByte, 16 );
- }
- try {
- String decodedChar = new String( bytes, UTF_8 );
- decoded = decoded.replace( encodedChar, decodedChar );
- } catch ( UnsupportedEncodingException e ) {
- e.printStackTrace();
- }
- }
- return decoded;
- }
-
- private String encodeValue( String decodedValue ) {
- Set exceptions = new HashSet();
- for ( int i = 0; i < decodedValue.length(); ) {
- int codePoint = decodedValue.codePointAt( i );
- i += Character.charCount( codePoint );
-
- boolean isIgnorable = false;
- if ( codePoint == codePoint( "/" ) || codePoint == codePoint( ":") ) {
- isIgnorable = true;
- }
-
- if ( codePoint >= codePoint( "<" ) && codePoint <= codePoint( "@" ) ) {
- isIgnorable = true;
- }
-
- if ( codePoint == codePoint( "[" ) || codePoint == codePoint( "]" ) ) {
- isIgnorable = true;
- }
-
- if ( codePoint == codePoint( "{" ) || codePoint == codePoint( "}" ) ) {
- isIgnorable = true;
- }
-
- if ( isIgnorable ) {
- exceptions.add( codePoint );
- }
- }
-
- return encode( decodedValue, exceptions );
- }
-
- private int codePoint( String character ) {
- return character.codePointAt( 0 );
- }
-
- private String decodeValue( String encodedValue, String decodedName ) {
- String decodedValue = null;
-
- if ( converter != null ) {
- try {
- decodedValue = converter.convert( encodedValue, decodedName );
- } catch ( ConverterException e ) {
- e.printStackTrace();
- }
- }
-
- if ( decodedValue == null ) {
- decodedValue = decode( encodedValue );
- }
-
- return decodedValue;
- }
-
- private Map getCookies( String cookieHeader ) {
- Map result = new HashMap();
- String[] cookies = cookieHeader.split( "; " );
- for ( int i = 0; i < cookies.length; i++ ) {
- String cookie = cookies[ i ];
- String encodedName = cookie.split( "=" )[ 0 ];
- String decodedName = decode( encodedName );
-
- String encodedValue = cookie.substring( cookie.indexOf( '=' ) + 1, cookie.length() );
- String decodedValue = decodeValue( encodedValue, decodedName );
- result.put( decodedName, decodedValue );
- }
- return result;
- }
-
- public static class Attributes extends AttributesDefinition {
- private Expiration expires;
- private String path;
- private String domain;
- private Boolean secure;
- private Boolean httpOnly;
-
- private Attributes() {}
-
- public static Attributes empty() {
- return new Attributes();
- }
-
- @Override
- Expiration expires() {
- return expires;
- }
- @Override
- public Attributes expires( Expiration expires ) {
- this.expires = expires;
- return this;
- }
-
- @Override
- String path() {
- return path;
- }
- @Override
- public Attributes path( String path ) {
- this.path = path;
- return this;
- }
-
- @Override
- String domain() {
- return domain;
- }
- @Override
- public Attributes domain( String domain ) {
- this.domain = domain;
- return this;
- }
-
- @Override
- Boolean secure() {
- return secure;
- }
- @Override
- public Attributes secure( Boolean secure ) {
- this.secure = secure;
- return this;
- }
-
- @Override
- Boolean httpOnly() {
- return httpOnly;
- }
- @Override
- public Attributes httpOnly( Boolean httpOnly ) {
- this.httpOnly = httpOnly;
- return this;
- }
-
- private Attributes merge( AttributesDefinition reference ) {
- if ( reference.path() != null ) {
- path = reference.path();
- }
- if ( reference.domain() != null ) {
- domain = reference.domain();
- }
- if ( reference.expires() != null ) {
- expires = reference.expires();
- }
- if ( reference.secure() != null ) {
- secure = reference.secure();
- }
- if ( reference.httpOnly() != null ) {
- httpOnly = reference.httpOnly();
- }
- return this;
- }
- }
-
- public static abstract class Converter implements ConverterStrategy {}
+ private static String UTF_8 = "UTF-8";
+ private HttpServletRequest request;
+ private HttpServletResponse response;
+ private AttributesDefinition defaults = Attributes.empty();
+ private ConverterStrategy converter;
+ private ObjectMapper mapper = new ObjectMapper();
+
+ private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";
+ private static ResourceBundle lStrings = ResourceBundle.getBundle(LSTRING_FILE);
+
+ private Cookies(HttpServletRequest request, HttpServletResponse response, ConverterStrategy converter) {
+ this.request = request;
+ this.response = response;
+ this.converter = converter;
+ }
+
+ public static Cookies initFromServlet(HttpServletRequest request, HttpServletResponse response) {
+ return new Cookies(request, response, null);
+ }
+
+ @Override
+ public synchronized String get(String name) {
+ if (name == null || name.length() == 0) {
+ throw new IllegalArgumentException(lStrings.getString("err.cookie_name_blank"));
+ }
+
+ String cookieHeader = request.getHeader("cookie");
+ if (cookieHeader == null) {
+ return null;
+ }
+
+ Map cookies = getCookies(cookieHeader);
+ for (String decodedName : cookies.keySet()) {
+ if (!name.equals(decodedName)) {
+ continue;
+ }
+ return cookies.get(decodedName);
+ }
+
+ return null;
+ }
+
+ @Override
+ public T get(String name, Class dataType) throws CookieParseException {
+ String value = get(name);
+ try {
+ return mapper.readValue(value, dataType);
+ } catch (IOException e) {
+ throw new CookieParseException(e);
+ }
+ }
+
+ @Override
+ public T get(String name, TypeReference typeRef) throws CookieParseException {
+ String value = get(name);
+ try {
+ return mapper.readValue(value, typeRef);
+ } catch (IOException e) {
+ throw new CookieParseException(e);
+ }
+ }
+
+ @Override
+ public Map get() {
+ Map result = new HashMap();
+
+ String cookieHeader = request.getHeader("cookie");
+ if (cookieHeader == null) {
+ return result;
+ }
+
+ return getCookies(cookieHeader);
+ }
+
+ @Override
+ public synchronized void set(String name, String value, AttributesDefinition attributes) {
+ if (name == null || name.length() == 0) {
+ throw new IllegalArgumentException(lStrings.getString("err.cookie_name_blank"));
+ }
+ if (value == null) {
+ throw new IllegalArgumentException();
+ }
+ if (attributes == null) {
+ throw new IllegalArgumentException();
+ }
+
+ String encodedName = encode(name);
+ String encodedValue = encodeValue(value);
+
+ StringBuilder header = new StringBuilder();
+ header.append(encodedName);
+ header.append('=');
+ header.append(encodedValue);
+
+ attributes = extend(Attributes.empty().path("/"), defaults, attributes);
+
+ String path = attributes.path();
+ if (path != null && !path.isEmpty()) {
+ header.append("; Path=").append(path);
+ }
+
+ Expiration expires = attributes.expires();
+ if (expires != null) {
+ header.append("; Expires=").append(expires.toExpiresString());
+ }
+
+ String domain = attributes.domain();
+ if (domain != null) {
+ header.append("; Domain=").append(domain);
+ }
+
+ Boolean secure = attributes.secure();
+ if (Boolean.TRUE.equals(secure)) {
+ header.append("; Secure");
+ }
+
+ Boolean httpOnly = attributes.httpOnly();
+ if (Boolean.TRUE.equals(httpOnly)) {
+ header.append("; HttpOnly");
+ }
+
+ if (response.isCommitted()) {
+ return;
+ }
+
+ setCookie(header.toString(), response);
+ }
+
+ @Override
+ public void set(String name, int value, AttributesDefinition attributes) throws CookieSerializationException {
+ set(name, String.valueOf(value), attributes);
+ }
+
+ @Override
+ public void set(String name, boolean value, AttributesDefinition attributes) throws CookieSerializationException {
+ set(name, String.valueOf(value), attributes);
+ }
+
+ @Override
+ public void set(String name, List value, AttributesDefinition attributes) throws CookieSerializationException {
+ try {
+ set(name, mapper.writeValueAsString(value), attributes);
+ } catch (JsonProcessingException e) {
+ throw new CookieSerializationException(e);
+ }
+ }
+
+ @Override
+ public void set(String name, CookieValue value, AttributesDefinition attributes) throws CookieSerializationException {
+ try {
+ set(name, mapper.writeValueAsString(value), attributes);
+ } catch (JsonProcessingException e) {
+ throw new CookieSerializationException(e);
+ }
+ }
+
+ @Override
+ public void set(String name, String value) {
+ if (name == null || name.length() == 0) {
+ throw new IllegalArgumentException(lStrings.getString("err.cookie_name_blank"));
+ }
+ if (value == null) {
+ throw new IllegalArgumentException();
+ }
+ set(name, value, defaults);
+ }
+
+ @Override
+ public void set(String name, int value) throws CookieSerializationException {
+ set(name, value, Attributes.empty());
+ }
+
+ @Override
+ public void set(String name, boolean value) {
+ set(name, String.valueOf(value));
+ }
+
+ @Override
+ public void set(String name, List value) throws CookieSerializationException {
+ set(name, value, Attributes.empty());
+ }
+
+ @Override
+ public void set(String name, CookieValue value) throws CookieSerializationException {
+ set(name, value, Attributes.empty());
+ }
+
+ @Override
+ public void remove(String name, AttributesDefinition attributes) {
+ if (name == null || name.length() == 0) {
+ throw new IllegalArgumentException(lStrings.getString("err.cookie_name_blank"));
+ }
+ if (attributes == null) {
+ throw new IllegalArgumentException();
+ }
+
+ set(name, "", extend(attributes, Attributes.empty()
+ .expires(Expiration.days(-1)))
+ );
+ }
+
+ @Override
+ public void remove(String name) {
+ if (name == null || name.length() == 0) {
+ throw new IllegalArgumentException(lStrings.getString("err.cookie_name_blank"));
+ }
+ remove(name, Attributes.empty());
+ }
+
+ @Override
+ public AttributesDefinition defaults() {
+ return this.defaults;
+ }
+
+ @Override
+ public Cookies withConverter(ConverterStrategy converter) {
+ return new Cookies(request, response, converter);
+ }
+
+ private Attributes extend(AttributesDefinition... mergeables) {
+ Attributes result = Attributes.empty();
+ for (AttributesDefinition mergeable : mergeables) {
+ result.merge(mergeable);
+ }
+ return result;
+ }
+
+ private void setCookie(String cookieValue, HttpServletResponse response) {
+ response.addHeader("Set-Cookie", cookieValue);
+ }
+
+ private String encode(String decoded) {
+ return encode(decoded, new HashSet());
+ }
+
+ private String encode(String decoded, Set exceptions) {
+ String encoded = decoded;
+ for (int i = 0; i < decoded.length(); ) {
+ int codePoint = decoded.codePointAt(i);
+ i += Character.charCount(codePoint);
+
+ boolean isDigit = codePoint >= codePoint("0") && codePoint <= codePoint("9");
+ if (isDigit) {
+ continue;
+ }
+
+ boolean isAsciiUppercaseLetter = codePoint >= codePoint("A") && codePoint <= codePoint("Z");
+ if (isAsciiUppercaseLetter) {
+ continue;
+ }
+
+ boolean isAsciiLowercaseLetter = codePoint >= codePoint("a") && codePoint <= codePoint("z");
+ if (isAsciiLowercaseLetter) {
+ continue;
+ }
+
+ boolean isAllowed =
+ codePoint == codePoint("!") || codePoint == codePoint("#") ||
+ codePoint == codePoint("$") || codePoint == codePoint("&") ||
+ codePoint == codePoint("'") || codePoint == codePoint("*") ||
+ codePoint == codePoint("+") || codePoint == codePoint("-") ||
+ codePoint == codePoint(".") || codePoint == codePoint("^") ||
+ codePoint == codePoint("_") || codePoint == codePoint("`") ||
+ codePoint == codePoint("|") || codePoint == codePoint("~");
+ if (isAllowed) {
+ continue;
+ }
+
+ if (exceptions.contains(codePoint)) {
+ continue;
+ }
+
+ try {
+ String character = new String(Character.toChars(codePoint));
+ CharArrayWriter hexSequence = new CharArrayWriter();
+ byte[] bytes = character.getBytes(UTF_8);
+ for (byte aByte : bytes) {
+ char left = Character.forDigit(aByte >> 4 & 0xF, 16);
+ char right = Character.forDigit(aByte & 0xF, 16);
+ hexSequence
+ .append('%')
+ .append(left)
+ .append(right);
+ }
+ String sequence = hexSequence.toString().toUpperCase();
+ encoded = encoded.replace(character, sequence);
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }
+ return encoded;
+ }
+
+ private String decode(String encoded) {
+ // Decode characters with 3 bytes first, then with 1 byte to fix https://github.com/js-cookie/java-cookie/issues/14
+ return decode(decode(encoded, 3), 1);
+ }
+
+ private String decode(String encoded, Integer bytesPerCharacter) {
+ String decoded = encoded;
+ Pattern pattern = Pattern.compile("(%[0-9A-Z]{2}){" + bytesPerCharacter + "}");
+ Matcher matcher = pattern.matcher(encoded);
+ while (matcher.find()) {
+ String encodedChar = matcher.group();
+ String[] encodedBytes = encodedChar.split("%");
+ byte[] bytes = new byte[encodedBytes.length - 1];
+ for (int i = 1; i < encodedBytes.length; i++) {
+ String encodedByte = encodedBytes[i];
+ bytes[i - 1] = (byte) Integer.parseInt(encodedByte, 16);
+ }
+ try {
+ String decodedChar = new String(bytes, UTF_8);
+ decoded = decoded.replace(encodedChar, decodedChar);
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }
+ return decoded;
+ }
+
+ private String encodeValue(String decodedValue) {
+ Set exceptions = new HashSet();
+ for (int i = 0; i < decodedValue.length(); ) {
+ int codePoint = decodedValue.codePointAt(i);
+ i += Character.charCount(codePoint);
+
+ boolean isIgnorable = false;
+ if (codePoint == codePoint("/") || codePoint == codePoint(":")) {
+ isIgnorable = true;
+ }
+
+ if (codePoint >= codePoint("<") && codePoint <= codePoint("@")) {
+ isIgnorable = true;
+ }
+
+ if (codePoint == codePoint("[") || codePoint == codePoint("]")) {
+ isIgnorable = true;
+ }
+
+ if (codePoint == codePoint("{") || codePoint == codePoint("}")) {
+ isIgnorable = true;
+ }
+
+ if (isIgnorable) {
+ exceptions.add(codePoint);
+ }
+ }
+
+ return encode(decodedValue, exceptions);
+ }
+
+ private int codePoint(String character) {
+ return character.codePointAt(0);
+ }
+
+ private String decodeValue(String encodedValue, String decodedName) {
+ String decodedValue = null;
+
+ if (converter != null) {
+ try {
+ decodedValue = converter.convert(encodedValue, decodedName);
+ } catch (ConverterException e) {
+ e.printStackTrace();
+ }
+ }
+
+ if (decodedValue == null) {
+ decodedValue = decode(encodedValue);
+ }
+
+ return decodedValue;
+ }
+
+ private Map getCookies(String cookieHeader) {
+ Map result = new HashMap();
+ String[] cookies = cookieHeader.split("; ");
+ for (String cookie : cookies) {
+ String encodedName = cookie.split("=")[0];
+ String decodedName = decode(encodedName);
+
+ String encodedValue = cookie.substring(cookie.indexOf('=') + 1);
+ String decodedValue = decodeValue(encodedValue, decodedName);
+ result.put(decodedName, decodedValue);
+ }
+ return result;
+ }
+
+ public static class Attributes extends AttributesDefinition {
+ private Expiration expires;
+ private String path;
+ private String domain;
+ private Boolean secure;
+ private Boolean httpOnly;
+
+ private Attributes() {
+ }
+
+ public static Attributes empty() {
+ return new Attributes();
+ }
+
+ @Override
+ Expiration expires() {
+ return expires;
+ }
+
+ @Override
+ public Attributes expires(Expiration expires) {
+ this.expires = expires;
+ return this;
+ }
+
+ @Override
+ String path() {
+ return path;
+ }
+
+ @Override
+ public Attributes path(String path) {
+ this.path = path;
+ return this;
+ }
+
+ @Override
+ String domain() {
+ return domain;
+ }
+
+ @Override
+ public Attributes domain(String domain) {
+ this.domain = domain;
+ return this;
+ }
+
+ @Override
+ Boolean secure() {
+ return secure;
+ }
+
+ @Override
+ public Attributes secure(Boolean secure) {
+ this.secure = secure;
+ return this;
+ }
+
+ @Override
+ Boolean httpOnly() {
+ return httpOnly;
+ }
+
+ @Override
+ public Attributes httpOnly(Boolean httpOnly) {
+ this.httpOnly = httpOnly;
+ return this;
+ }
+
+ private Attributes merge(AttributesDefinition reference) {
+ if (reference.path() != null) {
+ path = reference.path();
+ }
+ if (reference.domain() != null) {
+ domain = reference.domain();
+ }
+ if (reference.expires() != null) {
+ expires = reference.expires();
+ }
+ if (reference.secure() != null) {
+ secure = reference.secure();
+ }
+ if (reference.httpOnly() != null) {
+ httpOnly = reference.httpOnly();
+ }
+ return this;
+ }
+ }
+
+ public static abstract class Converter implements ConverterStrategy {
+ }
}
diff --git a/src/test/java/com/github/jscookie/javacookie/test/unit/CookiesDecodingTest.java b/src/test/java/com/github/jscookie/javacookie/test/unit/CookiesDecodingTest.java
index ef5150c..330dce5 100644
--- a/src/test/java/com/github/jscookie/javacookie/test/unit/CookiesDecodingTest.java
+++ b/src/test/java/com/github/jscookie/javacookie/test/unit/CookiesDecodingTest.java
@@ -1,5 +1,7 @@
package com.github.jscookie.javacookie.test.unit;
+import com.github.jscookie.javacookie.Cookies;
+import com.github.jscookie.javacookie.test.unit.utils.BaseTest;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -7,31 +9,36 @@
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
-import com.github.jscookie.javacookie.Cookies;
-import com.github.jscookie.javacookie.test.unit.utils.BaseTest;
-
-@RunWith( MockitoJUnitRunner.class )
+@RunWith(MockitoJUnitRunner.class)
public class CookiesDecodingTest extends BaseTest {
- private Cookies cookies;
+ private Cookies cookies;
+
+ @Before
+ public void before() {
+ cookies = Cookies.initFromServlet(request, response);
+ }
- @Before
- public void before() {
- cookies = Cookies.initFromServlet( request, response );
- }
+ @Test
+ public void character_not_allowed_in_name_and_value() {
+ Mockito.when(request.getHeader("cookie")).thenReturn("%3B=%3B");
+ String actual = cookies.get(";");
+ String expected = ";";
+ Assert.assertEquals(expected, actual);
+ }
- @Test
- public void character_not_allowed_in_name_and_value() {
- Mockito.when( request.getHeader( "cookie" ) ).thenReturn( "%3B=%3B" );
- String actual = cookies.get( ";" );
- String expected = ";";
- Assert.assertEquals( expected, actual );
- }
+ @Test
+ public void character_with_3_bytes() {
+ Mockito.when(request.getHeader("cookie")).thenReturn("c=%E4%BA%AC");
+ String actual = cookies.get("c");
+ String expected = "京";
+ Assert.assertEquals(expected, actual);
+ }
- @Test
- public void character_with_3_bytes() {
- Mockito.when( request.getHeader( "cookie" ) ).thenReturn( "c=%E4%BA%AC" );
- String actual = cookies.get( "c" );
- String expected = "京";
- Assert.assertEquals( expected, actual );
- }
+ @Test
+ public void two_encoded_characters() {
+ Mockito.when(request.getHeader("cookie")).thenReturn("c=New%20York%2C%20NY");
+ String actual = cookies.get("c");
+ String expected = "New York, NY";
+ Assert.assertEquals(expected, actual);
+ }
}
diff --git a/src/test/java/com/github/jscookie/javacookie/test/unit/utils/IntegrationUtils.java b/src/test/java/com/github/jscookie/javacookie/test/unit/utils/IntegrationUtils.java
index 4afe8a0..7229d10 100644
--- a/src/test/java/com/github/jscookie/javacookie/test/unit/utils/IntegrationUtils.java
+++ b/src/test/java/com/github/jscookie/javacookie/test/unit/utils/IntegrationUtils.java
@@ -1,26 +1,26 @@
package com.github.jscookie.javacookie.test.unit.utils;
-import java.io.File;
-
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.jboss.shrinkwrap.resolver.api.maven.Maven;
+import java.io.File;
+
public class IntegrationUtils {
- public static WebArchive createCommonDeployment() {
- boolean RECURSIVE_TRUE = true;
- return ShrinkWrap.create( WebArchive.class )
- .addPackage( "com.github.jscookie.javacookie" )
- .addPackages( RECURSIVE_TRUE, "com.github.jscookie.javacookie.test.integration" )
- .addAsLibraries(
- Maven.resolver()
- .loadPomFromFile( "pom.xml" )
- .resolve(
- "joda-time:joda-time",
- "com.fasterxml.jackson.core:jackson-databind"
- )
- .withTransitivity()
- .as( File.class )
- );
- }
+ public static WebArchive createCommonDeployment() {
+ boolean RECURSIVE_TRUE = true;
+ return ShrinkWrap.create(WebArchive.class)
+ .addPackage("com.github.jscookie.javacookie")
+ .addPackages(RECURSIVE_TRUE, "com.github.jscookie.javacookie.test.integration")
+ .addAsLibraries(
+ Maven.resolver()
+ .loadPomFromFile("pom.xml")
+ .resolve(
+ "joda-time:joda-time",
+ "com.fasterxml.jackson.core:jackson-databind"
+ )
+ .withTransitivity()
+ .as(File.class)
+ );
+ }
}