io.muserver.ParameterizedHeader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mu-server Show documentation
Show all versions of mu-server Show documentation
A simple but powerful web server framework
package io.muserver;
import java.util.*;
import static io.muserver.Mutils.notNull;
import static io.muserver.ParseUtils.isOWS;
import static io.muserver.ParseUtils.isTChar;
import static java.util.Collections.emptyMap;
/**
* A utility class to parse headers that are of the format param1, param2=value, param3="quoted string"
* such as Cache-Control etc.
* @see ParameterizedHeaderWithValue
*/
public class ParameterizedHeader {
private final Map parameters;
/**
* Creates a value with parameters
*
* @param parameters A map of parameters, such as charset: UTF-8
*/
private ParameterizedHeader(Map parameters) {
notNull("parameters", parameters);
this.parameters = parameters;
}
/**
* @return Gets all the parameters
*/
public Map parameters() {
return parameters;
}
/**
* @param name The name of the parameter to get
* @return Gets a single parameter, or null if there is no value
*/
public String parameter(String name) {
return parameters.get(name);
}
/**
* @param name The name of the parameter to get
* @param defaultValue The value to return if no parameter was set
* @return Gets a single parameter, or null if there is no value
*/
public String parameter(String name, String defaultValue) {
return parameters.getOrDefault(name, defaultValue);
}
/**
* @param name The name of the parameter to look up
* @return True if the parameter exists (with or without a value); otherwise false
*/
public boolean hasParameter(String name) {
return parameters.containsKey(name);
}
/**
* @return Gets the parameters in the order declared (without the parameter values)
*/
public List parameterNames() {
return new ArrayList<>(parameters.keySet());
}
private enum State {PARAM_NAME, PARAM_VALUE}
/**
* Converts a comma-separated list of param names (with optional values) into a Parameterized Header
* Null or blank strings return value with an empty parameter map.
* @param input The value to parse
* @return An object containing a map of name/value pairs (where values may be null)
* @throws IllegalArgumentException The value cannot be parsed
*/
public static ParameterizedHeader fromString(String input) {
if (input == null || input.trim().isEmpty()) {
return new ParameterizedHeader(emptyMap());
}
StringBuilder buffer = new StringBuilder();
Map parameters = new LinkedHashMap<>(); // keeps insertion order
State state = State.PARAM_NAME;
String paramName = null;
boolean isQuotedString = false;
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
if (state == State.PARAM_NAME) {
if (c == ',') {
if (buffer.length() > 0) {
parameters.put(buffer.toString(), null);
buffer.setLength(0);
paramName = null;
}
} else if (c == '=') {
paramName = buffer.toString();
if (paramName.isEmpty()) {
throw new IllegalArgumentException("Nameless values not allowed");
}
buffer.setLength(0);
state = State.PARAM_VALUE;
} else if (isTChar(c)) {
buffer.append(c);
} else if (isOWS(c)) {
// ignore it
} else {
throw new IllegalArgumentException("Got ascii " + ((int) c) + " while in " + state);
}
} else {
boolean isFirst = !isQuotedString && buffer.length() == 0;
if (isFirst && isOWS(c)) {
// ignore it
} else if (isFirst && c == '"') {
isQuotedString = true;
} else {
if (isQuotedString) {
char lastChar = input.charAt(i - 1);
if (c == '\\') {
// don't append
} else if (lastChar == '\\') {
buffer.append(c);
} else if (c == '"') {
// this is the end, but we'll update on the next go
isQuotedString = false;
} else {
buffer.append(c);
}
} else {
if (c == ',') {
parameters.put(paramName, buffer.toString());
buffer.setLength(0);
paramName = null;
state = State.PARAM_NAME;
} else if (isTChar(c)) {
buffer.append(c);
} else if (isOWS(c)) {
// ignore it
} else {
throw new IllegalArgumentException("Got character code " + ((int) c) + " (" + c + ") while parsing parameter value");
}
}
}
}
}
if (state == State.PARAM_VALUE) {
parameters.put(paramName, buffer.toString());
buffer.setLength(0);
} else {
if (buffer.length() > 0) {
parameters.put(buffer.toString(), null);
}
}
return new ParameterizedHeader(parameters);
}
/**
* Converts the HeaderValue into a string, suitable for printing in an HTTP header.
*
* @return A String, such as "some-value" or "content-type:text/html;charset=UTF-8"
*/
public String toString() {
StringBuilder sb = new StringBuilder();
Map parameters = this.parameters();
for (Map.Entry entry : parameters.entrySet()) {
if (sb.length() > 0) {
sb.append(", ");
}
sb.append(entry.getKey());
String value = entry.getValue();
if (value != null) {
sb.append('=').append(ParseUtils.quoteIfNeeded(value));
}
}
return sb.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ParameterizedHeader that = (ParameterizedHeader) o;
return Objects.equals(parameters, that.parameters);
}
@Override
public int hashCode() {
return Objects.hash(parameters);
}
}