View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.hc.core5.net;
29  
30  import java.net.URI;
31  import java.nio.charset.StandardCharsets;
32  import java.util.ArrayList;
33  import java.util.Arrays;
34  import java.util.Collections;
35  import java.util.List;
36  
37  import org.apache.hc.core5.http.NameValuePair;
38  import org.apache.hc.core5.http.message.BasicNameValuePair;
39  import org.hamcrest.CoreMatchers;
40  import org.junit.Assert;
41  import org.junit.Test;
42  
43  public class TestURLEncodedUtils {
44  
45      @Test
46      public void testParseURLCodedContent() throws Exception {
47          List <NameValuePair> result;
48  
49          result = parse("");
50          Assert.assertTrue(result.isEmpty());
51  
52          result = parse("Name0");
53          Assert.assertEquals(1, result.size());
54          assertNameValuePair(result.get(0), "Name0", null);
55  
56          result = parse("Name1=Value1");
57          Assert.assertEquals(1, result.size());
58          assertNameValuePair(result.get(0), "Name1", "Value1");
59  
60          result = parse("Name2=");
61          Assert.assertEquals(1, result.size());
62          assertNameValuePair(result.get(0), "Name2", "");
63  
64          result = parse("Name3");
65          Assert.assertEquals(1, result.size());
66          assertNameValuePair(result.get(0), "Name3", null);
67  
68          result = parse("Name4=Value%204%21");
69          Assert.assertEquals(1, result.size());
70          assertNameValuePair(result.get(0), "Name4", "Value 4!");
71  
72          result = parse("Name4=Value%2B4%21");
73          Assert.assertEquals(1, result.size());
74          assertNameValuePair(result.get(0), "Name4", "Value+4!");
75  
76          result = parse("Name4=Value%204%21%20%214");
77          Assert.assertEquals(1, result.size());
78          assertNameValuePair(result.get(0), "Name4", "Value 4! !4");
79  
80          result = parse("Name5=aaa&Name6=bbb");
81          Assert.assertEquals(2, result.size());
82          assertNameValuePair(result.get(0), "Name5", "aaa");
83          assertNameValuePair(result.get(1), "Name6", "bbb");
84  
85          result = parse("Name7=aaa&Name7=b%2Cb&Name7=ccc");
86          Assert.assertEquals(3, result.size());
87          assertNameValuePair(result.get(0), "Name7", "aaa");
88          assertNameValuePair(result.get(1), "Name7", "b,b");
89          assertNameValuePair(result.get(2), "Name7", "ccc");
90  
91          result = parse("Name8=xx%2C%20%20yy%20%20%2Czz");
92          Assert.assertEquals(1, result.size());
93          assertNameValuePair(result.get(0), "Name8", "xx,  yy  ,zz");
94  
95          result = parse("price=10%20%E2%82%AC");
96          Assert.assertEquals(1, result.size());
97          assertNameValuePair(result.get(0), "price", "10 \u20AC");
98      }
99  
100     @Test
101     public void testParseSegments() throws Exception {
102         Assert.assertThat(URLEncodedUtils.parsePathSegments("/this/that"),
103                 CoreMatchers.equalTo(Arrays.asList("this", "that")));
104         Assert.assertThat(URLEncodedUtils.parsePathSegments("this/that"),
105                 CoreMatchers.equalTo(Arrays.asList("this", "that")));
106         Assert.assertThat(URLEncodedUtils.parsePathSegments("this//that"),
107                 CoreMatchers.equalTo(Arrays.asList("this", "", "that")));
108         Assert.assertThat(URLEncodedUtils.parsePathSegments("this//that/"),
109                 CoreMatchers.equalTo(Arrays.asList("this", "", "that", "")));
110         Assert.assertThat(URLEncodedUtils.parsePathSegments("this//that/%2fthis%20and%20that"),
111                 CoreMatchers.equalTo(Arrays.asList("this", "", "that", "/this and that")));
112         Assert.assertThat(URLEncodedUtils.parsePathSegments("this///that//"),
113                 CoreMatchers.equalTo(Arrays.asList("this", "", "", "that", "", "")));
114         Assert.assertThat(URLEncodedUtils.parsePathSegments("/"),
115                 CoreMatchers.equalTo(Collections.singletonList("")));
116         Assert.assertThat(URLEncodedUtils.parsePathSegments(""),
117                 CoreMatchers.equalTo(Collections.<String>emptyList()));
118     }
119 
120     @Test
121     public void testFormatSegments() throws Exception {
122         Assert.assertThat(URLEncodedUtils.formatSegments("this", "that"),
123                 CoreMatchers.equalTo("/this/that"));
124         Assert.assertThat(URLEncodedUtils.formatSegments("this", "", "that"),
125                 CoreMatchers.equalTo("/this//that"));
126         Assert.assertThat(URLEncodedUtils.formatSegments("this", "", "that", "/this and that"),
127                 CoreMatchers.equalTo("/this//that/%2Fthis%20and%20that"));
128         Assert.assertThat(URLEncodedUtils.formatSegments("this", "", "", "that", "", ""),
129                 CoreMatchers.equalTo("/this///that//"));
130         Assert.assertThat(URLEncodedUtils.formatSegments(""),
131                 CoreMatchers.equalTo("/"));
132         Assert.assertThat(URLEncodedUtils.formatSegments(),
133                 CoreMatchers.equalTo(""));
134     }
135 
136     @Test
137     public void testParseURLCodedContentString() throws Exception {
138         List <NameValuePair> result;
139 
140         result = parseString("");
141         Assert.assertTrue(result.isEmpty());
142 
143         result = parseString("Name0");
144         Assert.assertEquals(1, result.size());
145         assertNameValuePair(result.get(0), "Name0", null);
146 
147         result = parseString("Name1=Value1");
148         Assert.assertEquals(1, result.size());
149         assertNameValuePair(result.get(0), "Name1", "Value1");
150 
151         result = parseString("Name2=");
152         Assert.assertEquals(1, result.size());
153         assertNameValuePair(result.get(0), "Name2", "");
154 
155         result = parseString("Name3");
156         Assert.assertEquals(1, result.size());
157         assertNameValuePair(result.get(0), "Name3", null);
158 
159         result = parseString("Name4=Value%204%21");
160         Assert.assertEquals(1, result.size());
161         assertNameValuePair(result.get(0), "Name4", "Value 4!");
162 
163         result = parseString("Name4=Value%2B4%21");
164         Assert.assertEquals(1, result.size());
165         assertNameValuePair(result.get(0), "Name4", "Value+4!");
166 
167         result = parseString("Name4=Value%204%21%20%214");
168         Assert.assertEquals(1, result.size());
169         assertNameValuePair(result.get(0), "Name4", "Value 4! !4");
170 
171         result = parseString("Name5=aaa&Name6=bbb");
172         Assert.assertEquals(2, result.size());
173         assertNameValuePair(result.get(0), "Name5", "aaa");
174         assertNameValuePair(result.get(1), "Name6", "bbb");
175 
176         result = parseString("Name7=aaa&Name7=b%2Cb&Name7=ccc");
177         Assert.assertEquals(3, result.size());
178         assertNameValuePair(result.get(0), "Name7", "aaa");
179         assertNameValuePair(result.get(1), "Name7", "b,b");
180         assertNameValuePair(result.get(2), "Name7", "ccc");
181 
182         result = parseString("Name8=xx%2C%20%20yy%20%20%2Czz");
183         Assert.assertEquals(1, result.size());
184         assertNameValuePair(result.get(0), "Name8", "xx,  yy  ,zz");
185 
186         result = parseString("price=10%20%E2%82%AC");
187         Assert.assertEquals(1, result.size());
188         assertNameValuePair(result.get(0), "price", "10 \u20AC");
189 
190         result = parse("a=b\"c&d=e");
191         Assert.assertEquals(2, result.size());
192         assertNameValuePair(result.get(0), "a", "b\"c");
193         assertNameValuePair(result.get(1), "d", "e");
194     }
195 
196     @Test
197     public void testParseInvalidURLCodedContent() throws Exception {
198         List <NameValuePair> result;
199 
200         result = parse("name=%");
201         Assert.assertEquals(1, result.size());
202         assertNameValuePair(result.get(0), "name", "%");
203 
204         result = parse("name=%a");
205         Assert.assertEquals(1, result.size());
206         assertNameValuePair(result.get(0), "name", "%a");
207 
208         result = parse("name=%wa%20");
209         Assert.assertEquals(1, result.size());
210         assertNameValuePair(result.get(0), "name", "%wa ");
211     }
212 
213     private static final int SWISS_GERMAN_HELLO [] = {
214         0x47, 0x72, 0xFC, 0x65, 0x7A, 0x69, 0x5F, 0x7A, 0xE4, 0x6D, 0xE4
215     };
216 
217     private static final int RUSSIAN_HELLO [] = {
218         0x412, 0x441, 0x435, 0x43C, 0x5F, 0x43F, 0x440, 0x438,
219         0x432, 0x435, 0x442
220     };
221 
222     private static String constructString(final int [] unicodeChars) {
223         final StringBuilder buffer = new StringBuilder();
224         if (unicodeChars != null) {
225             for (final int unicodeChar : unicodeChars) {
226                 buffer.append((char)unicodeChar);
227             }
228         }
229         return buffer.toString();
230     }
231 
232     @Test
233     public void testParseUTF8Ampersand1String() throws Exception {
234         final String ru_hello = constructString(RUSSIAN_HELLO);
235         final String ch_hello = constructString(SWISS_GERMAN_HELLO);
236         final List <NameValuePair> parameters = new ArrayList<>();
237         parameters.add(new BasicNameValuePair("russian", ru_hello));
238         parameters.add(new BasicNameValuePair("swiss", ch_hello));
239 
240         final String s = URLEncodedUtils.format(parameters, StandardCharsets.UTF_8);
241 
242         final List <NameValuePair> result = URLEncodedUtils.parse(s, StandardCharsets.UTF_8);
243         Assert.assertEquals(2, result.size());
244         assertNameValuePair(result.get(0), "russian", ru_hello);
245         assertNameValuePair(result.get(1), "swiss", ch_hello);
246     }
247 
248     @Test
249     public void testParseUTF8Ampersand2String() throws Exception {
250         testParseUTF8String('&');
251     }
252 
253     @Test
254     public void testParseUTF8SemicolonString() throws Exception {
255         testParseUTF8String(';');
256     }
257 
258     private void testParseUTF8String(final char parameterSeparator) throws Exception {
259         final String ru_hello = constructString(RUSSIAN_HELLO);
260         final String ch_hello = constructString(SWISS_GERMAN_HELLO);
261         final List <NameValuePair> parameters = new ArrayList<>();
262         parameters.add(new BasicNameValuePair("russian", ru_hello));
263         parameters.add(new BasicNameValuePair("swiss", ch_hello));
264 
265         final String s = URLEncodedUtils.format(parameters, parameterSeparator, StandardCharsets.UTF_8);
266 
267         final List<NameValuePair> result1 = URLEncodedUtils.parse(s, StandardCharsets.UTF_8);
268         Assert.assertEquals(2, result1.size());
269         assertNameValuePair(result1.get(0), "russian", ru_hello);
270         assertNameValuePair(result1.get(1), "swiss", ch_hello);
271 
272         final List<NameValuePair> result2 = URLEncodedUtils.parse(s, StandardCharsets.UTF_8, parameterSeparator);
273         Assert.assertEquals(2, result2.size());
274         assertNameValuePair(result2.get(0), "russian", ru_hello);
275         assertNameValuePair(result2.get(1), "swiss", ch_hello);
276     }
277 
278     @Test
279     public void testEmptyQuery() throws Exception {
280         final List<NameValuePair> result = URLEncodedUtils.parse("", StandardCharsets.UTF_8);
281         Assert.assertEquals(0, result.size());
282         // [HTTPCLIENT-1889]:
283         result.add(new BasicNameValuePair("key", "value"));
284     }
285 
286     @Test
287     public void testFormat() throws Exception {
288         final List <NameValuePair> params = new ArrayList<>();
289         Assert.assertEquals(0, URLEncodedUtils.format(params, StandardCharsets.US_ASCII).length());
290 
291         params.clear();
292         params.add(new BasicNameValuePair("Name0", null));
293         Assert.assertEquals("Name0", URLEncodedUtils.format(params, StandardCharsets.US_ASCII));
294 
295         params.clear();
296         params.add(new BasicNameValuePair("Name1", "Value1"));
297         Assert.assertEquals("Name1=Value1", URLEncodedUtils.format(params, StandardCharsets.US_ASCII));
298 
299         params.clear();
300         params.add(new BasicNameValuePair("Name2", ""));
301         Assert.assertEquals("Name2=", URLEncodedUtils.format(params, StandardCharsets.US_ASCII));
302 
303         params.clear();
304         params.add(new BasicNameValuePair("Name4", "Value 4&"));
305         Assert.assertEquals("Name4=Value+4%26", URLEncodedUtils.format(params, StandardCharsets.US_ASCII));
306 
307         params.clear();
308         params.add(new BasicNameValuePair("Name4", "Value+4&"));
309         Assert.assertEquals("Name4=Value%2B4%26", URLEncodedUtils.format(params, StandardCharsets.US_ASCII));
310 
311         params.clear();
312         params.add(new BasicNameValuePair("Name4", "Value 4& =4"));
313         Assert.assertEquals("Name4=Value+4%26+%3D4", URLEncodedUtils.format(params, StandardCharsets.US_ASCII));
314 
315         params.clear();
316         params.add(new BasicNameValuePair("Name5", "aaa"));
317         params.add(new BasicNameValuePair("Name6", "bbb"));
318         Assert.assertEquals("Name5=aaa&Name6=bbb", URLEncodedUtils.format(params, StandardCharsets.US_ASCII));
319 
320         params.clear();
321         params.add(new BasicNameValuePair("Name7", "aaa"));
322         params.add(new BasicNameValuePair("Name7", "b,b"));
323         params.add(new BasicNameValuePair("Name7", "ccc"));
324         Assert.assertEquals("Name7=aaa&Name7=b%2Cb&Name7=ccc", URLEncodedUtils.format(params, StandardCharsets.US_ASCII));
325         Assert.assertEquals("Name7=aaa&Name7=b%2Cb&Name7=ccc", URLEncodedUtils.format(params, '&', StandardCharsets.US_ASCII));
326         Assert.assertEquals("Name7=aaa;Name7=b%2Cb;Name7=ccc", URLEncodedUtils.format(params, ';', StandardCharsets.US_ASCII));
327 
328         params.clear();
329         params.add(new BasicNameValuePair("Name8", "xx,  yy  ,zz"));
330         Assert.assertEquals("Name8=xx%2C++yy++%2Czz", URLEncodedUtils.format(params, StandardCharsets.US_ASCII));
331     }
332 
333     @Test
334     public void testFormatString() throws Exception { // as above, using String
335         final List <NameValuePair> params = new ArrayList<>();
336         Assert.assertEquals(0, URLEncodedUtils.format(params, StandardCharsets.US_ASCII).length());
337 
338         params.clear();
339         params.add(new BasicNameValuePair("Name0", null));
340         Assert.assertEquals("Name0", URLEncodedUtils.format(params, StandardCharsets.US_ASCII));
341 
342         params.clear();
343         params.add(new BasicNameValuePair("Name1", "Value1"));
344         Assert.assertEquals("Name1=Value1", URLEncodedUtils.format(params, StandardCharsets.US_ASCII));
345 
346         params.clear();
347         params.add(new BasicNameValuePair("Name2", ""));
348         Assert.assertEquals("Name2=", URLEncodedUtils.format(params, StandardCharsets.US_ASCII));
349 
350         params.clear();
351         params.add(new BasicNameValuePair("Name4", "Value 4&"));
352         Assert.assertEquals("Name4=Value+4%26", URLEncodedUtils.format(params, StandardCharsets.US_ASCII));
353 
354         params.clear();
355         params.add(new BasicNameValuePair("Name4", "Value+4&"));
356         Assert.assertEquals("Name4=Value%2B4%26", URLEncodedUtils.format(params, StandardCharsets.US_ASCII));
357 
358         params.clear();
359         params.add(new BasicNameValuePair("Name4", "Value 4& =4"));
360         Assert.assertEquals("Name4=Value+4%26+%3D4", URLEncodedUtils.format(params, StandardCharsets.US_ASCII));
361 
362         params.clear();
363         params.add(new BasicNameValuePair("Name5", "aaa"));
364         params.add(new BasicNameValuePair("Name6", "bbb"));
365         Assert.assertEquals("Name5=aaa&Name6=bbb", URLEncodedUtils.format(params, StandardCharsets.US_ASCII));
366 
367         params.clear();
368         params.add(new BasicNameValuePair("Name7", "aaa"));
369         params.add(new BasicNameValuePair("Name7", "b,b"));
370         params.add(new BasicNameValuePair("Name7", "ccc"));
371         Assert.assertEquals("Name7=aaa&Name7=b%2Cb&Name7=ccc", URLEncodedUtils.format(params, StandardCharsets.US_ASCII));
372 
373         params.clear();
374         params.add(new BasicNameValuePair("Name8", "xx,  yy  ,zz"));
375         Assert.assertEquals("Name8=xx%2C++yy++%2Czz", URLEncodedUtils.format(params, StandardCharsets.US_ASCII));
376     }
377 
378     private List <NameValuePair> parse (final String params) {
379         return URLEncodedUtils.parse(params, StandardCharsets.UTF_8);
380     }
381 
382     private List <NameValuePair> parseString (final String uri) throws Exception {
383         return URLEncodedUtils.parse(new URI("?"+uri), StandardCharsets.UTF_8);
384     }
385 
386     private static void assertNameValuePair (
387             final NameValuePair parameter,
388             final String expectedName,
389             final String expectedValue) {
390         Assert.assertEquals(parameter.getName(), expectedName);
391         Assert.assertEquals(parameter.getValue(), expectedValue);
392     }
393 
394 }