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;
16  
17  import java.net.URL;
18  import java.util.ArrayList;
19  import java.util.List;
20  
21  import org.htmlunit.junit.annotation.Alerts;
22  import org.htmlunit.junit.annotation.HtmlUnitNYI;
23  import org.htmlunit.util.NameValuePair;
24  import org.junit.jupiter.api.Assertions;
25  import org.junit.jupiter.api.Test;
26  import org.openqa.selenium.By;
27  import org.openqa.selenium.WebDriver;
28  
29  /**
30   * Tests for {@link WebClient} using WebDriverTestCase.
31   *
32   * @author Marc Guillemot
33   * @author Frank Danek
34   * @author Ronald Brill
35   */
36  public class WebClient6Test extends WebDriverTestCase {
37  
38      /**
39       * @throws Exception if an error occurs
40       */
41      @Test
42      @Alerts({"§§URL§§page2.html", "3", "§§URL§§page2.html"})
43      public void redirect301() throws Exception {
44          redirectGet(301, HttpMethod.GET, "/page2.html");
45          redirectPost(301, HttpMethod.GET, "/page2.html", false);
46      }
47  
48      /**
49       * @throws Exception if an error occurs
50       */
51      @Test
52      @Alerts({"§§URL§§page2.html", "3", "§§URL§§page2.html"})
53      public void redirectAbsolute301() throws Exception {
54          redirectGet(301, HttpMethod.GET, new URL(URL_FIRST, "/page2.html").toExternalForm());
55          redirectPost(301, HttpMethod.GET, new URL(URL_FIRST, "/page2.html").toExternalForm(), false);
56      }
57  
58      /**
59       * @throws Exception if an error occurs
60       */
61      @Test
62      @Alerts({"§§URL§§page2.html?test=foo", "3", "§§URL§§page2.html?test=foo"})
63      public void redirect301WithQuery() throws Exception {
64          redirectGet(301, HttpMethod.GET, "/page2.html?test=foo");
65          redirectPost(301, HttpMethod.GET, "/page2.html?test=foo", true);
66      }
67  
68      /**
69       * @throws Exception if an error occurs
70       */
71      @Test
72      @Alerts({"§§URL§§page2.html", "3", "§§URL§§page2.html#hash"})
73      public void redirect301WithHash() throws Exception {
74          redirectGet(301, HttpMethod.GET, "/page2.html#hash");
75          redirectPost(301, HttpMethod.GET, "/page2.html#hash", false);
76      }
77  
78      /**
79       * @throws Exception if an error occurs
80       */
81      @Test
82      @Alerts({"§§URL§§page2.html?test=foo", "3", "§§URL§§page2.html?test=foo#hash"})
83      public void redirect301WithQueryAndHash() throws Exception {
84          redirectGet(301, HttpMethod.GET, "/page2.html?test=foo#hash");
85          redirectPost(301, HttpMethod.GET, "/page2.html?test=foo#hash", true);
86      }
87  
88      /**
89       * @throws Exception if an error occurs
90       */
91      @Test
92      @Alerts({"§§URL§§page2.html?ignorefrom=pwr&", "3",
93          "§§URL§§page2.html?ignorefrom=pwr&ignorenai=1&ignoresearch_submit=Get%20Resumes&mne=4"})
94      @HtmlUnitNYI(CHROME = {"§§URL§§page2.html?ignorefrom=pwr&", "3",
95                             "§§URL§§page2.html?ignorefrom=pwr&ignorenai=1&"
96                                     + "%23x26;ignoresearch_submit=Get%20Resumes&%23x26;mne=4"},
97              EDGE = {"§§URL§§page2.html?ignorefrom=pwr&", "3",
98                      "§§URL§§page2.html?ignorefrom=pwr&ignorenai=1&"
99                              + "%23x26;ignoresearch_submit=Get%20Resumes&%23x26;mne=4"},
100             FF = {"§§URL§§page2.html?ignorefrom=pwr&", "3",
101                   "§§URL§§page2.html?ignorefrom=pwr&ignorenai=1&"
102                           + "%23x26;ignoresearch_submit=Get%20Resumes&%23x26;mne=4"},
103             FF_ESR = {"§§URL§§page2.html?ignorefrom=pwr&", "3",
104                       "§§URL§§page2.html?ignorefrom=pwr&ignorenai=1&"
105                               + "%23x26;ignoresearch_submit=Get%20Resumes&%23x26;mne=4"})
106     public void redirect301WithQueryAndHashSpecialChars() throws Exception {
107         redirectGet(301, HttpMethod.GET,
108                 "/page2.html?ignorefrom=pwr&ignorenai=1&ignoresearch_submit=Get%20Resumes&mne=4");
109         redirectPost(301, HttpMethod.GET,
110                 "/page2.html?ignorefrom=pwr&ignorenai=1&ignoresearch_submit=Get%20Resumes&mne=4",
111                 true);
112     }
113 
114     /**
115      * @throws Exception if an error occurs
116      */
117     @Test
118     @Alerts({"§§URL§§page2.html?test=foo", "3", "§§URL§§page2.html?test=foo#hash"})
119     public void redirectAbsolute301WithQueryAndHash() throws Exception {
120         redirectGet(301, HttpMethod.GET, new URL(URL_FIRST,
121                 "/page2.html?test=foo#hash").toExternalForm());
122         redirectPost(301, HttpMethod.GET, new URL(URL_FIRST,
123                 "/page2.html?test=foo#hash").toExternalForm(), true);
124     }
125 
126     /**
127      * @throws Exception if an error occurs
128      */
129     @Test
130     @Alerts({"§§URL§§page2.html?ignorefrom=pwr&", "3",
131              "§§URL§§page2.html?ignorefrom=pwr&ignorenai=1&"
132                      + "ignoresearch_submit=Get%20Resumes&mne=4"})
133     @HtmlUnitNYI(CHROME = {"§§URL§§page2.html?ignorefrom=pwr&", "3",
134                            "§§URL§§page2.html?ignorefrom=pwr&ignorenai=1&"
135                            + "%23x26;ignoresearch_submit=Get%20Resumes&%23x26;mne=4"},
136             EDGE = {"§§URL§§page2.html?ignorefrom=pwr&", "3",
137                     "§§URL§§page2.html?ignorefrom=pwr&ignorenai=1&"
138                     + "%23x26;ignoresearch_submit=Get%20Resumes&%23x26;mne=4"},
139             FF = {"§§URL§§page2.html?ignorefrom=pwr&", "3",
140                   "§§URL§§page2.html?ignorefrom=pwr&ignorenai=1&"
141                           + "%23x26;ignoresearch_submit=Get%20Resumes&%23x26;mne=4"},
142             FF_ESR = {"§§URL§§page2.html?ignorefrom=pwr&", "3",
143                       "§§URL§§page2.html?ignorefrom=pwr&ignorenai=1&"
144                       + "%23x26;ignoresearch_submit=Get%20Resumes&%23x26;mne=4"})
145     public void redirectAbsolute301WithQueryAndHashSpecialChars() throws Exception {
146         redirectGet(301, HttpMethod.GET, new URL(URL_FIRST,
147             "/page2.html?ignorefrom=pwr&ignorenai=1&ignoresearch_submit=Get%20Resumes&mne=4")
148                 .toExternalForm());
149         redirectPost(301, HttpMethod.GET, new URL(URL_FIRST,
150             "/page2.html?ignorefrom=pwr&ignorenai=1&ignoresearch_submit=Get%20Resumes&mne=4")
151                     .toExternalForm(), true);
152     }
153 
154     /**
155      * @throws Exception if an error occurs
156      */
157     @Test
158     @Alerts({"§§URL§§page2.html", "3", "§§URL§§page2.html"})
159     public void redirect302() throws Exception {
160         redirectGet(302, HttpMethod.GET, "/page2.html");
161         redirectPost(302, HttpMethod.GET, "/page2.html", false);
162     }
163 
164     /**
165      * @throws Exception if an error occurs
166      */
167     @Test
168     @Alerts({"§§URL§§page2.html", "3", "§§URL§§page2.html"})
169     public void redirectAbsolute302() throws Exception {
170         redirectGet(302, HttpMethod.GET, new URL(URL_FIRST, "/page2.html").toExternalForm());
171         redirectPost(302, HttpMethod.GET, new URL(URL_FIRST, "/page2.html").toExternalForm(), false);
172     }
173 
174     /**
175      * @throws Exception if an error occurs
176      */
177     @Test
178     @Alerts({"§§URL§§page2.html?test=foo", "3", "§§URL§§page2.html?test=foo"})
179     public void redirect302WithQuery() throws Exception {
180         redirectGet(302, HttpMethod.GET, "/page2.html?test=foo");
181         redirectPost(302, HttpMethod.GET, "/page2.html?test=foo", true);
182     }
183 
184     /**
185      * @throws Exception if an error occurs
186      */
187     @Test
188     @Alerts({"§§URL§§page2.html", "3", "§§URL§§page2.html#hash"})
189     public void redirect302WithHash() throws Exception {
190         redirectGet(302, HttpMethod.GET, "/page2.html#hash");
191         redirectPost(302, HttpMethod.GET, "/page2.html#hash", false);
192     }
193 
194     /**
195      * @throws Exception if an error occurs
196      */
197     @Test
198     @Alerts({"§§URL§§page2.html?test=foo", "3", "§§URL§§page2.html?test=foo#hash"})
199     public void redirect302WithQueryAndHash() throws Exception {
200         redirectGet(302, HttpMethod.GET, "/page2.html?test=foo#hash");
201         redirectPost(302, HttpMethod.GET, "/page2.html?test=foo#hash", true);
202     }
203 
204     /**
205      * @throws Exception if an error occurs
206      */
207     @Test
208     @Alerts({"§§URL§§page2.html", "3", "§§URL§§page2.html"})
209     public void redirect303() throws Exception {
210         redirectGet(303, HttpMethod.GET, "/page2.html");
211         redirectPost(303, HttpMethod.GET, "/page2.html", false);
212     }
213 
214     /**
215      * @throws Exception if an error occurs
216      */
217     @Test
218     @Alerts({"§§URL§§page2.html", "3", "§§URL§§page2.html"})
219     public void redirectAbsolute303() throws Exception {
220         redirectGet(303, HttpMethod.GET, new URL(URL_FIRST, "/page2.html").toExternalForm());
221         redirectPost(303, HttpMethod.GET, new URL(URL_FIRST, "/page2.html").toExternalForm(), false);
222     }
223 
224     /**
225      * @throws Exception if an error occurs
226      */
227     @Test
228     @Alerts({"§§URL§§page2.html?test=foo", "3", "§§URL§§page2.html?test=foo"})
229     public void redirect303WithQuery() throws Exception {
230         redirectGet(303, HttpMethod.GET, "/page2.html?test=foo");
231         redirectPost(303, HttpMethod.GET, "/page2.html?test=foo", true);
232     }
233 
234     /**
235      * @throws Exception if an error occurs
236      */
237     @Test
238     @Alerts({"§§URL§§page2.html", "3", "§§URL§§page2.html#hash"})
239     public void redirect303WithHash() throws Exception {
240         redirectGet(303, HttpMethod.GET, "/page2.html#hash");
241         redirectPost(303, HttpMethod.GET, "/page2.html#hash", false);
242     }
243 
244     /**
245      * @throws Exception if an error occurs
246      */
247     @Test
248     @Alerts({"§§URL§§page2.html?test=foo", "3", "§§URL§§page2.html?test=foo#hash"})
249     public void redirect303WithQueryAndHash() throws Exception {
250         redirectGet(303, HttpMethod.GET, "/page2.html?test=foo#hash");
251         redirectPost(303, HttpMethod.GET, "/page2.html?test=foo#hash", true);
252     }
253 
254     /**
255      * @throws Exception if an error occurs
256      */
257     @Test
258     @Alerts({"§§URL§§page2.html", "3", "§§URL§§page2.html"})
259     public void redirect307() throws Exception {
260         redirectGet(307, HttpMethod.GET, "/page2.html");
261         redirectPost(307, HttpMethod.POST, "/page2.html", true);
262     }
263 
264     /**
265      * @throws Exception if an error occurs
266      */
267     @Test
268     @Alerts({"§§URL§§page2.html?test=foo", "3", "§§URL§§page2.html?test=foo"})
269     public void redirect307WithQuery() throws Exception {
270         redirectGet(307, HttpMethod.GET, "/page2.html?test=foo");
271         redirectPost(307, HttpMethod.POST, "/page2.html?test=foo", true);
272     }
273 
274     /**
275      * @throws Exception if an error occurs
276      */
277     @Test
278     @Alerts({"§§URL§§page2.html", "3", "§§URL§§page2.html"})
279     public void redirectAbsolute307() throws Exception {
280         redirectGet(307, HttpMethod.GET, new URL(URL_FIRST, "/page2.html").toExternalForm());
281         redirectPost(307, HttpMethod.POST, new URL(URL_FIRST, "/page2.html").toExternalForm(), true);
282     }
283 
284     /**
285      * @throws Exception if an error occurs
286      */
287     @Test
288     @Alerts({"§§URL§§page2.html", "3", "§§URL§§page2.html#hash"})
289     public void redirect307WithHash() throws Exception {
290         redirectGet(307, HttpMethod.GET, "/page2.html#hash");
291         redirectPost(307, HttpMethod.POST, "/page2.html#hash", true);
292     }
293 
294     /**
295      * @throws Exception if an error occurs
296      */
297     @Test
298     @Alerts({"§§URL§§page2.html?test=foo", "3", "§§URL§§page2.html?test=foo#hash"})
299     public void redirect307WithQueryAndHash() throws Exception {
300         redirectGet(307, HttpMethod.GET, "/page2.html?test=foo#hash");
301         redirectPost(307, HttpMethod.POST, "/page2.html?test=foo#hash", true);
302     }
303 
304     /**
305      * @throws Exception if an error occurs
306      */
307     @Test
308     @Alerts({"§§URL§§page2.html", "3", "§§URL§§page2.html"})
309     public void redirect308() throws Exception {
310         redirectGet(308, HttpMethod.GET, "/page2.html");
311         redirectPost(308, HttpMethod.POST, "/page2.html", true);
312     }
313 
314     /**
315      * @throws Exception if an error occurs
316      */
317     @Test
318     @Alerts({"§§URL§§page2.html?test=foo", "3", "§§URL§§page2.html?test=foo"})
319     public void redirect308WithQuery() throws Exception {
320         redirectGet(308, HttpMethod.GET, "/page2.html?test=foo");
321         redirectPost(308, HttpMethod.POST, "/page2.html?test=foo", true);
322     }
323 
324     /**
325      * @throws Exception if an error occurs
326      */
327     @Test
328     @Alerts({"§§URL§§page2.html", "3", "§§URL§§page2.html"})
329     public void redirectAbsolute308() throws Exception {
330         redirectGet(308, HttpMethod.GET, new URL(URL_FIRST, "/page2.html").toExternalForm());
331         redirectPost(308, HttpMethod.POST, new URL(URL_FIRST, "/page2.html").toExternalForm(), true);
332     }
333 
334     /**
335      * @throws Exception if an error occurs
336      */
337     @Test
338     @Alerts({"§§URL§§page2.html", "3", "§§URL§§page2.html#hash"})
339     public void redirect308WithHash() throws Exception {
340         redirectGet(308, HttpMethod.GET, "/page2.html#hash");
341         redirectPost(308, HttpMethod.POST, "/page2.html#hash", true);
342     }
343 
344     /**
345      * @throws Exception if an error occurs
346      */
347     @Test
348     @Alerts({"§§URL§§page2.html?test=foo", "3", "§§URL§§page2.html?test=foo#hash"})
349     public void redirect308WithQueryAndHash() throws Exception {
350         redirectGet(308, HttpMethod.GET, "/page2.html?test=foo#hash");
351         redirectPost(308, HttpMethod.POST, "/page2.html?test=foo#hash", true);
352     }
353 
354     /**
355      * @throws Exception if an error occurs
356      */
357     @Test
358     @Alerts({"§§URL§§page2.html?ignorefrom=pwr&", "3",
359         "§§URL§§page2.html?ignorefrom=pwr&ignorenai=1&ignoresearch_submit=Get%20Resumes&mne=4"})
360     @HtmlUnitNYI(CHROME = {"§§URL§§page2.html?ignorefrom=pwr&", "3",
361                            "§§URL§§page2.html?ignorefrom=pwr&ignorenai=1&"
362                                    + "%23x26;ignoresearch_submit=Get%20Resumes&%23x26;mne=4"},
363             EDGE = {"§§URL§§page2.html?ignorefrom=pwr&", "3",
364                     "§§URL§§page2.html?ignorefrom=pwr&ignorenai=1&"
365                             + "%23x26;ignoresearch_submit=Get%20Resumes&%23x26;mne=4"},
366             FF = {"§§URL§§page2.html?ignorefrom=pwr&", "3",
367                   "§§URL§§page2.html?ignorefrom=pwr&ignorenai=1&"
368                           + "%23x26;ignoresearch_submit=Get%20Resumes&%23x26;mne=4"},
369             FF_ESR = {"§§URL§§page2.html?ignorefrom=pwr&", "3",
370                       "§§URL§§page2.html?ignorefrom=pwr&ignorenai=1&"
371                               + "%23x26;ignoresearch_submit=Get%20Resumes&%23x26;mne=4"})
372     public void redirect302WithQueryAndHashSpecialChars() throws Exception {
373         redirectGet(302, HttpMethod.GET,
374                 "/page2.html?ignorefrom=pwr&ignorenai=1&ignoresearch_submit=Get%20Resumes&mne=4");
375         redirectPost(302, HttpMethod.GET,
376                 "/page2.html?ignorefrom=pwr&ignorenai=1&ignoresearch_submit=Get%20Resumes&mne=4",
377                 true);
378     }
379 
380     private void redirectGet(final int code, final HttpMethod httpMethod, final String redirectUrl) throws Exception {
381         final String html = DOCTYPE_HTML
382                 + "<html><body><a href='redirect.html'>redirect</a></body></html>";
383         final int reqCount = getMockWebConnection().getRequestCount();
384 
385         final URL url = new URL(URL_FIRST, "page2.html");
386         getMockWebConnection().setResponse(url, html);
387 
388         final List<NameValuePair> headers = new ArrayList<>();
389         headers.add(new NameValuePair("Location", redirectUrl));
390         getMockWebConnection().setDefaultResponse("", code, "Found", null, headers);
391 
392         expandExpectedAlertsVariables(URL_FIRST);
393         final WebDriver driver = loadPage2(html);
394         driver.findElement(By.tagName("a")).click();
395         if (useRealBrowser()) {
396             Thread.sleep(400);
397         }
398 
399         assertEquals(getExpectedAlerts()[0], getMockWebConnection().getLastWebRequest().getUrl().toString());
400         assertEquals(reqCount + Integer.parseInt(getExpectedAlerts()[1]), getMockWebConnection().getRequestCount());
401         assertEquals(httpMethod, getMockWebConnection().getLastWebRequest().getHttpMethod());
402         assertEquals(getExpectedAlerts()[2], driver.getCurrentUrl());
403     }
404 
405     private void redirectPost(final int code, final HttpMethod httpMethod,
406             final String redirectUrl, final boolean resendParams) throws Exception {
407         final String html = DOCTYPE_HTML
408                 + "<html><body><form action='redirect.html' method='POST'>\n"
409                 + "  <input type='hidden' name='param1' value='paramValue'>\n"
410                 + "  <input type='submit' id='postBtn' value='Submit'>\n"
411                 + "</form></body></html>";
412         final int reqCount = getMockWebConnection().getRequestCount();
413 
414         final URL url = new URL(URL_FIRST, "page2.html");
415         getMockWebConnection().setResponse(url, html);
416 
417         final List<NameValuePair> headers = new ArrayList<>();
418         headers.add(new NameValuePair("Location", redirectUrl));
419         getMockWebConnection().setDefaultResponse("", code, "Found", null, headers);
420 
421         expandExpectedAlertsVariables(URL_FIRST);
422         final WebDriver driver = loadPage2(html);
423         driver.findElement(By.id("postBtn")).click();
424         if (useRealBrowser()) {
425             Thread.sleep(400);
426         }
427 
428         assertEquals(reqCount + Integer.parseInt(getExpectedAlerts()[1]), getMockWebConnection().getRequestCount());
429         assertEquals(httpMethod, getMockWebConnection().getLastWebRequest().getHttpMethod());
430 
431         if (resendParams) {
432             assertTrue(getMockWebConnection().getLastWebRequest().getRequestParameters().size() > 0);
433 
434             final NameValuePair param = getMockWebConnection().getLastWebRequest().getRequestParameters().get(0);
435             if ("param1".equals(param.getName())) {
436                 assertEquals("paramValue", param.getValue());
437             }
438             else if ("test".equals(param.getName())) {
439                 assertEquals("foo", param.getValue());
440             }
441             else if (!param.getName().startsWith("ignore")) {
442                 Assertions.fail("unexpected param '" + param.getName() + "'");
443             }
444         }
445         else {
446             assertEquals(0, getMockWebConnection().getLastWebRequest().getRequestParameters().size());
447         }
448 
449         assertEquals(getExpectedAlerts()[0], getMockWebConnection().getLastWebRequest().getUrl().toString());
450         assertEquals(getExpectedAlerts()[2], driver.getCurrentUrl());
451     }
452 
453     /**
454      * Regression test for bug 2822048: a 302 redirect without Location header.
455      * @throws Exception if an error occurs
456      */
457     @Test
458     public void redirect302WithoutLocation() throws Exception {
459         final String html = DOCTYPE_HTML + "<html><body><a href='page2'>to redirect</a></body></html>";
460         getMockWebConnection().setDefaultResponse("", 302, "Found", null);
461 
462         final WebDriver driver = loadPage2(html);
463         driver.findElement(By.tagName("a")).click();
464         assertEquals(URL_FIRST + "page2", driver.getCurrentUrl());
465     }
466 
467     /**
468      * Regression test for bug 3017719: a 302 redirect should change the page url.
469      * @throws Exception if an error occurs
470      */
471     @Test
472     public void redirect302ChangePageUrl() throws Exception {
473         final String html = DOCTYPE_HTML + "<html><body><a href='redirect.html'>redirect</a></body></html>";
474 
475         final URL url = new URL(URL_FIRST, "page2.html");
476         getMockWebConnection().setResponse(url, html);
477 
478         final List<NameValuePair> headers = new ArrayList<>();
479         headers.add(new NameValuePair("Location", "/page2.html"));
480         getMockWebConnection().setDefaultResponse("", 302, "Found", null, headers);
481 
482         final WebDriver driver = loadPage2(html);
483         driver.findElement(By.tagName("a")).click();
484         assertEquals(url.toString(), driver.getCurrentUrl());
485     }
486 
487     /**
488      * Regression test for bug 3035155.
489      * Bug was fixes in HttpClient 4.1.
490      * @throws Exception if an error occurs
491      */
492     @Test
493     public void redirect302UrlsInQuery() throws Exception {
494         final String html = DOCTYPE_HTML + "<html><body><a href='redirect.html'>redirect</a></body></html>";
495 
496         final URL url = new URL(URL_FIRST, "page2.html");
497         getMockWebConnection().setResponse(url, html);
498 
499         final List<NameValuePair> headers = new ArrayList<>();
500         headers.add(new NameValuePair("Location", "/page2.html?param=http%3A//somwhere.org"));
501         getMockWebConnection().setDefaultResponse("", 302, "Found", null, headers);
502 
503         final WebDriver driver = loadPage2(html);
504         driver.findElement(By.tagName("a")).click();
505         assertEquals(url + "?param=http%3A//somwhere.org", driver.getCurrentUrl());
506     }
507 }