Skip to content

Commit 506bd91

Browse files
committed
Do not serialize version of Cookie for RFC 6265.
Signed-off-by: jansupol <[email protected]>
1 parent 9f1b14c commit 506bd91

File tree

9 files changed

+413
-20
lines changed

9 files changed

+413
-20
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0, which is available at
6+
* http://www.eclipse.org/legal/epl-2.0.
7+
*
8+
* This Source Code may also be made available under the following Secondary
9+
* Licenses when the conditions for such availability set forth in the
10+
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11+
* version 2 with the GNU Classpath Exception, which is available at
12+
* https://www.gnu.org/software/classpath/license.html.
13+
*
14+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15+
*/
16+
17+
package org.glassfish.jersey.http;
18+
19+
import jakarta.ws.rs.core.Cookie;
20+
21+
import java.util.Objects;
22+
23+
/**
24+
* Jersey subclass of {@link Cookie} bearing information about optional version.
25+
* Complies with RFC 6265.
26+
*/
27+
public final class JerseyCookie extends Cookie implements VersionOptional {
28+
private final Integer version;
29+
private JerseyCookie(Builder builder) throws IllegalArgumentException {
30+
super(builder);
31+
this.version = builder.version;
32+
}
33+
34+
@Override
35+
public boolean hasVersion() {
36+
return version != null;
37+
}
38+
39+
@Override
40+
public boolean equals(final Object obj) {
41+
if (obj == null) {
42+
return false;
43+
}
44+
if (obj.getClass() != Cookie.class && obj.getClass() != JerseyCookie.class) {
45+
return false;
46+
}
47+
final Cookie other = (Cookie) obj;
48+
if (!Objects.equals(this.getName(), other.getName())) {
49+
return false;
50+
}
51+
if (!Objects.equals(this.getValue(), other.getValue())) {
52+
return false;
53+
}
54+
if (!Objects.equals(this.getVersion(), other.getVersion())) {
55+
return false;
56+
}
57+
if (!Objects.equals(this.getPath(), other.getPath())) {
58+
return false;
59+
}
60+
if (!Objects.equals(this.getDomain(), other.getDomain())) {
61+
return false;
62+
}
63+
return true;
64+
}
65+
66+
67+
/**
68+
* Builder for building Cookie.
69+
*/
70+
public static final class Builder extends AbstractCookieBuilder<JerseyCookie.Builder> {
71+
private Integer version;
72+
/**
73+
* Create a new instance.
74+
*
75+
* @param name the name of the cookie.
76+
*/
77+
public Builder(String name) {
78+
super(name);
79+
}
80+
81+
@Override
82+
public Builder version(int version) {
83+
super.version(version);
84+
this.version = version;
85+
return this;
86+
}
87+
88+
/**
89+
* Set version as nullable Integer. {@code null} refers to RFC 6265 Cookie without a version.
90+
* @param version the version of the HTTP Cookie.
91+
* @return updated builder.
92+
*/
93+
public Builder version(Integer version) {
94+
super.version(version == null ? VersionOptional.NETSCAPE_VERSION : version);
95+
this.version = version;
96+
return this;
97+
}
98+
99+
@Override
100+
public Cookie build() {
101+
return new JerseyCookie(this);
102+
}
103+
104+
}
105+
106+
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/*
2+
* Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0, which is available at
6+
* http://www.eclipse.org/legal/epl-2.0.
7+
*
8+
* This Source Code may also be made available under the following Secondary
9+
* Licenses when the conditions for such availability set forth in the
10+
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11+
* version 2 with the GNU Classpath Exception, which is available at
12+
* https://www.gnu.org/software/classpath/license.html.
13+
*
14+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15+
*/
16+
17+
package org.glassfish.jersey.http;
18+
19+
import jakarta.ws.rs.core.Cookie;
20+
import jakarta.ws.rs.core.NewCookie;
21+
22+
import java.util.Objects;
23+
24+
/**
25+
* Jersey subclass of {@link NewCookie} bearing information about optional version.
26+
* Complies with RFC 6265.
27+
*/
28+
public final class JerseyNewCookie extends NewCookie implements VersionOptional {
29+
private final Integer version;
30+
private JerseyNewCookie(JerseyNewCookie.Builder builder) {
31+
super(builder);
32+
this.version = builder.version;
33+
}
34+
35+
@Override
36+
public boolean hasVersion() {
37+
return version != null;
38+
}
39+
40+
@Override
41+
public boolean equals(final Object obj) {
42+
if (obj == null) {
43+
return false;
44+
}
45+
if (obj.getClass() != NewCookie.class && obj.getClass() != JerseyNewCookie.class) {
46+
return false;
47+
}
48+
final NewCookie other = (NewCookie) obj;
49+
if (!Objects.equals(this.getName(), other.getName())) {
50+
return false;
51+
}
52+
if (!Objects.equals(this.getValue(), other.getValue())) {
53+
return false;
54+
}
55+
if (this.getVersion() != other.getVersion()) {
56+
return false;
57+
}
58+
if (!Objects.equals(this.getPath(), other.getPath())) {
59+
return false;
60+
}
61+
if (!Objects.equals(this.getDomain(), other.getDomain())) {
62+
return false;
63+
}
64+
if (!Objects.equals(this.getComment(), other.getComment())) {
65+
return false;
66+
}
67+
if (this.getMaxAge() != other.getMaxAge()) {
68+
return false;
69+
}
70+
if (!Objects.equals(this.getExpiry(), other.getExpiry())) {
71+
return false;
72+
}
73+
if (this.isSecure() != other.isSecure()) {
74+
return false;
75+
}
76+
if (this.isHttpOnly() != other.isHttpOnly()) {
77+
return false;
78+
}
79+
if (this.getSameSite() != other.getSameSite()) {
80+
return false;
81+
}
82+
return true;
83+
}
84+
85+
@Override
86+
public int hashCode() {
87+
return Objects.hash(super.hashCode(), version);
88+
}
89+
90+
/**
91+
* Builder class building the Jersey NewCookie subclass.
92+
*/
93+
public static final class Builder extends AbstractNewCookieBuilder<JerseyNewCookie.Builder> {
94+
private Integer version;
95+
96+
97+
/**
98+
* Create a new instance.
99+
*
100+
* @param name the name of the cookie.
101+
*/
102+
public Builder(String name) {
103+
super(name);
104+
}
105+
106+
/**
107+
* Create a new instance supplementing the information in the supplied cookie.
108+
*
109+
* @param cookie the cookie to copy.
110+
*/
111+
public Builder(Cookie cookie) {
112+
super(cookie);
113+
if (cookie instanceof VersionOptional) {
114+
this.version = ((VersionOptional) cookie).hasVersion() ? cookie.getVersion() : null;
115+
}
116+
}
117+
118+
@Override
119+
public Builder version(int version) {
120+
super.version(version);
121+
this.version = version;
122+
return this;
123+
}
124+
125+
/**
126+
* Set version. Can be {@code null} if RFC 6265.
127+
* @param version the cookie version.
128+
* @return updated builder.
129+
*/
130+
public Builder version(Integer version) {
131+
// Version 0 should refer to NETSCAPE, but NewCookie should be for RFC 2109 & 2965 - version 1.
132+
super.version(version == null ? DEFAULT_VERSION : version);
133+
this.version = version;
134+
return this;
135+
}
136+
137+
@Override
138+
public NewCookie build() {
139+
return new JerseyNewCookie(this);
140+
}
141+
}
142+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0, which is available at
6+
* http://www.eclipse.org/legal/epl-2.0.
7+
*
8+
* This Source Code may also be made available under the following Secondary
9+
* Licenses when the conditions for such availability set forth in the
10+
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11+
* version 2 with the GNU Classpath Exception, which is available at
12+
* https://www.gnu.org/software/classpath/license.html.
13+
*
14+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15+
*/
16+
17+
package org.glassfish.jersey.http;
18+
19+
/**
20+
* Provides information about optionality of version in {@code Cookie} and {@code NewCookie}.
21+
* The version is as follows: 0 - Netscape, 1 - RFC 2109 & 2965, not set RFC 6265.
22+
*/
23+
public interface VersionOptional {
24+
25+
/**
26+
* The version from the original Netscape specification.
27+
*/
28+
public static final int NETSCAPE_VERSION = 0;
29+
30+
/**
31+
* Defines if the version is set.
32+
* @return {@code true} when the version is set.
33+
*/
34+
boolean hasVersion();
35+
}

core-common/src/main/java/org/glassfish/jersey/message/internal/CookieProvider.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import jakarta.inject.Singleton;
2222

2323
import org.glassfish.jersey.internal.LocalizationMessages;
24+
import org.glassfish.jersey.http.VersionOptional;
2425
import org.glassfish.jersey.spi.HeaderDelegateProvider;
2526

2627
import static org.glassfish.jersey.message.internal.Utils.throwIllegalArgumentExceptionIfNull;
@@ -46,7 +47,15 @@ public String toString(Cookie cookie) {
4647

4748
StringBuilder b = new StringBuilder();
4849

49-
b.append("$Version=").append(cookie.getVersion()).append(';');
50+
boolean printVersion = false;
51+
if (cookie instanceof VersionOptional) {
52+
printVersion = ((VersionOptional) cookie).hasVersion();
53+
} else if (cookie.getVersion() == Cookie.DEFAULT_VERSION || cookie.getVersion() == VersionOptional.NETSCAPE_VERSION) {
54+
printVersion = true;
55+
}
56+
if (printVersion) {
57+
b.append("$Version=").append(cookie.getVersion()).append(';');
58+
}
5059

5160
b.append(cookie.getName()).append('=');
5261
StringBuilderUtils.appendQuotedIfWhitespace(b, cookie.getValue());

core-common/src/main/java/org/glassfish/jersey/message/internal/CookiesParser.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import jakarta.ws.rs.core.NewCookie;
2929

3030
import org.glassfish.jersey.internal.LocalizationMessages;
31+
import org.glassfish.jersey.http.JerseyCookie;
32+
import org.glassfish.jersey.http.JerseyNewCookie;
3133

3234
/**
3335
* Cookies parser.
@@ -43,7 +45,7 @@ private static class MutableCookie {
4345

4446
String name;
4547
String value;
46-
int version = Cookie.DEFAULT_VERSION;
48+
Integer version = null;
4749
String path = null;
4850
String domain = null;
4951

@@ -53,14 +55,14 @@ public MutableCookie(String name, String value) {
5355
}
5456

5557
public Cookie getImmutableCookie() {
56-
return new Cookie(name, value, path, domain, version);
58+
return new JerseyCookie.Builder(name).version(version).value(value).path(path).domain(domain).build();
5759
}
5860
}
5961

6062
public static Map<String, Cookie> parseCookies(String header) {
6163
String bites[] = header.split("[;,]");
6264
Map<String, Cookie> cookies = new LinkedHashMap<String, Cookie>();
63-
int version = 0;
65+
Integer version = null;
6466
MutableCookie cookie = null;
6567
for (String bite : bites) {
6668
String crumbs[] = bite.split("=", 2);
@@ -123,7 +125,7 @@ private static class MutableNewCookie {
123125
String value = null;
124126
String path = null;
125127
String domain = null;
126-
int version = Cookie.DEFAULT_VERSION;
128+
Integer version = null;
127129
String comment = null;
128130
int maxAge = NewCookie.DEFAULT_MAX_AGE;
129131
boolean secure = false;
@@ -137,7 +139,8 @@ public MutableNewCookie(String name, String value) {
137139
}
138140

139141
public NewCookie getImmutableNewCookie() {
140-
return new NewCookie(name, value, path, domain, version, comment, maxAge, expiry, secure, httpOnly, sameSite);
142+
return new JerseyNewCookie.Builder(name).version(version).value(value).path(path).domain(domain).comment(comment)
143+
.maxAge(maxAge).expiry(expiry).secure(secure).httpOnly(httpOnly).sameSite(sameSite).build();
141144
}
142145
}
143146

core-common/src/main/java/org/glassfish/jersey/message/internal/NewCookieProvider.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616

1717
package org.glassfish.jersey.message.internal;
1818

19+
import jakarta.ws.rs.core.Cookie;
1920
import jakarta.ws.rs.core.NewCookie;
2021

2122
import jakarta.inject.Singleton;
2223

2324
import org.glassfish.jersey.internal.LocalizationMessages;
25+
import org.glassfish.jersey.http.VersionOptional;
2426
import org.glassfish.jersey.spi.HeaderDelegateProvider;
2527

2628
import java.util.Locale;
@@ -51,7 +53,15 @@ public String toString(final NewCookie cookie) {
5153
b.append(cookie.getName()).append('=');
5254
StringBuilderUtils.appendQuotedIfWhitespace(b, cookie.getValue());
5355

54-
b.append(";").append("Version=").append(cookie.getVersion());
56+
boolean printVersion = false;
57+
if (cookie instanceof VersionOptional) {
58+
printVersion = ((VersionOptional) cookie).hasVersion();
59+
} else if (cookie.getVersion() == Cookie.DEFAULT_VERSION) {
60+
printVersion = true;
61+
}
62+
if (printVersion) {
63+
b.append(";").append("Version=").append(cookie.getVersion());
64+
}
5565

5666
if (cookie.getComment() != null) {
5767
b.append(";Comment=");

0 commit comments

Comments
 (0)