Skip to content

Commit

Permalink
[UNDERTOW-2194] - improve cookie parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
baranowb committed Dec 15, 2022
1 parent d24d91f commit 76138d6
Show file tree
Hide file tree
Showing 8 changed files with 509 additions and 102 deletions.
12 changes: 6 additions & 6 deletions core/src/main/java/io/undertow/server/DelegatingIterable.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,21 @@
/**
* @author <a href="mailto:ropalka@redhat.com">Richard Opalka</a>
*/
final class DelegatingIterable<E> implements Iterable<E> {
final class DelegatingIterable<E,V> implements Iterable<V> {

private final Iterable<E> delegate;
private final MultiValueHashListStorage<E,V> delegate;

DelegatingIterable(final Iterable<E> delegate) {
DelegatingIterable(final MultiValueHashListStorage<E,V> delegate) {
this.delegate = delegate;
}

Iterable<E> getDelegate() {
MultiValueHashListStorage<E,V> getDelegate() {
return delegate;
}

@Override
public Iterator<E> iterator() {
return new ReadOnlyIterator(delegate.iterator());
public Iterator<V> iterator() {
return delegate.valuesIterator();
}

}
47 changes: 39 additions & 8 deletions core/src/main/java/io/undertow/server/HttpServerExchange.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@
import java.nio.channels.Channel;
import java.nio.channels.FileChannel;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
Expand Down Expand Up @@ -139,8 +142,8 @@ public final class HttpServerExchange extends AbstractAttachable {
private Map<String, Deque<String>> queryParameters;
private Map<String, Deque<String>> pathParameters;

private DelegatingIterable<Cookie> requestCookies;
private DelegatingIterable<Cookie> responseCookies;
private DelegatingIterable<String, Cookie> requestCookies;
private DelegatingIterable<String, Cookie> responseCookies;

private Map<String, Cookie> deprecatedRequestCookies;
private Map<String, Cookie> deprecatedResponseCookies;
Expand Down Expand Up @@ -1156,7 +1159,7 @@ public HttpServerExchange addPathParam(final String name, final String param) {
@Deprecated(since="2.2.0", forRemoval=true)
public Map<String, Cookie> getRequestCookies() {
if (deprecatedRequestCookies == null) {
deprecatedRequestCookies = new MapDelegatingToSet((Set<Cookie>)((DelegatingIterable<Cookie>)requestCookies()).getDelegate());
deprecatedRequestCookies = new MapDelegatingToMultiValueStorage(((DelegatingIterable<String,Cookie>)requestCookies()).getDelegate());
}
return deprecatedRequestCookies;
}
Expand All @@ -1179,7 +1182,7 @@ public HttpServerExchange setRequestCookie(final Cookie cookie) {
Rfc6265CookieSupport.validateDomain(cookie.getDomain());
}
}
((Set<Cookie>)((DelegatingIterable<Cookie>)requestCookies()).getDelegate()).add(cookie);
((DelegatingIterable<String,Cookie>)requestCookies()).getDelegate().put(cookie.getName(),cookie);
return this;
}

Expand All @@ -1196,13 +1199,41 @@ public Cookie getRequestCookie(final String name) {
return null;
}

public List<Cookie> getRequestCookies(final String name) {
if (name == null) return Collections.emptyList();
requestCookies();
final List<Cookie> modifiableList = (List<Cookie>) requestCookies.getDelegate().get(name);
return Collections.unmodifiableList(modifiableList);
}

public List<String> getRequestCookieNames() {
requestCookies();
//This will produce collapsed set of keys
final Set<String> modifiableList = requestCookies.getDelegate().keySet();
return Collections.unmodifiableList(new ArrayList<String>(modifiableList));
}

public List<Cookie> getResponseCookies(final String name) {
if (name == null) return Collections.emptyList();
responseCookies();
final List<Cookie> modifiableList = (List<Cookie>) responseCookies.getDelegate().get(name);
return Collections.unmodifiableList(modifiableList);
}

public List<String> getResponseCookieNames() {
responseCookies();
//This will produce collapsed set of keys
final Set<String> modifiableList = responseCookies.getDelegate().keySet();
return Collections.unmodifiableList(new ArrayList<String>(modifiableList));
}

/**
* Returns unmodifiable enumeration of request cookies.
* @return A read-only enumeration of request cookies
*/
public Iterable<Cookie> requestCookies() {
if (requestCookies == null) {
Set<Cookie> requestCookiesParam = new OverridableTreeSet<>();
MultiValueHashListStorage<String,Cookie> requestCookiesParam = new MultiValueHashListStorage<String, Cookie>();
requestCookies = new DelegatingIterable<>(requestCookiesParam);
Cookies.parseRequestCookies(
getConnection().getUndertowOptions().get(UndertowOptions.MAX_COOKIES, 200),
Expand Down Expand Up @@ -1230,7 +1261,7 @@ public HttpServerExchange setResponseCookie(final Cookie cookie) {
Rfc6265CookieSupport.validateDomain(cookie.getDomain());
}
}
((Set<Cookie>)((DelegatingIterable<Cookie>)responseCookies()).getDelegate()).add(cookie);
((DelegatingIterable<String,Cookie>)responseCookies()).getDelegate().put(cookie.getName(),cookie);
return this;
}

Expand All @@ -1241,7 +1272,7 @@ public HttpServerExchange setResponseCookie(final Cookie cookie) {
@Deprecated(since="2.2.0", forRemoval=true)
public Map<String, Cookie> getResponseCookies() {
if (deprecatedResponseCookies == null) {
deprecatedResponseCookies = new MapDelegatingToSet((Set<Cookie>)((DelegatingIterable<Cookie>)responseCookies()).getDelegate());
deprecatedResponseCookies = new MapDelegatingToMultiValueStorage(((DelegatingIterable<String,Cookie>)responseCookies()).getDelegate());
}
return deprecatedResponseCookies;
}
Expand All @@ -1252,7 +1283,7 @@ public Map<String, Cookie> getResponseCookies() {
*/
public Iterable<Cookie> responseCookies() {
if (responseCookies == null) {
responseCookies = new DelegatingIterable<>(new OverridableTreeSet<>());
responseCookies = new DelegatingIterable<>(new MultiValueHashListStorage<String,Cookie>());
}
return responseCookies;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package io.undertow.server;

import java.util.Collection;
import java.util.Map;
import java.util.Set;

@Deprecated
class MapDelegatingToMultiValueStorage<K, V> implements Map<K, V> {

private final MultiValueHashListStorage<K, V> target;

MapDelegatingToMultiValueStorage(MultiValueHashListStorage<K, V> target) {
super();
this.target = target;
}

@Override
public int size() {
// this wont be accurate
return target.size();
}

@Override
public boolean isEmpty() {
return target.isEmpty();
}

@Override
public boolean containsKey(Object key) {
return target.containsKey(key);
}

@Override
public boolean containsValue(Object value) {
return target.containsValue(value);
}

@Override
public V get(Object key) {
// this will roughly mimic it
Collection<V> lst = target.get((K) key);
if (lst != null && lst.size() > 0) {
return lst.iterator().next();
} else {
return null;
}
}

@Override
public V put(K key, V value) {
Collection<V> rems = target.removeAll(key);
target.put(key, value);
if (rems != null && rems.size() > 0) {
return rems.iterator().next();
} else {
return null;
}
}

@Override
public V remove(Object key) {
Collection<V> rems = target.removeAll(key);
if (rems != null && rems.size() > 0) {
return rems.iterator().next();
} else {
return null;
}
}

@Override
public void putAll(Map<? extends K, ? extends V> m) {
for(Entry<? extends K, ? extends V> vk:m.entrySet()) {
target.removeAll(vk.getKey());
}
for(Entry<? extends K, ? extends V> vk:m.entrySet()) {
target.put(vk.getKey(),vk.getValue());
}
}

@Override
public void clear() {
target.clear();
}

@Override
public Set<K> keySet() {
return target.keySet();
}

@Override
public Collection<V> values() {
throw new UnsupportedOperationException();
}

@Override
public Set<Entry<K, V>> entrySet() {
throw new RuntimeException();
}

}
Loading

0 comments on commit 76138d6

Please sign in to comment.