Merge remote-tracking branch 'origin/jetty-9.4.x' into jetty-10.0.x
This commit is contained in:
commit
1113b15110
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue