Skip to content

Commit

Permalink
Experiment providing random access to fields.
Browse files Browse the repository at this point in the history
Fix #11811 with javadoc and an optional random access implementation.
  • Loading branch information
gregw committed May 27, 2024
1 parent 7e39aad commit 2b41c6b
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -617,17 +617,17 @@ default Enumeration<String> getFieldNames()
default Set<String> getFieldNamesCollection()
{
Set<HttpHeader> seenByHeader = EnumSet.noneOf(HttpHeader.class);
Set<String> seenByName = null;
Set<String> buildByName = null;
List<String> list = new ArrayList<>(size());

for (HttpField f : this)
{
HttpHeader header = f.getHeader();
if (header == null)
{
if (seenByName == null)
seenByName = new TreeSet<>(String::compareToIgnoreCase);
if (seenByName.add(f.getName()))
if (buildByName == null)
buildByName = new TreeSet<>(String::compareToIgnoreCase);
if (buildByName.add(f.getName()))
list.add(f.getName());
}
else if (seenByHeader.add(header))
Expand All @@ -636,6 +636,8 @@ else if (seenByHeader.add(header))
}
}

Set<String> seenByName = buildByName;

// use the list to retain a rough ordering
return new AbstractSet<>()
{
Expand All @@ -650,6 +652,14 @@ public int size()
{
return list.size();
}

@Override
public boolean contains(Object o)
{
if (o instanceof String s)
return seenByName != null && seenByName.contains(s) || seenByHeader.contains(HttpHeader.CACHE.get(s));
return false;
}
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,15 +244,15 @@ public void set(HttpField field)
/**
* An immutable {@link HttpFields} instance, optimized for random field access.
*/
private static class RandomAccess implements HttpFields
public static class RandomAccess implements HttpFields
{
private final HttpFields _httpFields;
private final EnumMap<HttpHeader, HttpField> _enumMap = new EnumMap<>(HttpHeader.class);
private final Map<String, HttpField> _stringMap;

RandomAccess(org.eclipse.jetty.http.ImmutableHttpFields httpFields)
RandomAccess(HttpFields httpFields)
{
_httpFields = Objects.requireNonNull(httpFields);
_httpFields = Objects.requireNonNull(httpFields.asImmutable());
Map<String, HttpField> stringMap = null;
for (HttpField field : httpFields)
{
Expand Down Expand Up @@ -354,7 +354,16 @@ public ListIterator<HttpField> listIterator(int index)
@Override
public Set<String> getFieldNamesCollection()
{
LinkedHashSet<String> set = new LinkedHashSet<>();
LinkedHashSet<String> set = new LinkedHashSet<>()
{
@Override
public boolean contains(Object o)
{
if (o instanceof String s)
return _stringMap.containsKey(s) || _enumMap.containsKey(HttpHeader.CACHE.get(s));
return false;
}
};
TreeSet<String> seenByName = null;
for (HttpField field : _httpFields)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand Down Expand Up @@ -354,16 +355,27 @@ public void testCaseInsensitive()
assertThat(header.get("EXPECT"), is("100"));
assertThat(header.get("eXpEcT"), is("100"));
assertThat(header.get(HttpHeader.EXPECT), is("100"));
assertTrue(header.contains("expect"));
assertTrue(header.contains("Expect"));
assertTrue(header.contains("EXPECT"));
assertTrue(header.contains("eXpEcT"));

assertThat(header.get("random"), is("value"));
assertThat(header.get("Random"), is("value"));
assertThat(header.get("RANDOM"), is("value"));
assertThat(header.get("rAnDoM"), is("value"));
assertThat(header.get("RaNdOm"), is("value"));
assertTrue(header.contains("random"));
assertTrue(header.contains("Random"));
assertTrue(header.contains("RANDOM"));
assertTrue(header.contains("rAnDoM"));
assertTrue(header.contains("RaNdOm"));

assertThat(header.get("Accept-Charset"), is("UTF-8"));
assertThat(header.get("accept-charset"), is("UTF-8"));
assertThat(header.get(HttpHeader.ACCEPT_CHARSET), is("UTF-8"));
assertTrue(header.contains("Accept-Charset"));
assertTrue(header.contains("accept-charset"));

assertThat(header.getValuesList("Accept-Charset"), contains("UTF-8", "UTF-16"));
assertThat(header.getValuesList("accept-charset"), contains("UTF-8", "UTF-16"));
Expand All @@ -373,9 +385,19 @@ public void testCaseInsensitive()
assertThat(header.get("Foo-Bar"), is("one"));
assertThat(header.getValuesList("foo-bar"), contains("one", "two"));
assertThat(header.getValuesList("Foo-Bar"), contains("one", "two"));
assertTrue(header.contains("foo-bar"));
assertTrue(header.contains("Foo-Bar"));

// We know the order of the set is deterministic
assertThat(header.getFieldNamesCollection(), contains("expect", "RaNdOm", "Accept-Charset", "foo-bar"));
Set<String> names = header.getFieldNamesCollection();
assertThat(names, contains("expect", "RaNdOm", "Accept-Charset", "foo-bar"));
assertTrue(names.contains("expect"));
assertTrue(names.contains("Expect"));
assertTrue(names.contains("random"));
assertTrue(names.contains("accept-charset"));
assertTrue(names.contains("Accept-Charset"));
assertTrue(names.contains("foo-bar"));
assertTrue(names.contains("Foo-Bar"));
}

@ParameterizedTest
Expand Down Expand Up @@ -1492,16 +1514,27 @@ public void testRandomAccess()
assertThat(header.get("EXPECT"), is("100"));
assertThat(header.get("eXpEcT"), is("100"));
assertThat(header.get(HttpHeader.EXPECT), is("100"));
assertTrue(header.contains("expect"));
assertTrue(header.contains("Expect"));
assertTrue(header.contains("EXPECT"));
assertTrue(header.contains("eXpEcT"));

assertThat(header.get("random"), is("value"));
assertThat(header.get("Random"), is("value"));
assertThat(header.get("RANDOM"), is("value"));
assertThat(header.get("rAnDoM"), is("value"));
assertThat(header.get("RaNdOm"), is("value"));
assertTrue(header.contains("random"));
assertTrue(header.contains("Random"));
assertTrue(header.contains("RANDOM"));
assertTrue(header.contains("rAnDoM"));
assertTrue(header.contains("RaNdOm"));

assertThat(header.get("Accept-Charset"), is("UTF-8"));
assertThat(header.get("accept-charset"), is("UTF-8"));
assertThat(header.get(HttpHeader.ACCEPT_CHARSET), is("UTF-8"));
assertTrue(header.contains("Accept-Charset"));
assertTrue(header.contains("accept-charset"));

assertThat(header.getValuesList("Accept-Charset"), contains("UTF-8", "UTF-16"));
assertThat(header.getValuesList("accept-charset"), contains("UTF-8", "UTF-16"));
Expand All @@ -1511,8 +1544,18 @@ public void testRandomAccess()
assertThat(header.get("Foo-Bar"), is("one"));
assertThat(header.getValuesList("foo-bar"), contains("one", "two"));
assertThat(header.getValuesList("Foo-Bar"), contains("one", "two"));
assertTrue(header.contains("foo-bar"));
assertTrue(header.contains("Foo-Bar"));

// We know the order of the set is deterministic
assertThat(header.getFieldNamesCollection(), contains("Expect", "RaNdOm", "Accept-Charset", "foo-bar"));
Set<String> names = header.getFieldNamesCollection();
assertThat(names, contains("Expect", "RaNdOm", "Accept-Charset", "foo-bar"));
assertTrue(names.contains("expect"));
assertTrue(names.contains("Expect"));
assertTrue(names.contains("random"));
assertTrue(names.contains("accept-charset"));
assertTrue(names.contains("Accept-Charset"));
assertTrue(names.contains("foo-bar"));
assertTrue(names.contains("Foo-Bar"));
}
}

0 comments on commit 2b41c6b

Please sign in to comment.