22
33import java .io .IOException ;
44import java .net .InetSocketAddress ;
5+ import java .nio .charset .MalformedInputException ;
56import java .nio .charset .StandardCharsets ;
6- import java .util .ArrayList ;
7+ import java .nio .charset .UnmappableCharacterException ;
8+ import java .util .Collection ;
79import java .util .LinkedHashMap ;
810import java .util .List ;
911import java .util .Map ;
12+ import java .util .logging .Level ;
13+ import java .util .logging .Logger ;
1014import java .util .stream .Collectors ;
1115
16+ import org .xbib .datastructures .common .MultiMap ;
1217import org .xbib .datastructures .common .Pair ;
18+ import org .xbib .datastructures .json .tiny .Json ;
1319import org .xbib .datastructures .json .tiny .JsonBuilder ;
20+ import org .xbib .datastructures .tiny .TinyList ;
21+ import org .xbib .datastructures .tiny .TinyMultiMap ;
1422import org .xbib .net .Attributes ;
1523import org .xbib .net .Parameter ;
1624import org .xbib .net .ParameterException ;
25+ import org .xbib .net .PercentDecoder ;
1726import org .xbib .net .URL ;
27+ import org .xbib .net .http .HttpHeaderNames ;
28+ import org .xbib .net .http .HttpHeaderValues ;
1829import org .xbib .net .http .HttpHeaders ;
1930import org .xbib .net .http .HttpMethod ;
2031import org .xbib .net .http .HttpVersion ;
2132import org .xbib .net .http .server .auth .BaseAttributes ;
2233import org .xbib .net .http .server .route .HttpRouterContext ;
34+ import org .xbib .net .util .ExceptionFormatter ;
2335
2436public 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}
0 commit comments