Skip to content

Commit

Permalink
Set-Cookie headers should not be combined (netty#8611)
Browse files Browse the repository at this point in the history
Motivation:

According to the HTTP spec set-cookie headers should not be combined
because they are not using the list syntax.

Modifications:

Do not combine set-cookie headers.

Result:

Set-Cookie headers won't be combined anymore
  • Loading branch information
madgnome authored and normanmaurer committed Dec 1, 2018
1 parent a0c3081 commit d05666a
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.util.List;
import java.util.Map;

import static io.netty.handler.codec.http.HttpHeaderNames.SET_COOKIE;
import static io.netty.util.AsciiString.CASE_INSENSITIVE_HASHER;
import static io.netty.util.internal.StringUtil.COMMA;
import static io.netty.util.internal.StringUtil.unescapeCsvFields;
Expand Down Expand Up @@ -87,7 +88,7 @@ public CombinedHttpHeadersImpl(HashingStrategy<CharSequence> nameHashingStrategy
@Override
public Iterator<CharSequence> valueIterator(CharSequence name) {
Iterator<CharSequence> itr = super.valueIterator(name);
if (!itr.hasNext()) {
if (!itr.hasNext() || cannotBeCombined(name)) {
return itr;
}
Iterator<CharSequence> unescapedItr = unescapeCsvFields(itr.next()).iterator();
Expand All @@ -100,7 +101,7 @@ public Iterator<CharSequence> valueIterator(CharSequence name) {
@Override
public List<CharSequence> getAll(CharSequence name) {
List<CharSequence> values = super.getAll(name);
if (values.isEmpty()) {
if (values.isEmpty() || cannotBeCombined(name)) {
return values;
}
if (values.size() != 1) {
Expand Down Expand Up @@ -213,9 +214,13 @@ public CombinedHttpHeadersImpl setObject(CharSequence name, Iterable<?> values)
return this;
}

private static boolean cannotBeCombined(CharSequence name) {
return SET_COOKIE.contentEqualsIgnoreCase(name);
}

private CombinedHttpHeadersImpl addEscapedValue(CharSequence name, CharSequence escapedValue) {
CharSequence currentValue = super.get(name);
if (currentValue == null) {
if (currentValue == null || cannotBeCombined(name)) {
super.add(name, escapedValue);
} else {
super.set(name, commaSeparateEscapedValues(currentValue, escapedValue));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@
import java.util.Collections;
import java.util.Iterator;

import static io.netty.handler.codec.http.HttpHeaderNames.SET_COOKIE;
import static io.netty.util.AsciiString.contentEquals;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

public class CombinedHttpHeadersTest {
Expand Down Expand Up @@ -66,6 +69,28 @@ public void addCombinedHeadersWhenNotEmpty() {
assertEquals("a,b,c", headers.get(HEADER_NAME).toString());
}

@Test
public void dontCombineSetCookieHeaders() {
final CombinedHttpHeaders headers = newCombinedHttpHeaders();
headers.add(SET_COOKIE, "a");
final CombinedHttpHeaders otherHeaders = newCombinedHttpHeaders();
otherHeaders.add(SET_COOKIE, "b");
otherHeaders.add(SET_COOKIE, "c");
headers.add(otherHeaders);
assertThat(headers.getAll(SET_COOKIE), hasSize(3));
}

@Test
public void dontCombineSetCookieHeadersRegardlessOfCase() {
final CombinedHttpHeaders headers = newCombinedHttpHeaders();
headers.add("Set-Cookie", "a");
final CombinedHttpHeaders otherHeaders = newCombinedHttpHeaders();
otherHeaders.add("set-cookie", "b");
otherHeaders.add("SET-COOKIE", "c");
headers.add(otherHeaders);
assertThat(headers.getAll(SET_COOKIE), hasSize(3));
}

@Test
public void setCombinedHeadersWhenNotEmpty() {
final CombinedHttpHeaders headers = newCombinedHttpHeaders();
Expand Down Expand Up @@ -274,6 +299,15 @@ public void testGetAll() {
assertEquals(Arrays.asList("a,b,c"), headers.getAll(HEADER_NAME));
}

@Test
public void getAllDontCombineSetCookie() {
final CombinedHttpHeaders headers = newCombinedHttpHeaders();
headers.add(SET_COOKIE, "a");
headers.add(SET_COOKIE, "b");
assertThat(headers.getAll(SET_COOKIE), hasSize(2));
assertEquals(Arrays.asList("a", "b"), headers.getAll(SET_COOKIE));
}

@Test
public void owsTrimming() {
final CombinedHttpHeaders headers = newCombinedHttpHeaders();
Expand Down Expand Up @@ -314,6 +348,22 @@ public void valueIterator() {
assertValueIterator(headers.valueCharSequenceIterator(HEADER_NAME));
}

@Test
public void nonCombinableHeaderIterator() {
final CombinedHttpHeaders headers = newCombinedHttpHeaders();
headers.add(SET_COOKIE, "c");
headers.add(SET_COOKIE, "b");
headers.add(SET_COOKIE, "a");

final Iterator<String> strItr = headers.valueStringIterator(SET_COOKIE);
assertTrue(strItr.hasNext());
assertEquals("a", strItr.next());
assertTrue(strItr.hasNext());
assertEquals("b", strItr.next());
assertTrue(strItr.hasNext());
assertEquals("c", strItr.next());
}

private static void assertValueIterator(Iterator<? extends CharSequence> strItr) {
assertTrue(strItr.hasNext());
assertEquals("a", strItr.next());
Expand Down

0 comments on commit d05666a

Please sign in to comment.