Skip to content

Commit ba332dd

Browse files
committed
add multi map convenience method to obtain all parameters from a http request
1 parent 2b413de commit ba332dd

File tree

6 files changed

+102
-3
lines changed

6 files changed

+102
-3
lines changed

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
group = org.xbib
22
name = net-http
3-
version = 4.0.2
3+
version = 4.0.3
44

55
org.gradle.warning.mode = ALL

net-http-server/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ dependencies {
33
api libs.config
44
implementation libs.settings.datastructures.json
55
implementation libs.settings.datastructures.yaml
6+
implementation libs.datastructures.tiny
67
implementation libs.datastructures.json.tiny
78
}

net-http-server/src/main/java/module-info.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
requires org.xbib.net.mime;
2727
requires org.xbib.net.http;
2828
requires org.xbib.datastructures.common;
29+
requires org.xbib.datastructures.tiny;
2930
requires org.xbib.datastructures.json.tiny;
3031
requires org.xbib.config;
3132
requires java.logging;

net-http-server/src/main/java/org/xbib/net/http/server/BaseHttpRequest.java

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,41 @@
22

33
import java.io.IOException;
44
import java.net.InetSocketAddress;
5+
import java.nio.charset.MalformedInputException;
56
import java.nio.charset.StandardCharsets;
6-
import java.util.ArrayList;
7+
import java.nio.charset.UnmappableCharacterException;
8+
import java.util.Collection;
79
import java.util.LinkedHashMap;
810
import java.util.List;
911
import java.util.Map;
12+
import java.util.logging.Level;
13+
import java.util.logging.Logger;
1014
import java.util.stream.Collectors;
1115

16+
import org.xbib.datastructures.common.MultiMap;
1217
import org.xbib.datastructures.common.Pair;
18+
import org.xbib.datastructures.json.tiny.Json;
1319
import org.xbib.datastructures.json.tiny.JsonBuilder;
20+
import org.xbib.datastructures.tiny.TinyList;
21+
import org.xbib.datastructures.tiny.TinyMultiMap;
1422
import org.xbib.net.Attributes;
1523
import org.xbib.net.Parameter;
1624
import org.xbib.net.ParameterException;
25+
import org.xbib.net.PercentDecoder;
1726
import org.xbib.net.URL;
27+
import org.xbib.net.http.HttpHeaderNames;
28+
import org.xbib.net.http.HttpHeaderValues;
1829
import org.xbib.net.http.HttpHeaders;
1930
import org.xbib.net.http.HttpMethod;
2031
import org.xbib.net.http.HttpVersion;
2132
import org.xbib.net.http.server.auth.BaseAttributes;
2233
import org.xbib.net.http.server.route.HttpRouterContext;
34+
import org.xbib.net.util.ExceptionFormatter;
2335

2436
public abstract class BaseHttpRequest implements HttpRequest {
2537

38+
private static final Logger logger = Logger.getLogger(BaseHttpRequest.class.getName());
39+
2640
protected final BaseHttpRequestBuilder builder;
2741

2842
private final Attributes attributes;
@@ -157,7 +171,7 @@ public String asJson() {
157171
jsonBuilder.buildKey("sequenceid").buildValue(builder.sequenceId);
158172
jsonBuilder.buildKey("streamid").buildValue(builder.streamId);
159173
jsonBuilder.buildKey("requestid").buildValue(builder.requestId);
160-
// body may be large
174+
// body may be large, skip it
161175
//jsonBuilder.buildKey("encoding").buildValue("ISO-8859-1");
162176
//jsonBuilder.buildKey("body").buildValue(StandardCharsets.ISO_8859_1.decode(builder.getBody()).toString());
163177
jsonBuilder.endMap();
@@ -166,4 +180,83 @@ public String asJson() {
166180
}
167181
return jsonBuilder.build();
168182
}
183+
184+
@SuppressWarnings("unchecked")
185+
@Override
186+
public MultiMap<String, Object> asMultiMap() {
187+
PercentDecoder percentDecoder = new PercentDecoder();
188+
MultiMap<String, Object> multiMap = new ParameterMap();
189+
String contentType = getHeaders().get(HttpHeaderNames.CONTENT_TYPE);
190+
if (getMethod() == HttpMethod.POST &&
191+
contentType != null && contentType.contains(HttpHeaderValues.APPLICATION_JSON)) {
192+
String bodyAsChars = getBodyAsChars(StandardCharsets.UTF_8).toString();
193+
Map<String, Object> map = Json.toMap(bodyAsChars);
194+
for (Map.Entry<String, Object> entry : map.entrySet()) {
195+
if (entry.getValue() instanceof Iterable) {
196+
multiMap.putAll(entry.getKey(), (Iterable<Object>) entry.getValue());
197+
} else {
198+
multiMap.put(entry.getKey(), entry.getValue());
199+
}
200+
}
201+
}
202+
try {
203+
toMultiMapEntry(getParameter().get(Parameter.Domain.PATH),
204+
percentDecoder,
205+
false,
206+
multiMap);
207+
toMultiMapEntry(getParameter().get(Parameter.Domain.FORM),
208+
percentDecoder,
209+
HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED.equals(contentType),
210+
multiMap);
211+
toMultiMapEntry(getParameter().get(Parameter.Domain.QUERY),
212+
percentDecoder,
213+
HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED.equals(contentType),
214+
multiMap);
215+
} catch (ParameterException e) {
216+
logger.log(Level.WARNING, e.getMessage(), ExceptionFormatter.format(e));
217+
}
218+
return multiMap;
219+
}
220+
221+
@SuppressWarnings("unchecked")
222+
private static void toMultiMapEntry(Parameter parameter,
223+
PercentDecoder percentDecoder,
224+
boolean isFormEncoded,
225+
MultiMap<String, Object> multiMap) {
226+
for (Pair<String, Object> entry : parameter) {
227+
try {
228+
List<Object> list;
229+
Object value = entry.getValue();
230+
if (value instanceof List) {
231+
list = (List<Object>) value;
232+
} else if (value != null) {
233+
list = List.of(value);
234+
} else {
235+
list = List.of();
236+
}
237+
for (Object object : list) {
238+
String string = object.toString();
239+
if (isFormEncoded) {
240+
string = string.replace('+', ' ');
241+
}
242+
multiMap.put(entry.getKey(), percentDecoder.decode(string));
243+
}
244+
} catch (MalformedInputException | UnmappableCharacterException e) {
245+
logger.log(Level.WARNING, "unable to percent decode parameter: " +
246+
entry.getKey() + "=" + entry.getValue());
247+
}
248+
}
249+
}
250+
251+
private static class ParameterMap extends TinyMultiMap<String, Object> {
252+
253+
public ParameterMap() {
254+
}
255+
256+
@Override
257+
protected Collection<Object> newValues() {
258+
// keep values with multiple occurences
259+
return TinyList.builder();
260+
}
261+
}
169262
}

net-http-server/src/main/java/org/xbib/net/http/server/HttpRequest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.io.InputStream;
44
import java.nio.ByteBuffer;
55
import java.util.List;
6+
import org.xbib.datastructures.common.MultiMap;
67
import org.xbib.net.Attributes;
78
import org.xbib.net.Parameter;
89
import org.xbib.net.Request;
@@ -45,4 +46,6 @@ public interface HttpRequest extends Request {
4546
Attributes getAttributes();
4647

4748
String asJson();
49+
50+
MultiMap<String, Object> asMultiMap();
4851
}

settings.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ dependencyResolutionManagement {
3434
library('net-security', 'org.xbib', 'net-security').versionRef('net')
3535
library('net-bouncycastle', 'org.xbib', 'net-bouncycastle').versionRef('net')
3636
library('datastructures-common', 'org.xbib', 'datastructures-common').versionRef('datastructures')
37+
library('datastructures-tiny', 'org.xbib', 'datastructures-tiny').versionRef('datastructures')
3738
library('datastructures-json-tiny', 'org.xbib', 'datastructures-json-tiny').versionRef('datastructures')
3839
library('datastructures-yaml-tiny', 'org.xbib', 'datastructures-yaml-tiny').versionRef('datastructures')
3940
library('config', 'org.xbib', 'config').versionRef('datastructures')

0 commit comments

Comments
 (0)