Skip to content

Commit f6299d9

Browse files
slandellenormanmaurer
authored andcommitted
Minor ClientCookieDecoder improvements
Motivation: * Path attribute should be null, not empty String, if it's passed as "Path=". * Only extract attribute value when the name is recognized. * Only extract Expires attribute value String if MaxAge is undefined as it has precedence. Modification: Modify ClientCookieDecoder. Add "testIgnoreEmptyPath" test in ClientCookieDecoderTest. Result: More idyomatic Path behavior (like Domain). Minor performance improvement in some corner cases.
1 parent 864f196 commit f6299d9

File tree

2 files changed

+46
-39
lines changed

2 files changed

+46
-39
lines changed

codec-http/src/main/java/io/netty/handler/codec/http/cookie/ClientCookieDecoder.java

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -138,39 +138,44 @@ public Cookie decode(String header) {
138138
return null;
139139
}
140140

141-
cookieBuilder = new CookieBuilder(cookie);
141+
cookieBuilder = new CookieBuilder(cookie, header);
142142
} else {
143143
// cookie attribute
144-
String attrValue = valueBegin == -1 ? null : header.substring(valueBegin, valueEnd);
145-
cookieBuilder.appendAttribute(header, nameBegin, nameEnd, attrValue);
144+
cookieBuilder.appendAttribute(nameBegin, nameEnd, valueBegin, valueEnd);
146145
}
147146
}
148147
return cookieBuilder.cookie();
149148
}
150149

151150
private static class CookieBuilder {
152151

152+
private final String header;
153153
private final DefaultCookie cookie;
154154
private String domain;
155155
private String path;
156156
private long maxAge = Long.MIN_VALUE;
157-
private String expires;
157+
private int expiresStart;
158+
private int expiresEnd;
158159
private boolean secure;
159160
private boolean httpOnly;
160161

161-
public CookieBuilder(DefaultCookie cookie) {
162+
public CookieBuilder(DefaultCookie cookie, String header) {
162163
this.cookie = cookie;
164+
this.header = header;
163165
}
164166

165-
private long mergeMaxAgeAndExpire(long maxAge, String expires) {
167+
private long mergeMaxAgeAndExpires() {
166168
// max age has precedence over expires
167169
if (maxAge != Long.MIN_VALUE) {
168170
return maxAge;
169-
} else if (expires != null) {
170-
Date expiresDate = HttpHeaderDateFormat.get().parse(expires, new ParsePosition(0));
171-
if (expiresDate != null) {
172-
long maxAgeMillis = expiresDate.getTime() - System.currentTimeMillis();
173-
return maxAgeMillis / 1000 + (maxAgeMillis % 1000 != 0 ? 1 : 0);
171+
} else {
172+
String expires = computeValue(expiresStart, expiresEnd);
173+
if (expires != null) {
174+
Date expiresDate = HttpHeaderDateFormat.get().parse(expires, new ParsePosition(0));
175+
if (expiresDate != null) {
176+
long maxAgeMillis = expiresDate.getTime() - System.currentTimeMillis();
177+
return maxAgeMillis / 1000 + (maxAgeMillis % 1000 != 0 ? 1 : 0);
178+
}
174179
}
175180
}
176181
return Long.MIN_VALUE;
@@ -179,7 +184,7 @@ private long mergeMaxAgeAndExpire(long maxAge, String expires) {
179184
public Cookie cookie() {
180185
cookie.setDomain(domain);
181186
cookie.setPath(path);
182-
cookie.setMaxAge(mergeMaxAgeAndExpire(maxAge, expires));
187+
cookie.setMaxAge(mergeMaxAgeAndExpires());
183188
cookie.setSecure(secure);
184189
cookie.setHttpOnly(httpOnly);
185190
return cookie;
@@ -189,53 +194,43 @@ public Cookie cookie() {
189194
* Parse and store a key-value pair. First one is considered to be the
190195
* cookie name/value. Unknown attribute names are silently discarded.
191196
*
192-
* @param header
193-
* the HTTP header
194197
* @param keyStart
195198
* where the key starts in the header
196199
* @param keyEnd
197200
* where the key ends in the header
198-
* @param value
199-
* the decoded value
201+
* @param valueStart
202+
* where the value starts in the header
203+
* @param valueEnd
204+
* where the value ends in the header
200205
*/
201-
public void appendAttribute(String header, int keyStart, int keyEnd,
202-
String value) {
203-
setCookieAttribute(header, keyStart, keyEnd, value);
204-
}
205-
206-
private void setCookieAttribute(String header, int keyStart,
207-
int keyEnd, String value) {
206+
public void appendAttribute(int keyStart, int keyEnd, int valueStart, int valueEnd) {
208207
int length = keyEnd - keyStart;
209208

210209
if (length == 4) {
211-
parse4(header, keyStart, value);
210+
parse4(keyStart, valueStart, valueEnd);
212211
} else if (length == 6) {
213-
parse6(header, keyStart, value);
212+
parse6(keyStart, valueStart, valueEnd);
214213
} else if (length == 7) {
215-
parse7(header, keyStart, value);
214+
parse7(keyStart, valueStart, valueEnd);
216215
} else if (length == 8) {
217-
parse8(header, keyStart, value);
216+
parse8(keyStart, valueStart, valueEnd);
218217
}
219218
}
220219

221-
private void parse4(String header, int nameStart, String value) {
220+
private void parse4(int nameStart, int valueStart, int valueEnd) {
222221
if (header.regionMatches(true, nameStart, CookieHeaderNames.PATH, 0, 4)) {
223-
path = value;
222+
path = computeValue(valueStart, valueEnd);
224223
}
225224
}
226225

227-
private void parse6(String header, int nameStart, String value) {
226+
private void parse6(int nameStart, int valueStart, int valueEnd) {
228227
if (header.regionMatches(true, nameStart, CookieHeaderNames.DOMAIN, 0, 5)) {
229-
domain = value.length() > 0 ? value.toString() : null;
228+
domain = computeValue(valueStart, valueEnd);
230229
} else if (header.regionMatches(true, nameStart, CookieHeaderNames.SECURE, 0, 5)) {
231230
secure = true;
232231
}
233232
}
234233

235-
private void setExpire(String value) {
236-
expires = value;
237-
}
238-
239234
private void setMaxAge(String value) {
240235
try {
241236
maxAge = Math.max(Long.valueOf(value), 0L);
@@ -244,18 +239,23 @@ private void setMaxAge(String value) {
244239
}
245240
}
246241

247-
private void parse7(String header, int nameStart, String value) {
242+
private void parse7(int nameStart, int valueStart, int valueEnd) {
248243
if (header.regionMatches(true, nameStart, CookieHeaderNames.EXPIRES, 0, 7)) {
249-
setExpire(value);
244+
expiresStart = valueStart;
245+
expiresEnd = valueEnd;
250246
} else if (header.regionMatches(true, nameStart, CookieHeaderNames.MAX_AGE, 0, 7)) {
251-
setMaxAge(value);
247+
setMaxAge(computeValue(valueStart, valueEnd));
252248
}
253249
}
254250

255-
private void parse8(String header, int nameStart, String value) {
251+
private void parse8(int nameStart, int valueStart, int valueEnd) {
256252
if (header.regionMatches(true, nameStart, CookieHeaderNames.HTTPONLY, 0, 8)) {
257253
httpOnly = true;
258254
}
259255
}
256+
257+
private String computeValue(int valueStart, int valueEnd) {
258+
return valueStart == -1 || valueStart == valueEnd ? null : header.substring(valueStart, valueEnd);
259+
}
260260
}
261261
}

codec-http/src/test/java/io/netty/handler/codec/http/cookie/ClientCookieDecoderTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,4 +277,11 @@ public void testIgnoreEmptyDomain() {
277277
Cookie cookie = ClientCookieDecoder.STRICT.decode(emptyDomain);
278278
assertNull(cookie.domain());
279279
}
280+
281+
@Test
282+
public void testIgnoreEmptyPath() {
283+
String emptyPath = "sessionid=OTY4ZDllNTgtYjU3OC00MWRjLTkzMWMtNGUwNzk4MTY0MTUw;Domain=;Path=";
284+
Cookie cookie = ClientCookieDecoder.STRICT.decode(emptyPath);
285+
assertNull(cookie.path());
286+
}
280287
}

0 commit comments

Comments
 (0)