Merged branch 'jetty-9.4.x-5104-incorrect_via_header-2' into 'jetty-9.4.x-5104-incorrect_via_header'.
This commit is contained in:
commit
c3598e814b
|
@ -292,6 +292,11 @@ public class HttpField
|
||||||
return _name.equalsIgnoreCase(field.getName());
|
return _name.equalsIgnoreCase(field.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean is(String name)
|
||||||
|
{
|
||||||
|
return _name.equalsIgnoreCase(name);
|
||||||
|
}
|
||||||
|
|
||||||
private int nameHashCode()
|
private int nameHashCode()
|
||||||
{
|
{
|
||||||
int h = this.hash;
|
int h = this.hash;
|
||||||
|
|
|
@ -166,36 +166,56 @@ public class HttpFields implements Iterable<HttpField>
|
||||||
*/
|
*/
|
||||||
public void computeField(String name, BiFunction<String, List<HttpField>, HttpField> computeFn)
|
public void computeField(String name, BiFunction<String, List<HttpField>, HttpField> computeFn)
|
||||||
{
|
{
|
||||||
boolean found = false;
|
// Look for first occurrence
|
||||||
ListIterator<HttpField> iterator = listIterator();
|
int first = -1;
|
||||||
while (iterator.hasNext())
|
for (int i = 0; i < _size; i++)
|
||||||
{
|
{
|
||||||
HttpField field = iterator.next();
|
HttpField f = _fields[i];
|
||||||
if (field.getName().equalsIgnoreCase(name))
|
if (f.is(name))
|
||||||
{
|
{
|
||||||
if (found)
|
first = i;
|
||||||
{
|
break;
|
||||||
// Remove other headers with the same name, since
|
|
||||||
// we have computed one from all of them already.
|
|
||||||
iterator.remove();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
HttpField newField = computeFn.apply(name, Collections.unmodifiableList(getFields(name)));
|
|
||||||
if (newField == null)
|
|
||||||
iterator.remove();
|
|
||||||
else
|
|
||||||
iterator.set(newField);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found)
|
|
||||||
|
// If the header is not found, add a new one;
|
||||||
|
if (first < 0)
|
||||||
{
|
{
|
||||||
HttpField newField = computeFn.apply(name, null);
|
HttpField newField = computeFn.apply(name, null);
|
||||||
if (newField != null)
|
if (newField != null)
|
||||||
put(newField);
|
add(newField);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Are there any more occurrences?
|
||||||
|
List<HttpField> found = null;
|
||||||
|
for (int i = first + 1; i < _size; i++)
|
||||||
|
{
|
||||||
|
HttpField f = _fields[i];
|
||||||
|
if (f.is(name))
|
||||||
|
{
|
||||||
|
if (found == null)
|
||||||
|
{
|
||||||
|
found = new ArrayList<>();
|
||||||
|
found.add(_fields[first]);
|
||||||
|
}
|
||||||
|
// Remember and remove additional fields
|
||||||
|
found.add(f);
|
||||||
|
remove(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no additional fields were found, handle singleton case
|
||||||
|
if (found == null)
|
||||||
|
found = Collections.singletonList(_fields[first]);
|
||||||
|
else
|
||||||
|
found = Collections.unmodifiableList(found);
|
||||||
|
|
||||||
|
HttpField newField = computeFn.apply(name, found);
|
||||||
|
if (newField == null)
|
||||||
|
remove(first);
|
||||||
|
else
|
||||||
|
_fields[first] = newField;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int size()
|
public int size()
|
||||||
|
@ -277,7 +297,7 @@ public class HttpFields implements Iterable<HttpField>
|
||||||
for (int i = 0; i < _size; i++)
|
for (int i = 0; i < _size; i++)
|
||||||
{
|
{
|
||||||
HttpField f = _fields[i];
|
HttpField f = _fields[i];
|
||||||
if (f.getName().equalsIgnoreCase(name))
|
if (f.is(name))
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -305,7 +325,7 @@ public class HttpFields implements Iterable<HttpField>
|
||||||
for (int i = 0; i < _size; i++)
|
for (int i = 0; i < _size; i++)
|
||||||
{
|
{
|
||||||
HttpField f = _fields[i];
|
HttpField f = _fields[i];
|
||||||
if (f.getName().equalsIgnoreCase(name))
|
if (f.is(name))
|
||||||
{
|
{
|
||||||
if (fields == null)
|
if (fields == null)
|
||||||
fields = new ArrayList<>();
|
fields = new ArrayList<>();
|
||||||
|
@ -342,7 +362,7 @@ public class HttpFields implements Iterable<HttpField>
|
||||||
for (int i = _size; i-- > 0; )
|
for (int i = _size; i-- > 0; )
|
||||||
{
|
{
|
||||||
HttpField f = _fields[i];
|
HttpField f = _fields[i];
|
||||||
if (f.getName().equalsIgnoreCase(name) && f.contains(value))
|
if (f.is(name) && f.contains(value))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -364,7 +384,7 @@ public class HttpFields implements Iterable<HttpField>
|
||||||
for (int i = _size; i-- > 0; )
|
for (int i = _size; i-- > 0; )
|
||||||
{
|
{
|
||||||
HttpField f = _fields[i];
|
HttpField f = _fields[i];
|
||||||
if (f.getName().equalsIgnoreCase(name))
|
if (f.is(name))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -398,7 +418,7 @@ public class HttpFields implements Iterable<HttpField>
|
||||||
for (int i = 0; i < _size; i++)
|
for (int i = 0; i < _size; i++)
|
||||||
{
|
{
|
||||||
HttpField f = _fields[i];
|
HttpField f = _fields[i];
|
||||||
if (f.getName().equalsIgnoreCase(header))
|
if (f.is(header))
|
||||||
return f.getValue();
|
return f.getValue();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -434,7 +454,7 @@ public class HttpFields implements Iterable<HttpField>
|
||||||
for (int i = 0; i < _size; i++)
|
for (int i = 0; i < _size; i++)
|
||||||
{
|
{
|
||||||
HttpField f = _fields[i];
|
HttpField f = _fields[i];
|
||||||
if (f.getName().equalsIgnoreCase(name))
|
if (f.is(name))
|
||||||
{
|
{
|
||||||
if (list == null)
|
if (list == null)
|
||||||
list = new ArrayList<>(size() - i);
|
list = new ArrayList<>(size() - i);
|
||||||
|
@ -489,7 +509,7 @@ public class HttpFields implements Iterable<HttpField>
|
||||||
for (int i = 0; i < _size; i++)
|
for (int i = 0; i < _size; i++)
|
||||||
{
|
{
|
||||||
HttpField f = _fields[i];
|
HttpField f = _fields[i];
|
||||||
if (f.getName().equalsIgnoreCase(name))
|
if (f.is(name))
|
||||||
{
|
{
|
||||||
if (existing == null)
|
if (existing == null)
|
||||||
existing = new QuotedCSV(false);
|
existing = new QuotedCSV(false);
|
||||||
|
@ -577,7 +597,7 @@ public class HttpFields implements Iterable<HttpField>
|
||||||
QuotedCSV values = null;
|
QuotedCSV values = null;
|
||||||
for (HttpField f : this)
|
for (HttpField f : this)
|
||||||
{
|
{
|
||||||
if (f.getName().equalsIgnoreCase(name))
|
if (f.is(name))
|
||||||
{
|
{
|
||||||
if (values == null)
|
if (values == null)
|
||||||
values = new QuotedCSV(keepQuotes);
|
values = new QuotedCSV(keepQuotes);
|
||||||
|
@ -635,7 +655,7 @@ public class HttpFields implements Iterable<HttpField>
|
||||||
QuotedQualityCSV values = null;
|
QuotedQualityCSV values = null;
|
||||||
for (HttpField f : this)
|
for (HttpField f : this)
|
||||||
{
|
{
|
||||||
if (f.getName().equalsIgnoreCase(name))
|
if (f.is(name))
|
||||||
{
|
{
|
||||||
if (values == null)
|
if (values == null)
|
||||||
values = new QuotedQualityCSV();
|
values = new QuotedQualityCSV();
|
||||||
|
@ -657,7 +677,7 @@ public class HttpFields implements Iterable<HttpField>
|
||||||
{
|
{
|
||||||
final HttpField f = _fields[i];
|
final HttpField f = _fields[i];
|
||||||
|
|
||||||
if (f.getName().equalsIgnoreCase(name) && f.getValue() != null)
|
if (f.is(name) && f.getValue() != null)
|
||||||
{
|
{
|
||||||
final int first = i;
|
final int first = i;
|
||||||
return new Enumeration<String>()
|
return new Enumeration<String>()
|
||||||
|
@ -673,7 +693,7 @@ public class HttpFields implements Iterable<HttpField>
|
||||||
while (i < _size)
|
while (i < _size)
|
||||||
{
|
{
|
||||||
field = _fields[i++];
|
field = _fields[i++];
|
||||||
if (field.getName().equalsIgnoreCase(name) && field.getValue() != null)
|
if (field.is(name) && field.getValue() != null)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
field = null;
|
field = null;
|
||||||
|
@ -887,8 +907,7 @@ public class HttpFields implements Iterable<HttpField>
|
||||||
if (f.getHeader() == name)
|
if (f.getHeader() == name)
|
||||||
{
|
{
|
||||||
removed = f;
|
removed = f;
|
||||||
_size--;
|
remove(i);
|
||||||
System.arraycopy(_fields, i + 1, _fields, i, _size - i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return removed;
|
return removed;
|
||||||
|
@ -906,16 +925,22 @@ public class HttpFields implements Iterable<HttpField>
|
||||||
for (int i = _size; i-- > 0; )
|
for (int i = _size; i-- > 0; )
|
||||||
{
|
{
|
||||||
HttpField f = _fields[i];
|
HttpField f = _fields[i];
|
||||||
if (f.getName().equalsIgnoreCase(name))
|
if (f.is(name))
|
||||||
{
|
{
|
||||||
removed = f;
|
removed = f;
|
||||||
_size--;
|
remove(i);
|
||||||
System.arraycopy(_fields, i + 1, _fields, i, _size - i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return removed;
|
return removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void remove(int i)
|
||||||
|
{
|
||||||
|
_size--;
|
||||||
|
System.arraycopy(_fields, i + 1, _fields, i, _size - i);
|
||||||
|
_fields[_size] = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a header as an long value. Returns the value of an integer field or -1 if not found. The
|
* Get a header as an long value. Returns the value of an integer field or -1 if not found. The
|
||||||
* case of the field name is ignored.
|
* case of the field name is ignored.
|
||||||
|
@ -1307,8 +1332,7 @@ public class HttpFields implements Iterable<HttpField>
|
||||||
{
|
{
|
||||||
if (_current < 0)
|
if (_current < 0)
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
_size--;
|
HttpFields.this.remove(_current);
|
||||||
System.arraycopy(_fields, _current + 1, _fields, _current, _size - _current);
|
|
||||||
_fields[_size] = null;
|
_fields[_size] = null;
|
||||||
_cursor = _current;
|
_cursor = _current;
|
||||||
_current = -1;
|
_current = -1;
|
||||||
|
|
|
@ -866,4 +866,32 @@ public class HttpFieldsTest
|
||||||
assertThat(header.stream().count(), is(3L));
|
assertThat(header.stream().count(), is(3L));
|
||||||
assertThat(header.stream().map(HttpField::getName).filter("name2"::equalsIgnoreCase).count(), is(1L));
|
assertThat(header.stream().map(HttpField::getName).filter("name2"::equalsIgnoreCase).count(), is(1L));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCompute()
|
||||||
|
{
|
||||||
|
HttpFields header = new HttpFields();
|
||||||
|
assertThat(header.size(), is(0));
|
||||||
|
|
||||||
|
header.computeField("Test", (n, f) -> null);
|
||||||
|
assertThat(header.size(), is(0));
|
||||||
|
|
||||||
|
header.add(new HttpField("Before", "value"));
|
||||||
|
assertThat(header.stream().map(HttpField::toString).collect(Collectors.toList()), contains("Before: value"));
|
||||||
|
|
||||||
|
header.computeField("Test", (n, f) -> new HttpField(n, "one"));
|
||||||
|
assertThat(header.stream().map(HttpField::toString).collect(Collectors.toList()), contains("Before: value", "Test: one"));
|
||||||
|
|
||||||
|
header.add(new HttpField("After", "value"));
|
||||||
|
assertThat(header.stream().map(HttpField::toString).collect(Collectors.toList()), contains("Before: value", "Test: one", "After: value"));
|
||||||
|
|
||||||
|
header.add(new HttpField("Test", "extra"));
|
||||||
|
assertThat(header.stream().map(HttpField::toString).collect(Collectors.toList()), contains("Before: value", "Test: one", "After: value", "Test: extra"));
|
||||||
|
|
||||||
|
header.computeField("Test", (n, f) -> new HttpField("TEST", "count=" + f.size()));
|
||||||
|
assertThat(header.stream().map(HttpField::toString).collect(Collectors.toList()), contains("Before: value", "TEST: count=2", "After: value"));
|
||||||
|
|
||||||
|
header.computeField("TEST", (n, f) -> null);
|
||||||
|
assertThat(header.stream().map(HttpField::toString).collect(Collectors.toList()), contains("Before: value", "After: value"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue