add multi map convenience method to obtain all parameters from a http request

This commit is contained in:
Jörg Prante 2023-11-04 19:45:51 +01:00
parent 2b413def7a
commit ba332dd10b
6 changed files with 102 additions and 3 deletions

View file

@ -1,5 +1,5 @@
group = org.xbib group = org.xbib
name = net-http name = net-http
version = 4.0.2 version = 4.0.3
org.gradle.warning.mode = ALL org.gradle.warning.mode = ALL

View file

@ -3,5 +3,6 @@ dependencies {
api libs.config api libs.config
implementation libs.settings.datastructures.json implementation libs.settings.datastructures.json
implementation libs.settings.datastructures.yaml implementation libs.settings.datastructures.yaml
implementation libs.datastructures.tiny
implementation libs.datastructures.json.tiny implementation libs.datastructures.json.tiny
} }

View file

@ -26,6 +26,7 @@ module org.xbib.net.http.server {
requires org.xbib.net.mime; requires org.xbib.net.mime;
requires org.xbib.net.http; requires org.xbib.net.http;
requires org.xbib.datastructures.common; requires org.xbib.datastructures.common;
requires org.xbib.datastructures.tiny;
requires org.xbib.datastructures.json.tiny; requires org.xbib.datastructures.json.tiny;
requires org.xbib.config; requires org.xbib.config;
requires java.logging; requires java.logging;

View file

@ -2,27 +2,41 @@ package org.xbib.net.http.server;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.nio.charset.MalformedInputException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.nio.charset.UnmappableCharacterException;
import java.util.Collection;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.xbib.datastructures.common.MultiMap;
import org.xbib.datastructures.common.Pair; import org.xbib.datastructures.common.Pair;
import org.xbib.datastructures.json.tiny.Json;
import org.xbib.datastructures.json.tiny.JsonBuilder; import org.xbib.datastructures.json.tiny.JsonBuilder;
import org.xbib.datastructures.tiny.TinyList;
import org.xbib.datastructures.tiny.TinyMultiMap;
import org.xbib.net.Attributes; import org.xbib.net.Attributes;
import org.xbib.net.Parameter; import org.xbib.net.Parameter;
import org.xbib.net.ParameterException; import org.xbib.net.ParameterException;
import org.xbib.net.PercentDecoder;
import org.xbib.net.URL; import org.xbib.net.URL;
import org.xbib.net.http.HttpHeaderNames;
import org.xbib.net.http.HttpHeaderValues;
import org.xbib.net.http.HttpHeaders; import org.xbib.net.http.HttpHeaders;
import org.xbib.net.http.HttpMethod; import org.xbib.net.http.HttpMethod;
import org.xbib.net.http.HttpVersion; import org.xbib.net.http.HttpVersion;
import org.xbib.net.http.server.auth.BaseAttributes; import org.xbib.net.http.server.auth.BaseAttributes;
import org.xbib.net.http.server.route.HttpRouterContext; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.util.ExceptionFormatter;
public abstract class BaseHttpRequest implements HttpRequest { public abstract class BaseHttpRequest implements HttpRequest {
private static final Logger logger = Logger.getLogger(BaseHttpRequest.class.getName());
protected final BaseHttpRequestBuilder builder; protected final BaseHttpRequestBuilder builder;
private final Attributes attributes; private final Attributes attributes;
@ -157,7 +171,7 @@ public abstract class BaseHttpRequest implements HttpRequest {
jsonBuilder.buildKey("sequenceid").buildValue(builder.sequenceId); jsonBuilder.buildKey("sequenceid").buildValue(builder.sequenceId);
jsonBuilder.buildKey("streamid").buildValue(builder.streamId); jsonBuilder.buildKey("streamid").buildValue(builder.streamId);
jsonBuilder.buildKey("requestid").buildValue(builder.requestId); jsonBuilder.buildKey("requestid").buildValue(builder.requestId);
// body may be large // body may be large, skip it
//jsonBuilder.buildKey("encoding").buildValue("ISO-8859-1"); //jsonBuilder.buildKey("encoding").buildValue("ISO-8859-1");
//jsonBuilder.buildKey("body").buildValue(StandardCharsets.ISO_8859_1.decode(builder.getBody()).toString()); //jsonBuilder.buildKey("body").buildValue(StandardCharsets.ISO_8859_1.decode(builder.getBody()).toString());
jsonBuilder.endMap(); jsonBuilder.endMap();
@ -166,4 +180,83 @@ public abstract class BaseHttpRequest implements HttpRequest {
} }
return jsonBuilder.build(); return jsonBuilder.build();
} }
@SuppressWarnings("unchecked")
@Override
public MultiMap<String, Object> asMultiMap() {
PercentDecoder percentDecoder = new PercentDecoder();
MultiMap<String, Object> multiMap = new ParameterMap();
String contentType = getHeaders().get(HttpHeaderNames.CONTENT_TYPE);
if (getMethod() == HttpMethod.POST &&
contentType != null && contentType.contains(HttpHeaderValues.APPLICATION_JSON)) {
String bodyAsChars = getBodyAsChars(StandardCharsets.UTF_8).toString();
Map<String, Object> map = Json.toMap(bodyAsChars);
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (entry.getValue() instanceof Iterable) {
multiMap.putAll(entry.getKey(), (Iterable<Object>) entry.getValue());
} else {
multiMap.put(entry.getKey(), entry.getValue());
}
}
}
try {
toMultiMapEntry(getParameter().get(Parameter.Domain.PATH),
percentDecoder,
false,
multiMap);
toMultiMapEntry(getParameter().get(Parameter.Domain.FORM),
percentDecoder,
HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED.equals(contentType),
multiMap);
toMultiMapEntry(getParameter().get(Parameter.Domain.QUERY),
percentDecoder,
HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED.equals(contentType),
multiMap);
} catch (ParameterException e) {
logger.log(Level.WARNING, e.getMessage(), ExceptionFormatter.format(e));
}
return multiMap;
}
@SuppressWarnings("unchecked")
private static void toMultiMapEntry(Parameter parameter,
PercentDecoder percentDecoder,
boolean isFormEncoded,
MultiMap<String, Object> multiMap) {
for (Pair<String, Object> entry : parameter) {
try {
List<Object> list;
Object value = entry.getValue();
if (value instanceof List) {
list = (List<Object>) value;
} else if (value != null) {
list = List.of(value);
} else {
list = List.of();
}
for (Object object : list) {
String string = object.toString();
if (isFormEncoded) {
string = string.replace('+', ' ');
}
multiMap.put(entry.getKey(), percentDecoder.decode(string));
}
} catch (MalformedInputException | UnmappableCharacterException e) {
logger.log(Level.WARNING, "unable to percent decode parameter: " +
entry.getKey() + "=" + entry.getValue());
}
}
}
private static class ParameterMap extends TinyMultiMap<String, Object> {
public ParameterMap() {
}
@Override
protected Collection<Object> newValues() {
// keep values with multiple occurences
return TinyList.builder();
}
}
} }

View file

@ -3,6 +3,7 @@ package org.xbib.net.http.server;
import java.io.InputStream; import java.io.InputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.List; import java.util.List;
import org.xbib.datastructures.common.MultiMap;
import org.xbib.net.Attributes; import org.xbib.net.Attributes;
import org.xbib.net.Parameter; import org.xbib.net.Parameter;
import org.xbib.net.Request; import org.xbib.net.Request;
@ -45,4 +46,6 @@ public interface HttpRequest extends Request {
Attributes getAttributes(); Attributes getAttributes();
String asJson(); String asJson();
MultiMap<String, Object> asMultiMap();
} }

View file

@ -34,6 +34,7 @@ dependencyResolutionManagement {
library('net-security', 'org.xbib', 'net-security').versionRef('net') library('net-security', 'org.xbib', 'net-security').versionRef('net')
library('net-bouncycastle', 'org.xbib', 'net-bouncycastle').versionRef('net') library('net-bouncycastle', 'org.xbib', 'net-bouncycastle').versionRef('net')
library('datastructures-common', 'org.xbib', 'datastructures-common').versionRef('datastructures') library('datastructures-common', 'org.xbib', 'datastructures-common').versionRef('datastructures')
library('datastructures-tiny', 'org.xbib', 'datastructures-tiny').versionRef('datastructures')
library('datastructures-json-tiny', 'org.xbib', 'datastructures-json-tiny').versionRef('datastructures') library('datastructures-json-tiny', 'org.xbib', 'datastructures-json-tiny').versionRef('datastructures')
library('datastructures-yaml-tiny', 'org.xbib', 'datastructures-yaml-tiny').versionRef('datastructures') library('datastructures-yaml-tiny', 'org.xbib', 'datastructures-yaml-tiny').versionRef('datastructures')
library('config', 'org.xbib', 'config').versionRef('datastructures') library('config', 'org.xbib', 'config').versionRef('datastructures')