2020
2121import java .io .UnsupportedEncodingException ;
2222import java .net .URLDecoder ;
23+ import java .net .URLEncoder ;
2324import java .nio .charset .StandardCharsets ;
2425import java .util .ArrayDeque ;
2526import java .util .Deque ;
2627import java .util .LinkedHashMap ;
2728import java .util .Map ;
2829import org .xnio .OptionMap ;
2930
31+ import io .undertow .UndertowMessages ;
3032import io .undertow .UndertowOptions ;
3133import io .undertow .server .HttpServerExchange ;
3234
@@ -42,33 +44,42 @@ private QueryParameterUtils() {
4244 }
4345
4446 public static String buildQueryString (final Map <String , Deque <String >> params ) {
45- StringBuilder sb = new StringBuilder ();
46- boolean first = true ;
47- for (Map .Entry <String , Deque <String >> entry : params .entrySet ()) {
48- if (entry .getValue ().isEmpty ()) {
49- if (first ) {
50- first = false ;
51- } else {
52- sb .append ('&' );
53- }
54- sb .append (entry .getKey ());
55- sb .append ('=' );
56- } else {
57- for (String val : entry .getValue ()) {
47+ return QueryParameterUtils .buildQueryString (params , null );
48+ }
49+
50+ public static String buildQueryString (final Map <String , Deque <String >> params , final String encoding ) {
51+ try {
52+ StringBuilder sb = new StringBuilder ();
53+ boolean first = true ;
54+ for (Map .Entry <String , Deque <String >> entry : params .entrySet ()) {
55+ final String key = encoding != null ? URLEncoder .encode (entry .getKey (), encoding ) : entry .getKey ();
56+ if (entry .getValue ().isEmpty ()) {
5857 if (first ) {
5958 first = false ;
6059 } else {
6160 sb .append ('&' );
6261 }
63- sb .append (entry . getKey () );
62+ sb .append (key );
6463 sb .append ('=' );
65- sb .append (val );
64+ } else {
65+ for (String val : entry .getValue ()) {
66+ if (first ) {
67+ first = false ;
68+ } else {
69+ sb .append ('&' );
70+ }
71+ final String _val = encoding != null ? URLEncoder .encode (val , encoding ) : val ;
72+ sb .append (key );
73+ sb .append ('=' );
74+ sb .append (_val );
75+ }
6676 }
6777 }
78+ return sb .toString ();
79+ } catch (UnsupportedEncodingException e ) {
80+ throw UndertowMessages .MESSAGES .failedToEncodeQueryString (buildQueryString (params ), encoding );
6881 }
69- return sb .toString ();
7082 }
71-
7283 /**
7384 * Parses a query string into a map
7485 * @param newQueryString The query string
@@ -146,8 +157,9 @@ public static Map<String, Deque<String>> mergeQueryParametersWithNewQueryString(
146157 return mergeQueryParametersWithNewQueryString (queryParameters , newQueryString , StandardCharsets .UTF_8 .name ());
147158 }
148159
160+ @ Deprecated
149161 public static Map <String , Deque <String >> mergeQueryParametersWithNewQueryString (final Map <String , Deque <String >> queryParameters , final String newQueryString , final String encoding ) {
150-
162+ //DEPRACETED this will create duplicates
151163 Map <String , Deque <String >> newQueryParameters = parseQueryString (newQueryString , encoding );
152164 //according to the spec the new query parameters have to 'take precedence'
153165 for (Map .Entry <String , Deque <String >> entry : queryParameters .entrySet ()) {
@@ -160,6 +172,20 @@ public static Map<String, Deque<String>> mergeQueryParametersWithNewQueryString(
160172 return newQueryParameters ;
161173 }
162174
175+ public static Map <String , Deque <String >> mergeQueryParameters (final Map <String , Deque <String >> newParams , final Map <String , Deque <String >> oldParams ) {
176+ //according to the spec the new query parameters have to 'take precedence'
177+ for (Map .Entry <String , Deque <String >> entry : oldParams .entrySet ()) {
178+ if (!newParams .containsKey (entry .getKey ())) {
179+ newParams .put (entry .getKey (), new ArrayDeque <>(entry .getValue ()));
180+ } else {
181+ final Deque <String > newValues = newParams .get (entry .getKey ());
182+ final Deque <String > oldValues = entry .getValue ();
183+ oldValues .stream ().filter (v -> !newValues .contains (v )).forEach (v -> newValues .add (v ));
184+ }
185+ }
186+ return newParams ;
187+ }
188+
163189 public static String getQueryParamEncoding (HttpServerExchange exchange ) {
164190 String encoding = null ;
165191 OptionMap undertowOptions = exchange .getConnection ().getUndertowOptions ();
0 commit comments