
org.exquery.http.AcceptHeader Maven / Gradle / Ivy
The newest version!
/**
* Copyright © 2012, Adam Retter / EXQuery
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.exquery.http;
import java.util.*;
/**
* Representation of an HTTP Accept header.
*
* RFC 7231
*
* @author Adam Retter
*/
public class AcceptHeader {
private final static char PARAMETER_SEPARATOR = ';';
private final static char QUALITY_PARAMETER = 'q';
private final static char PARAMETER_KEY_VALUE_SEPARATOR = '=';
private final List accepts;
/**
* @param headerValue The value of the HTTP Accept header
*
* @throws IllegalArgumentException If the headerValue is not a valid value for an HTTP 1.1 Accept header
*/
public AcceptHeader(final String headerValue) {
accepts = AcceptHeaderParser.parse(headerValue);
//sort accepts by qualityFactor
Collections.sort(accepts);
}
public List getAccepts() {
return accepts;
}
public static class Accept implements Comparable {
private final static float DEFAULT_QUALITY_FACTOR = 1;
final String mediaRange;
/* @Nullable */ final Parameter[] parameters;
/* @Nullable */ final Weight weight;
public Accept(final String mediaRange) {
this(mediaRange, (Weight)null);
}
public Accept(final org.exquery.InternetMediaType internetMediaType) {
this(internetMediaType.getMediaType());
}
public Accept(final org.exquery.InternetMediaType internetMediaType, final Weight weight) {
this(internetMediaType.getMediaType(), weight);
}
public Accept(final org.exquery.InternetMediaType internetMediaType, final Parameter[] parameters) {
this(internetMediaType.getMediaType(), parameters);
}
public Accept(final String mediaRange, final Weight weight) {
this(mediaRange, null, weight);
}
public Accept(final String mediaRange, final Parameter[] parameters) {
this(mediaRange, parameters, null);
}
public Accept(final org.exquery.InternetMediaType internetMediaType, final float qualityFactor) {
this(internetMediaType.getMediaType(), new Weight(qualityFactor));
}
public Accept(final org.exquery.InternetMediaType internetMediaType, final int qualityFactor) {
this(internetMediaType.getMediaType(), new Weight(qualityFactor));
}
public Accept(final org.exquery.InternetMediaType internetMediaType, final Parameter[] parameters, final Weight weight) {
this(internetMediaType.getMediaType(), parameters, weight);
}
public Accept(final String mediaRange, final Parameter[] parameters, final Weight weight) {
this.mediaRange = mediaRange;
this.parameters = parameters;
this.weight = weight;
}
@Override
public int compareTo(final Accept other) {
final float thisQf = weight == null ? DEFAULT_QUALITY_FACTOR : weight.qvalue;
final float otherQf = other.weight == null ? DEFAULT_QUALITY_FACTOR : other.weight.qvalue;
int c = Float.compare(otherQf, thisQf);
if (c == 0) {
c = mediaRange.compareTo(other.mediaRange);
}
return c;
// return Math.round(otherQf * 10) - Math.round(thisQf * 10);
}
public String getMediaRange() {
return mediaRange;
}
public float getQualityFactor() {
return weight == null ? DEFAULT_QUALITY_FACTOR : weight.qvalue;
}
public Accept.Parameter[] getParameters() {
return parameters;
}
public Accept.Weight getWeight() {
return weight;
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder(getMediaRange());
if (getParameters() != null) {
for (final Accept.Parameter parameter : parameters) {
builder.append(PARAMETER_SEPARATOR);
builder.append(parameter.toString());
}
}
if (getWeight() != null) {
builder.append(PARAMETER_SEPARATOR);
builder.append(weight.toString());
}
return builder.toString();
}
@Override
public boolean equals(final Object other) {
if (this == other) {
return true;
}
if (other == null || getClass() != other.getClass()) {
return false;
}
final Accept otherAccept = (Accept) other;
return mediaRange.equals(otherAccept.mediaRange) &&
Arrays.equals(parameters, otherAccept.parameters) &&
(weight == otherAccept.weight || (weight != null && weight.equals(otherAccept.weight)));
}
@Override
public int hashCode() {
int result = 1;
result = 31 * result + this.mediaRange.hashCode();
result = 31 * result + Arrays.hashCode(parameters);
result = 31 * result + (weight != null ? weight.hashCode() : 0);
return result;
}
public static class Parameter {
final String name;
final String value;
public Parameter(final String name, final String value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public String getValue() {
return value;
}
@Override
public String toString() {
return name + PARAMETER_KEY_VALUE_SEPARATOR + value;
}
@Override
public boolean equals(final Object other) {
if (this == other) {
return true;
}
if (other == null || getClass() != other.getClass()) {
return false;
}
final Parameter otherParameter = (Parameter) other;
return name.equals(otherParameter.name) &&
value.equals(otherParameter.value);
}
@Override
public int hashCode() {
int hash = 7;
hash = 61 * hash + this.name.hashCode();
hash = 61 * hash + this.value.hashCode();
return hash;
}
}
public static class Weight {
final float qvalue;
final boolean intQValue;
final AcceptExt[] acceptExts;
public Weight (final float qvalue) {
this(qvalue, null);
}
public Weight (final int qvalue) {
this(qvalue, null);
}
public Weight (final int qvalue, final AcceptExt[] acceptExts) {
this(qvalue, true, acceptExts);
}
public Weight (final float qvalue, final AcceptExt[] acceptExts) {
this(qvalue, false, acceptExts);
}
private Weight (final float qvalue, final boolean intQValue, final AcceptExt[] acceptExts) {
this.qvalue = qvalue;
this.intQValue = intQValue;
this.acceptExts = acceptExts;
}
@Override
public String toString() {
if (acceptExts == null) {
if (intQValue) {
return "q=" + (int)qvalue;
} else {
return "q=" + qvalue;
}
} else {
final StringBuilder builder = new StringBuilder();
builder.append("q=");
if (intQValue) {
builder.append((int) qvalue);
} else {
builder.append(qvalue);
}
for (final AcceptExt acceptExt : acceptExts) {
builder.append(PARAMETER_SEPARATOR);
builder.append(acceptExt.toString());
}
return builder.toString();
}
}
@Override
public boolean equals(final Object other) {
if (this == other) {
return true;
}
if (other == null || getClass() != other.getClass()) {
return false;
}
final Weight otherWeight = (Weight) other;
return Float.compare(otherWeight.qvalue, qvalue) == 0 &&
Arrays.equals(acceptExts, otherWeight.acceptExts);
}
@Override
public int hashCode() {
int result = 1;
result = 31 * result + Float.floatToIntBits(qvalue);
result = 31 * result + Arrays.hashCode(acceptExts);
return result;
}
}
public static class AcceptExt {
final String name;
/* @Nullable */ final String value;
public AcceptExt(final String name) {
this(name, null);
}
public AcceptExt(final String name, /* @Nullable */ final String value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public String getValue() {
return value;
}
@Override
public String toString() {
if (value == null) {
return name;
} else {
return name + PARAMETER_KEY_VALUE_SEPARATOR + value;
}
}
@Override
public boolean equals(final Object other) {
if (this == other) {
return true;
}
if (other == null || getClass() != other.getClass()) {
return false;
}
final AcceptExt otherAcceptExt = (AcceptExt) other;
return name.equals(otherAcceptExt.name) &&
(value == otherAcceptExt.value
|| (value != null && value.equals(otherAcceptExt.value)));
}
@Override
public int hashCode() {
int hash = 7;
hash = 61 * hash + this.name.hashCode();
hash = 61 * hash + (this.value != null ? this.value.hashCode() : 0);
return hash;
}
}
}
public static class AcceptHeaderParser {
private enum ParserState {
INIT,
TYPE,
SUBTYPE,
FINISHING_SUBTYPE,
STARTING_PARAMETER,
PARAMETER_NAME,
PARAMETER_VALUE,
FINISHING_PARAMETER_VALUE,
MAYBE_WEIGHT_PARAMETER_NAME,
WEIGHT_PARAMETER_VALUE_INT,
WEIGHT_PARAMETER_VALUE_MAYBE_DECIMAL,
WEIGHT_PARAMETER_VALUE_ZERO_DECIMAL,
WEIGHT_PARAMETER_VALUE_ONE_DECIMAL,
QUOTED_STRING,
QUOTED_PAIR_2,
NEXT
}
private final static char SYMBOL_ACCEPT_SEPARATOR = ',';
private final static char SYMBOL_TYPE_SUBTYPE_SEP = '/';
private final static char SYMBOL_PARAMETER_SEP = ';';
private final static char SYMBOL_WEIGHT_PARAM_NAME = 'q';
private final static char SYMBOL_PARAM_NAME_VALUE_SEP = '=';
private final static char SYMBOL_DQUOTE = '"';
private final static char SYMBOL_BACKSLASH = '\\';
/**
* Parses the value of a HTTP Accept header
*
* @param headerValue the value of the HTTP Accept header
*
* @return the list of things that are acceptable
*
* @throws IllegalArgumentException if the header value does not meet the HTTP 1.1 (RFC 7231) standard
*/
public static List parse(final String headerValue) throws IllegalArgumentException {
ParserState state = ParserState.INIT;
ParserState prevState = null;
String type = null;
String subType = null;
String parameterName = null;
String parameterValue = null;
final StringBuilder buf = new StringBuilder();
boolean isAcceptExt = false;
Accept.Parameter[] parameters = null;
Accept.Weight weight = null;
final List accepts = new ArrayList();
for (int idx = 0; idx < headerValue.length(); idx++) {
final char c = headerValue.charAt(idx);
switch (state) {
case NEXT:
if (isOWS(c)) {
continue;
}
// NOTE: intentional fall-through
case INIT:
if (isTokenChar(c)) {
buf.append(c);
state = ParserState.TYPE;
} else {
throw new IllegalArgumentException("Non-Token character at index " + idx + " whilst looking for media-type at start of Accept Header: '" + c + "'");
}
break;
case TYPE:
if (c == SYMBOL_TYPE_SUBTYPE_SEP) {
type = buf.toString();
buf.setLength(0);
state = ParserState.SUBTYPE;
} else if (isTokenChar(c)) {
buf.append(c);
} else {
throw new IllegalArgumentException("Non-Token character at index " + idx + " whilst parsing type component of media-type: '" + c + "'");
}
break;
case FINISHING_SUBTYPE:
if (isOWS(c)) {
continue;
} else if(isTokenChar(c)) {
throw new IllegalArgumentException("Token character at index " + idx + " whilst parsing end of sub-type component of media-type: '" + c + "'");
}
// NOTE: intentional fall-through
case SUBTYPE:
if (c == SYMBOL_PARAMETER_SEP) {
subType = buf.toString();
buf.setLength(0);
state = ParserState.STARTING_PARAMETER;
} else if (c == SYMBOL_ACCEPT_SEPARATOR) {
subType = buf.toString();
buf.setLength(0);
state = ParserState.NEXT;
accepts.add(new Accept(type + '/' + subType, copyOf(parameters), weight));
type = null;
subType = null;
isAcceptExt = false;
parameters = null;
weight = null;
} else if (isOWS(c)) {
subType = buf.toString();
buf.setLength(0);
state = ParserState.FINISHING_SUBTYPE;
} else if(isTokenChar(c)) {
buf.appendCodePoint(c);
} else {
throw new IllegalArgumentException("Non-Token character at index " + idx + " whilst parsing sub-type component of media-type: '" + c + "'");
}
break;
case STARTING_PARAMETER:
if (isOWS(c)) {
continue;
} else {
state = ParserState.PARAMETER_NAME;
}
// NOTE: intentional fall-through
case PARAMETER_NAME:
if (c == SYMBOL_WEIGHT_PARAM_NAME) {
buf.append(c);
state = ParserState.MAYBE_WEIGHT_PARAMETER_NAME;
} else if (isTokenChar(c)) {
buf.append(c);
} else if (c == SYMBOL_PARAM_NAME_VALUE_SEP) {
parameterName = buf.toString();
buf.setLength(0);
state = ParserState.PARAMETER_VALUE;
} else if (isAcceptExt && (isOWS(c) || c == SYMBOL_PARAMETER_SEP)) {
parameterName = buf.toString();
buf.setLength(0);
state = ParserState.STARTING_PARAMETER;
weight = addAcceptExt(weight, parameterName, null);
parameterName = null;
parameterValue = null;
} else {
throw new IllegalArgumentException("Non-Token character at index " + idx + " whilst parsing parameter: '" + c + "'");
}
break;
case MAYBE_WEIGHT_PARAMETER_NAME:
if (c == SYMBOL_PARAM_NAME_VALUE_SEP) {
parameterName = buf.toString();
buf.setLength(0);
state = ParserState.WEIGHT_PARAMETER_VALUE_INT;
} else if (isTokenChar(c)) {
buf.append(c);
state = ParserState.PARAMETER_NAME;
} else {
throw new IllegalArgumentException("Non-Token character at index " + idx + " whilst parsing parameter: '" + c + "'");
}
break;
case FINISHING_PARAMETER_VALUE:
if (isOWS(c)) {
continue;
} else if(c == SYMBOL_DQUOTE) {
throw new IllegalArgumentException("Double-quote character at index " + idx + " whilst parsing end of parameter value: '" + c + "'");
} else if (isTokenChar(c)) {
throw new IllegalArgumentException("Token character at index " + idx + " whilst parsing end of parameter value: '" + c + "'");
}
// NOTE: intentional fall-through
case PARAMETER_VALUE:
if (c == SYMBOL_DQUOTE) {
prevState = state; // save the state, so we can come back when we finish the quoted string
state = ParserState.QUOTED_STRING;
} else if (isTokenChar(c)) {
buf.append(c);
} else if (c == SYMBOL_PARAMETER_SEP) {
if (buf.length() > 0) {
parameterValue = buf.toString();
}
buf.setLength(0);
if (isAcceptExt) {
weight = addAcceptExt(weight, parameterName, parameterValue);
} else {
parameters = addParameter(parameters, parameterName, parameterValue);
}
state = ParserState.STARTING_PARAMETER;
parameterName = null;
parameterValue = null;
} else if (c == SYMBOL_ACCEPT_SEPARATOR) {
if (buf.length() > 0) {
parameterValue = buf.toString();
}
buf.setLength(0);
if (isAcceptExt) {
weight = addAcceptExt(weight, parameterName, parameterValue);
} else {
parameters = addParameter(parameters, parameterName, parameterValue);
}
state = ParserState.NEXT;
accepts.add(new Accept(type + '/' + subType, copyOf(parameters), weight));
type = null;
subType = null;
isAcceptExt = false;
parameterName = null;
parameterValue = null;
parameters = null;
weight = null;
} else if (isOWS(c)) {
parameterValue = buf.toString();
buf.setLength(0);
if (isAcceptExt) {
weight = addAcceptExt(weight, parameterName, parameterValue);
} else {
parameters = addParameter(parameters, parameterName, parameterValue);
}
state = ParserState.FINISHING_PARAMETER_VALUE;
parameterName = null;
parameterValue = null;
}
break;
case WEIGHT_PARAMETER_VALUE_INT:
if (c == '0') {
buf.append(c);
prevState = ParserState.WEIGHT_PARAMETER_VALUE_ZERO_DECIMAL; // actually the next state ;-)
state = ParserState.WEIGHT_PARAMETER_VALUE_MAYBE_DECIMAL;
} else if (c == '1') {
buf.append(c);
prevState = ParserState.WEIGHT_PARAMETER_VALUE_ONE_DECIMAL; // actually the next state ;-)
state = ParserState.WEIGHT_PARAMETER_VALUE_MAYBE_DECIMAL;
} else {
throw new IllegalArgumentException("Illegal character at index " + idx + " whilst parsing weight accept-parameter value: '" + c + "'");
}
break;
case WEIGHT_PARAMETER_VALUE_MAYBE_DECIMAL:
if (c == '.') {
buf.append(c);
state = prevState;
} else if (isOWS(c) || c == SYMBOL_PARAMETER_SEP) {
// next must be an accept-ext
isAcceptExt = true;
if (buf.length() > 0) {
parameterValue = buf.toString();
}
buf.setLength(0);
weight = new Accept.Weight(Integer.parseInt(parameterValue));
state = ParserState.PARAMETER_NAME;
parameterName = null;
parameterValue = null;
} else if (c == SYMBOL_ACCEPT_SEPARATOR) {
if (buf.length() > 0) {
parameterValue = buf.toString();
}
buf.setLength(0);
weight = new Accept.Weight(Integer.parseInt(parameterValue));
state = ParserState.NEXT;
accepts.add(new Accept(type + '/' + subType, copyOf(parameters), weight));
type = null;
subType = null;
isAcceptExt = false;
parameterName = null;
parameterValue = null;
parameters = null;
weight = null;
} else {
throw new IllegalArgumentException("Illegal character at index " + idx + " whilst parsing weight accept-parameter value: '" + c + "'");
}
break;
case WEIGHT_PARAMETER_VALUE_ZERO_DECIMAL:
if (isDigit(c) && buf.length() < 6) {
buf.append(c);
} else if (isOWS(c) || c == SYMBOL_PARAMETER_SEP) {
// next must be an accept-ext
isAcceptExt = true;
if (buf.length() > 0) {
parameterValue = buf.toString();
}
buf.setLength(0);
weight = new Accept.Weight(Float.parseFloat(parameterValue));
state = ParserState.PARAMETER_NAME;
parameterName = null;
parameterValue = null;
} else if (c == SYMBOL_ACCEPT_SEPARATOR) {
if (buf.length() > 0) {
parameterValue = buf.toString();
}
buf.setLength(0);
weight = new Accept.Weight(Float.parseFloat(parameterValue));
state = ParserState.NEXT;
accepts.add(new Accept(type + '/' + subType, copyOf(parameters), weight));
type = null;
subType = null;
isAcceptExt = false;
parameterName = null;
parameterValue = null;
parameters = null;
weight = null;
} else {
throw new IllegalArgumentException("Illegal character at index " + idx + " whilst parsing weight accept-parameter value: '" + c + "'");
}
break;
case WEIGHT_PARAMETER_VALUE_ONE_DECIMAL:
if (c == '0' && buf.length() < 6) {
buf.append(c);
} else if (isOWS(c) || c == SYMBOL_PARAMETER_SEP) {
// next must be an accept-ext
isAcceptExt = true;
if (buf.length() > 0) {
parameterValue = buf.toString();
}
buf.setLength(0);
weight = new Accept.Weight(Float.parseFloat(parameterValue));
state = ParserState.PARAMETER_NAME;
parameterName = null;
parameterValue = null;
} else if (c == SYMBOL_ACCEPT_SEPARATOR) {
if (buf.length() > 0) {
parameterValue = buf.toString();
}
buf.setLength(0);
weight = new Accept.Weight(Float.parseFloat(parameterValue));
state = ParserState.NEXT;
accepts.add(new Accept(type + '/' + subType, copyOf(parameters), weight));
type = null;
subType = null;
isAcceptExt = false;
parameterName = null;
parameterValue = null;
parameters = null;
weight = null;
} else {
throw new IllegalArgumentException("Illegal character at index " + idx + " whilst parsing weight accept-parameter value: '" + c + "'");
}
break;
case QUOTED_PAIR_2:
if (isQuotedPair2(c)) {
buf.append(c);
state = ParserState.QUOTED_STRING;
} else {
throw new IllegalArgumentException("Illegal character at index " + idx + " whilst parsing quoted pair: '" + c + "'");
}
// NOTE: intentional fall-through
case QUOTED_STRING:
if (c == SYMBOL_DQUOTE) {
parameterValue = buf.toString();
buf.setLength(0);
if (isAcceptExt) {
weight = addAcceptExt(weight, parameterName, parameterValue);
} else {
parameters = addParameter(parameters, parameterName, parameterValue);
}
state = prevState;
parameterName = null;
parameterValue = null;
} else if (isQdText(c)) {
buf.append(c);
} else if (c == SYMBOL_BACKSLASH) {
buf.append(c);
state = ParserState.QUOTED_PAIR_2;
} else {
throw new IllegalArgumentException("Illegal character at index " + idx + " whilst parsing quoted string: '" + c + "'");
}
break;
}
}
if (type != null) {
if (subType == null) {
subType = buf.toString();
} else if (parameterValue == null) {
parameterValue = buf.toString();
if (parameterName.equals("" + QUALITY_PARAMETER)) {
if (weight == null) {
if (parameterValue.indexOf('.') != -1) {
weight = new Accept.Weight(Float.parseFloat(parameterValue));
} else {
weight = new Accept.Weight(Integer.parseInt(parameterValue));
}
}
} else {
if (isAcceptExt) {
weight = addAcceptExt(weight, parameterName, parameterValue);
} else {
parameters = addParameter(parameters, parameterName, parameterValue);
}
}
}
accepts.add(new Accept(type + '/' + subType, copyOf(parameters), weight));
type = null;
subType = null;
isAcceptExt = false;
parameterName = null;
parameterValue = null;
parameters = null;
weight = null;
}
return accepts;
}
private static boolean isTokenChar(final char c) {
return
isDigit(c)
|| (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') // ALPHA
|| c == '!'
|| c == '#'
|| c == '$'
|| c == '%'
|| c == '&'
|| c == '\''
|| c == '*'
|| c == '+'
|| c == '-'
|| c == '.'
|| c == '^'
|| c == '_'
|| c == '`'
|| c == '|'
|| c == '~';
}
private static boolean isDigit(final char c) {
return c >= '0' && c <= '9'; // DIGIT
}
private static boolean isOWS(final char c) {
return c == ' ' || c == '\t';
}
private static boolean isQdText(final char c) {
return
c == '\t'
|| c == ' '
|| c == 0x21
|| (c >= 0x23 && c <= 0x5B)
|| (c >= 0x5D && c <= 0x7E)
|| isObsText(c); // obs-text
}
private static boolean isObsText(final char c) {
return c >= 0x80 && c <= 0xFF;
}
private static boolean isQuotedPair2(final char c) {
return
c == '\t'
|| c == ' '
|| (c >= 0x20 && c <= 0x7F) // VCHAR
|| isObsText(c); // obs-text
}
private static Accept.Parameter[] addParameter(/* @Nullable */ Accept.Parameter[] parameters,
final String parameterName, final String parameterValue) {
if (parameters == null) {
parameters = new Accept.Parameter[1];
} else {
parameters = Arrays.copyOf(parameters, parameters.length + 1);
}
parameters[parameters.length - 1] = new Accept.Parameter(parameterName, parameterValue);
return parameters;
}
private static Accept.Weight addAcceptExt(final Accept.Weight weight,
final String name, /* @Nullable */ final String value) {
final Accept.AcceptExt[] acceptExts;
if (weight.acceptExts == null) {
acceptExts = new Accept.AcceptExt[1];
} else {
acceptExts = Arrays.copyOf(weight.acceptExts, weight.acceptExts.length + 1);
}
acceptExts[acceptExts.length - 1] = new Accept.AcceptExt(name, value);
return new Accept.Weight(weight.qvalue, weight.intQValue, acceptExts);
}
private static /* @Nullable */ T[] copyOf(/* @Nullable */ final T[] array) {
if (array == null) {
return null;
}
return Arrays.copyOf(array, array.length);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy