View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.http;
16  
17  import java.nio.charset.StandardCharsets;
18  import java.time.Instant;
19  import java.time.LocalDate;
20  import java.time.Month;
21  import java.time.ZoneId;
22  import java.util.ArrayList;
23  import java.util.Date;
24  import java.util.List;
25  
26  import org.htmlunit.WebTestCase;
27  import org.htmlunit.junit.BrowserRunner;
28  import org.htmlunit.util.NameValuePair;
29  import org.junit.Assert;
30  import org.junit.Test;
31  import org.junit.runner.RunWith;
32  
33  /**
34   * Tests for {@link HttpUtils}.
35   *
36   * @author Ronald Brill
37   */
38  @RunWith(BrowserRunner.class)
39  public class HttpUtilsTest extends WebTestCase {
40  
41      /**
42       * @throws Exception if the test fails
43       */
44      @Test
45      public void testBasicDateParse() {
46          final Date expected = createDate(2004, Month.NOVEMBER, 13);
47          Assert.assertEquals(expected, HttpUtils.parseDate("Sat, 13 Nov 2004 00:00:00 GMT"));
48          Assert.assertEquals(expected, HttpUtils.parseDate("Saturday, 13 Nov 2004 00:00:00 GMT"));
49          Assert.assertEquals(expected, HttpUtils.parseDate("Sat, 13-Nov-2004 00:00:00 GMT"));
50          Assert.assertEquals(expected, HttpUtils.parseDate("Saturday, 13-Nov-2004 00:00:00 GMT"));
51          Assert.assertEquals(expected, HttpUtils.parseDate("Sat, 13 Nov 2004 00:00:00 GMT"));
52      }
53  
54      /**
55       * @throws Exception if the test fails
56       */
57      @Test
58      public void testMalformedDate() {
59          Assert.assertNull(HttpUtils.parseDate("Sat, 13 Nov 2004 00:00:00 GMD"));
60          Assert.assertNull(HttpUtils.parseDate("Die Feb 22 17:20:18 2024"));
61          Assert.assertNull(HttpUtils.parseDate("Thu Feb 22 17:20;18 2024"));
62      }
63  
64      /**
65       * @throws Exception if the test fails
66       */
67      @Test
68      public void testParseInvalid() {
69          Assert.assertNull(HttpUtils.parseDate("Friday, 13-Nov-04 00:00:00 GMT"));
70      }
71  
72      /**
73       * @throws Exception if the test fails
74       */
75      @Test
76      public void testParseNull() {
77          Assert.assertNull(HttpUtils.parseDate(null));
78      }
79  
80      /**
81       * @throws Exception if the test fails
82       */
83      @Test
84      public void testTwoDigitYearDateParse() {
85          Assert.assertEquals(createDate(2004, Month.NOVEMBER, 13),
86                  HttpUtils.parseDate("Saturday, 13-Nov-04 00:00:00 GMT"));
87  
88          Assert.assertEquals(createDate(2074, Month.NOVEMBER, 13),
89                  HttpUtils.parseDate("Tuesday, 13-Nov-74 00:00:00 GMT"));
90      }
91  
92      /**
93       * @throws Exception if the test fails
94       */
95      @Test
96      public void testParseQuotedDate() {
97          Assert.assertEquals(createDate(2004, Month.NOVEMBER, 13),
98                  HttpUtils.parseDate("'Sat, 13 Nov 2004 00:00:00 GMT'"));
99      }
100 
101     /**
102      * @throws Exception if the test fails
103      */
104     @Test
105     public void testFormatDate() {
106         Assert.assertEquals("Sat, 13 Nov 2004 00:00:00 GMT",
107                 HttpUtils.formatDate(createDate(2004, Month.NOVEMBER, 13)));
108     }
109 
110     private static Date createDate(final int year, final Month month, final int day) {
111         final Instant instant = LocalDate.of(year, month, day).atStartOfDay(ZoneId.of("GMT")).toInstant();
112         return new Date(instant.toEpochMilli());
113     }
114 
115     /**
116      * @throws Exception if the test fails
117      */
118     @Test
119     public void testParseURLCodedContent() throws Exception {
120         List<NameValuePair> result;
121 
122         result = HttpUtils.parseUrlQuery("", StandardCharsets.UTF_8);
123         Assert.assertTrue(result.isEmpty());
124 
125         result = HttpUtils.parseUrlQuery("Name0", StandardCharsets.UTF_8);
126         Assert.assertEquals(1, result.size());
127         assertNameValuePair(result.get(0), "Name0", null);
128 
129         result = HttpUtils.parseUrlQuery("Name1=Value1", StandardCharsets.UTF_8);
130         Assert.assertEquals(1, result.size());
131         assertNameValuePair(result.get(0), "Name1", "Value1");
132 
133         result = HttpUtils.parseUrlQuery("Name2=", StandardCharsets.UTF_8);
134         Assert.assertEquals(1, result.size());
135         assertNameValuePair(result.get(0), "Name2", "");
136 
137         result = HttpUtils.parseUrlQuery("Name3", StandardCharsets.UTF_8);
138         Assert.assertEquals(1, result.size());
139         assertNameValuePair(result.get(0), "Name3", null);
140 
141         result = HttpUtils.parseUrlQuery("Name4=Value%204%21", StandardCharsets.UTF_8);
142         Assert.assertEquals(1, result.size());
143         assertNameValuePair(result.get(0), "Name4", "Value 4!");
144 
145         result = HttpUtils.parseUrlQuery("Name4=Value%2B4%21", StandardCharsets.UTF_8);
146         Assert.assertEquals(1, result.size());
147         assertNameValuePair(result.get(0), "Name4", "Value+4!");
148 
149         result = HttpUtils.parseUrlQuery("Name4=Value%204%21%20%214", StandardCharsets.UTF_8);
150         Assert.assertEquals(1, result.size());
151         assertNameValuePair(result.get(0), "Name4", "Value 4! !4");
152 
153         result = HttpUtils.parseUrlQuery("Name5=aaa&Name6=bbb", StandardCharsets.UTF_8);
154         Assert.assertEquals(2, result.size());
155         assertNameValuePair(result.get(0), "Name5", "aaa");
156         assertNameValuePair(result.get(1), "Name6", "bbb");
157 
158         result = HttpUtils.parseUrlQuery("Name7=aaa&Name7=b%2Cb&Name7=ccc", StandardCharsets.UTF_8);
159         Assert.assertEquals(3, result.size());
160         assertNameValuePair(result.get(0), "Name7", "aaa");
161         assertNameValuePair(result.get(1), "Name7", "b,b");
162         assertNameValuePair(result.get(2), "Name7", "ccc");
163 
164         result = HttpUtils.parseUrlQuery("Name8=xx%2C%20%20yy%20%20%2Czz", StandardCharsets.UTF_8);
165         Assert.assertEquals(1, result.size());
166         assertNameValuePair(result.get(0), "Name8", "xx,  yy  ,zz");
167 
168         result = HttpUtils.parseUrlQuery("price=10%20%E2%82%AC", StandardCharsets.UTF_8);
169         Assert.assertEquals(1, result.size());
170         assertNameValuePair(result.get(0), "price", "10 \u20AC");
171 
172         result = HttpUtils.parseUrlQuery("a=b\"c&d=e", StandardCharsets.UTF_8);
173         Assert.assertEquals(2, result.size());
174         assertNameValuePair(result.get(0), "a", "b\"c");
175         assertNameValuePair(result.get(1), "d", "e");
176     }
177 
178     /**
179      * @throws Exception if the test fails
180      */
181     @Test
182     public void testParseInvalidURLCodedContent() throws Exception {
183         List<NameValuePair> result;
184 
185         result = HttpUtils.parseUrlQuery("name=%", StandardCharsets.UTF_8);
186         Assert.assertEquals(1, result.size());
187         assertNameValuePair(result.get(0), "name", "%");
188 
189         result = HttpUtils.parseUrlQuery("name=%a", StandardCharsets.UTF_8);
190         Assert.assertEquals(1, result.size());
191         assertNameValuePair(result.get(0), "name", "%a");
192 
193         result = HttpUtils.parseUrlQuery("name=%wa%20", StandardCharsets.UTF_8);
194         Assert.assertEquals(1, result.size());
195         assertNameValuePair(result.get(0), "name", "%wa ");
196     }
197 
198     private static void assertNameValuePair(
199             final NameValuePair parameter,
200             final String expectedName,
201             final String expectedValue) {
202         Assert.assertEquals(parameter.getName(), expectedName);
203         Assert.assertEquals(parameter.getValue(), expectedValue);
204     }
205 
206     /**
207      * @throws Exception if the test fails
208      */
209     @Test
210     public void toQueryFormFields() {
211         final List<NameValuePair> params = new ArrayList<>();
212         Assert.assertEquals("", HttpUtils.toQueryFormFields(params, StandardCharsets.US_ASCII));
213 
214         params.clear();
215         params.add(new NameValuePair("Name0", null));
216         Assert.assertEquals("Name0", HttpUtils.toQueryFormFields(params, StandardCharsets.US_ASCII));
217 
218         params.clear();
219         params.add(new NameValuePair("Name1", "Value1"));
220         Assert.assertEquals("Name1=Value1", HttpUtils.toQueryFormFields(params, StandardCharsets.US_ASCII));
221 
222         params.clear();
223         params.add(new NameValuePair("Name2", ""));
224         Assert.assertEquals("Name2=", HttpUtils.toQueryFormFields(params, StandardCharsets.US_ASCII));
225 
226         params.clear();
227         params.add(new NameValuePair("Name4", "Value 4&"));
228         Assert.assertEquals("Name4=Value+4%26", HttpUtils.toQueryFormFields(params, StandardCharsets.US_ASCII));
229 
230         params.clear();
231         params.add(new NameValuePair("Name4", "Value+4&"));
232         Assert.assertEquals("Name4=Value%2B4%26", HttpUtils.toQueryFormFields(params, StandardCharsets.US_ASCII));
233 
234         params.clear();
235         params.add(new NameValuePair("Name4", "Value 4& =4"));
236         Assert.assertEquals("Name4=Value+4%26+%3D4", HttpUtils.toQueryFormFields(params, StandardCharsets.US_ASCII));
237 
238         params.clear();
239         params.add(new NameValuePair("Name5", "aaa"));
240         params.add(new NameValuePair("Name6", "bbb"));
241         Assert.assertEquals("Name5=aaa&Name6=bbb", HttpUtils.toQueryFormFields(params, StandardCharsets.US_ASCII));
242 
243         params.clear();
244         params.add(new NameValuePair("Name7", "aaa"));
245         params.add(new NameValuePair("Name7", "b,b"));
246         params.add(new NameValuePair("Name7", "ccc"));
247         Assert.assertEquals("Name7=aaa&Name7=b%2Cb&Name7=ccc",
248                 HttpUtils.toQueryFormFields(params, StandardCharsets.US_ASCII));
249 
250         params.clear();
251         params.add(new NameValuePair("Name8", "xx,  yy  ,zz"));
252         Assert.assertEquals("Name8=xx%2C++yy++%2Czz", HttpUtils.toQueryFormFields(params, StandardCharsets.US_ASCII));
253     }
254 }