io.vertx.ext.web.impl.ParsableHeaderValue Maven / Gradle / Ivy
package io.vertx.ext.web.impl;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import io.vertx.codegen.annotations.Nullable;
import io.vertx.ext.web.ParsedHeaderValue;
public class ParsableHeaderValue implements ParsedHeaderValue {
private final String headerContent;
protected String value;
private float weight;
private Map parameter;
private int paramsWeight;
public ParsableHeaderValue(String headerContent) {
Objects.requireNonNull(headerContent, "headerContent must not be null");
this.headerContent = headerContent;
value = null;
weight = -1;
parameter = Collections.emptyMap();
}
@Override
public String rawValue() {
return headerContent;
}
@Override
public String value() {
ensureHeaderProcessed();
return value;
}
@Override
public float weight() {
ensureHeaderProcessed();
return weight;
}
@Override
public boolean isPermitted() {
ensureHeaderProcessed();
// rfc7231 states the least possible number above 0 is 0.001
return weight < 0.001;
}
public String parameter(String key) {
ensureHeaderProcessed();
return parameter.get(key);
}
public Map parameters() {
ensureHeaderProcessed();
return Collections.unmodifiableMap(parameter);
}
public final boolean isMatchedBy(ParsedHeaderValue matchTry){
ParsableHeaderValue impl = (ParsableHeaderValue) matchTry;
return this.headerContent.equals(impl.headerContent) || isMatchedBy2(impl);
}
protected boolean isMatchedBy2(ParsableHeaderValue matchTry){
ensureHeaderProcessed();
if (matchTry.parameter.isEmpty()) {
return true;
}
if (parameter.isEmpty()) {
return false;
}
for (Entry requiredParameter : matchTry.parameter.entrySet()) {
String parameterValueToTest = parameter.get(requiredParameter.getKey());
String requiredParamVal = requiredParameter.getValue();
if (parameterValueToTest == null || (
!requiredParamVal.isEmpty() && !requiredParamVal.equalsIgnoreCase(parameterValueToTest))
){
return false;
}
}
return true;
}
@Override
public @Nullable T findMatchedBy(Collection matchTries) {
for (T matchTry : matchTries) {
if(isMatchedBy(matchTry)){
return matchTry;
}
}
return null;
}
private void ensureParameterIsHashMap() {
if(parameter.isEmpty()){
parameter = new HashMap<>();
}
}
protected void ensureHeaderProcessed() {
if(weight < 0){
// as per rfc7231, the default value is 1
weight = DEFAULT_WEIGHT;
HeaderParser.parseHeaderValue(
headerContent,
this::setValue,
this::setWeight,
this::addParameter
);
paramsWeight = parameter.isEmpty() ? 0 : 1;
}
}
public ParsableHeaderValue forceParse(){
ensureHeaderProcessed();
return this;
}
private void setValue(String value) {
this.value = value;
}
private void addParameter(String key, String value) {
ensureParameterIsHashMap();
if(value == null){
value = "";
paramsWeight = Math.max(1, paramsWeight);
} else {
paramsWeight = Math.max(2, paramsWeight);
}
parameter.put(key, value);
}
private void setWeight(float weight) {
// Keep between 0 and 1 while dropping after the 3rd digit to the right (rfc7231#section-5.3.1)
this.weight = ((int)((Math.max(0, Math.min(1, weight)) * 100)) / 100.0f);
}
public final int weightedOrder(){
ensureHeaderProcessed();
return (int)(weight() * 1000) + (weightedOrderPart2() * 10) + paramsWeight;
}
protected int weightedOrderPart2(){
return 0;
}
@Override
public int hashCode() {
return Objects.hash(headerContent);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof ParsableHeaderValue)) {
return false;
}
ParsableHeaderValue other = (ParsableHeaderValue) obj;
if (headerContent == null) {
return other.headerContent == null;
} else {
return headerContent.equals(other.headerContent);
}
}
}