Add Server Cookie Parser overload for multiple cookies. (#9856)

Motivation:

Multiple cookie values can be present in a single header.

Modification:

Add `decodeAll` overload which returns all cookies

Result:

Fixes #7210

Note:

This change is not as perscriptive as the ideas brought up in the linked issue.  Changing the Set implementation or the equals/compareTo definition is likely a breaking change, so they are practical.
This commit is contained in:
Carl Mastrangelo 2019-12-10 02:32:45 -08:00 committed by Norman Maurer
parent f10bee9057
commit daa354d659
2 changed files with 48 additions and 5 deletions

View File

@ -17,7 +17,10 @@ package io.netty.handler.codec.http.cookie;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
@ -56,20 +59,41 @@ public final class ServerCookieDecoder extends CookieDecoder {
super(strict); super(strict);
} }
/**
* Decodes the specified Set-Cookie HTTP header value into a {@link Cookie}. Unlike {@link #decode(String)}, this
* includes all cookie values present, even if they have the same name.
*
* @return the decoded {@link Cookie}
*/
public List<Cookie> decodeAll(String header) {
List<Cookie> cookies = new ArrayList<>();
decode(cookies, header);
return Collections.unmodifiableList(cookies);
}
/** /**
* Decodes the specified Set-Cookie HTTP header value into a {@link Cookie}. * Decodes the specified Set-Cookie HTTP header value into a {@link Cookie}.
* *
* @return the decoded {@link Cookie} * @return the decoded {@link Cookie}
*/ */
public Set<Cookie> decode(String header) { public Set<Cookie> decode(String header) {
Set<Cookie> cookies = new TreeSet<>();
decode(cookies, header);
return cookies;
}
/**
* Decodes the specified Set-Cookie HTTP header value into a {@link Cookie}.
*
* @return the decoded {@link Cookie}
*/
private void decode(Collection<? super Cookie> cookies, String header) {
final int headerLen = requireNonNull(header, "header").length(); final int headerLen = requireNonNull(header, "header").length();
if (headerLen == 0) { if (headerLen == 0) {
return Collections.emptySet(); return;
} }
Set<Cookie> cookies = new TreeSet<>();
int i = 0; int i = 0;
boolean rfc2965Style = false; boolean rfc2965Style = false;
@ -149,7 +173,5 @@ public final class ServerCookieDecoder extends CookieDecoder {
cookies.add(cookie); cookies.add(cookie);
} }
} }
return cookies;
} }
} }

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.handler.codec.http.cookie; package io.netty.handler.codec.http.cookie;
import java.util.List;
import org.junit.Test; import org.junit.Test;
import java.util.Iterator; import java.util.Iterator;
@ -53,6 +54,26 @@ public class ServerCookieDecoderTest {
assertEquals("myValue3", cookie.value()); assertEquals("myValue3", cookie.value());
} }
@Test
public void testDecodingAllMultipleCookies() {
String c1 = "myCookie=myValue;";
String c2 = "myCookie=myValue2;";
String c3 = "myCookie=myValue3;";
List<Cookie> cookies = ServerCookieDecoder.STRICT.decodeAll(c1 + c2 + c3);
assertEquals(3, cookies.size());
Iterator<Cookie> it = cookies.iterator();
Cookie cookie = it.next();
assertNotNull(cookie);
assertEquals("myValue", cookie.value());
cookie = it.next();
assertNotNull(cookie);
assertEquals("myValue2", cookie.value());
cookie = it.next();
assertNotNull(cookie);
assertEquals("myValue3", cookie.value());
}
@Test @Test
public void testDecodingGoogleAnalyticsCookie() { public void testDecodingGoogleAnalyticsCookie() {
String source = String source =