Merge remote-tracking branch 'origin/jetty-9.4.x' into jetty-10.0.x

This commit is contained in:
gregw 2021-02-18 14:18:31 +01:00
commit 1113b15110
1 changed files with 89 additions and 35 deletions

View File

@ -16,13 +16,13 @@ package org.eclipse.jetty.http;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.function.ToIntFunction; import java.util.function.ToIntFunction;
import java.util.stream.Collectors;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import static java.lang.Integer.MIN_VALUE;
/** /**
* Implements a quoted comma separated list of quality values * Implements a quoted comma separated list of quality values
* in accordance with RFC7230 and RFC7231. * in accordance with RFC7230 and RFC7231.
@ -53,7 +53,8 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
return 3; return 3;
}; };
private final List<Double> _quality = new ArrayList<>(); private final List<QualityValue> _qualities = new ArrayList<>();
private QualityValue _lastQuality;
private boolean _sorted = false; private boolean _sorted = false;
private final ToIntFunction<String> _secondaryOrdering; private final ToIntFunction<String> _secondaryOrdering;
@ -62,7 +63,7 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
*/ */
public QuotedQualityCSV() public QuotedQualityCSV()
{ {
this((ToIntFunction)null); this((ToIntFunction<String>)null);
} }
/** /**
@ -83,32 +84,48 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
if ("*".equals(s)) if ("*".equals(s))
return preferredOrder.length; return preferredOrder.length;
return MIN_VALUE; return 0;
}); });
} }
/** /**
* Orders values with equal quality with the given function. * Orders values with equal quality with the given function.
* *
* @param secondaryOrdering Function to apply an ordering other than specified by quality * @param secondaryOrdering Function to apply an ordering other than specified by quality, highest values are sorted first.
*/ */
public QuotedQualityCSV(ToIntFunction<String> secondaryOrdering) public QuotedQualityCSV(ToIntFunction<String> secondaryOrdering)
{ {
this._secondaryOrdering = secondaryOrdering == null ? s -> 0 : secondaryOrdering; this._secondaryOrdering = secondaryOrdering == null ? s -> 0 : secondaryOrdering;
} }
@Override
protected void parsedValueAndParams(StringBuffer buffer)
{
super.parsedValueAndParams(buffer);
// Collect full value with parameters
_lastQuality = new QualityValue(_lastQuality._quality, buffer.toString(), _lastQuality._index);
_qualities.set(_lastQuality._index, _lastQuality);
}
@Override @Override
protected void parsedValue(StringBuffer buffer) protected void parsedValue(StringBuffer buffer)
{ {
super.parsedValue(buffer); super.parsedValue(buffer);
_sorted = false;
// This is the just the value, without parameters.
// Assume a quality of ONE // Assume a quality of ONE
_quality.add(1.0D); _lastQuality = new QualityValue(1.0D, buffer.toString(), _qualities.size());
_qualities.add(_lastQuality);
} }
@Override @Override
protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue) protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue)
{ {
_sorted = false;
if (paramName < 0) if (paramName < 0)
{ {
if (buffer.charAt(buffer.length() - 1) == ';') if (buffer.charAt(buffer.length() - 1) == ';')
@ -118,7 +135,7 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
buffer.charAt(paramName) == 'q' && paramValue > paramName && buffer.charAt(paramName) == 'q' && paramValue > paramName &&
buffer.length() >= paramName && buffer.charAt(paramName + 1) == '=') buffer.length() >= paramName && buffer.charAt(paramName + 1) == '=')
{ {
Double q; double q;
try try
{ {
q = (_keepQuotes && buffer.charAt(paramValue) == '"') q = (_keepQuotes && buffer.charAt(paramValue) == '"')
@ -133,8 +150,10 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
buffer.setLength(Math.max(0, paramName - 1)); buffer.setLength(Math.max(0, paramName - 1));
if (q != 1.0D) if (q != 1.0D)
// replace assumed quality {
_quality.set(_quality.size() - 1, q); _lastQuality = new QualityValue(q, buffer.toString(), _lastQuality._index);
_qualities.set(_lastQuality._index, _lastQuality);
}
} }
} }
@ -156,38 +175,73 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
protected void sort() protected void sort()
{ {
_values.clear();
_qualities.stream()
.filter((qv) -> qv._quality != 0.0D)
.sorted()
.map(QualityValue::getValue)
.collect(Collectors.toCollection(() -> _values));
_sorted = true; _sorted = true;
}
Double last = 0.0D; private class QualityValue implements Comparable<QualityValue>
int lastSecondaryOrder = Integer.MIN_VALUE; {
private final double _quality;
private final String _value;
private final int _index;
for (int i = _values.size(); i-- > 0; ) private QualityValue(double quality, String value, int index)
{ {
String v = _values.get(i); _quality = quality;
Double q = _quality.get(i); _value = value;
_index = index;
int compare = last.compareTo(q);
if (compare > 0 || (compare == 0 && _secondaryOrdering.applyAsInt(v) < lastSecondaryOrder))
{
_values.set(i, _values.get(i + 1));
_values.set(i + 1, v);
_quality.set(i, _quality.get(i + 1));
_quality.set(i + 1, q);
last = 0.0D;
lastSecondaryOrder = 0;
i = _values.size();
continue;
}
last = q;
lastSecondaryOrder = _secondaryOrdering.applyAsInt(v);
} }
int lastElement = _quality.size(); @Override
while (lastElement > 0 && _quality.get(--lastElement).equals(0.0D)) public int hashCode()
{ {
_quality.remove(lastElement); return Double.hashCode(_quality) ^ Objects.hash(_value, _index);
_values.remove(lastElement); }
@Override
public boolean equals(Object obj)
{
if (!(obj instanceof QualityValue))
return false;
QualityValue qv = (QualityValue)obj;
return _quality == qv._quality && Objects.equals(_value, qv._value) && Objects.equals(_index, qv._index);
}
private String getValue()
{
return _value;
}
@Override
public int compareTo(QualityValue o)
{
// sort highest quality first
int compare = Double.compare(o._quality, _quality);
if (compare == 0)
{
// then sort secondary order highest first
compare = Integer.compare(_secondaryOrdering.applyAsInt(o._value), _secondaryOrdering.applyAsInt(_value));
if (compare == 0)
// then sort index lowest first
compare = -Integer.compare(o._index, _index);
}
return compare;
}
@Override
public String toString()
{
return String.format("%s@%x[%s,q=%f,i=%d]",
getClass().getSimpleName(),
hashCode(),
_value,
_quality,
_index);
} }
} }
} }