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