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 static org.junit.Assert.fail;
18  
19  import java.net.URL;
20  import java.net.URLEncoder;
21  import java.nio.charset.Charset;
22  import java.time.Duration;
23  import java.util.Arrays;
24  
25  import org.apache.commons.lang3.StringUtils;
26  import org.htmlunit.junit.BrowserRunner;
27  import org.htmlunit.junit.annotation.Alerts;
28  import org.htmlunit.junit.annotation.HtmlUnitNYI;
29  import org.htmlunit.junit.annotation.NotYetImplemented;
30  import org.htmlunit.junit.annotation.OS;
31  import org.junit.Assert;
32  import org.junit.Test;
33  import org.junit.runner.RunWith;
34  import org.openqa.selenium.By;
35  import org.openqa.selenium.WebDriver;
36  import org.openqa.selenium.support.ui.ExpectedCondition;
37  import org.openqa.selenium.support.ui.Wait;
38  import org.openqa.selenium.support.ui.WebDriverWait;
39  
40  /**
41   * Tests using the {@link PrimitiveWebServer}.
42   *
43   * @author Ahmed Ashour
44   * @author Ronald Brill
45   */
46  @RunWith(BrowserRunner.class)
47  public class HttpWebConnection3Test extends WebDriverTestCase {
48  
49      /**
50       * @throws Exception if the test fails
51       */
52      @Test
53      @Alerts(DEFAULT = {HttpHeader.HOST, HttpHeader.CONNECTION, HttpHeader.SEC_CH_UA, HttpHeader.SEC_CH_UA_MOBILE,
54                         HttpHeader.SEC_CH_UA_PLATFORM,
55                         HttpHeader.UPGRADE_INSECURE_REQUESTS, HttpHeader.USER_AGENT, HttpHeader.ACCEPT,
56                         HttpHeader.SEC_FETCH_SITE, HttpHeader.SEC_FETCH_MODE, HttpHeader.SEC_FETCH_USER,
57                         HttpHeader.SEC_FETCH_DEST, HttpHeader.ACCEPT_ENCODING, HttpHeader.ACCEPT_LANGUAGE},
58              FF = {HttpHeader.HOST, HttpHeader.USER_AGENT, HttpHeader.ACCEPT, HttpHeader.ACCEPT_LANGUAGE,
59                    HttpHeader.ACCEPT_ENCODING, HttpHeader.CONNECTION, HttpHeader.UPGRADE_INSECURE_REQUESTS,
60                    HttpHeader.SEC_FETCH_DEST, HttpHeader.SEC_FETCH_MODE, HttpHeader.SEC_FETCH_SITE,
61                    HttpHeader.SEC_FETCH_USER, HttpHeader.PRIORITY},
62              FF_ESR = {HttpHeader.HOST, HttpHeader.USER_AGENT, HttpHeader.ACCEPT, HttpHeader.ACCEPT_LANGUAGE,
63                        HttpHeader.ACCEPT_ENCODING, HttpHeader.CONNECTION, HttpHeader.UPGRADE_INSECURE_REQUESTS,
64                        HttpHeader.SEC_FETCH_DEST, HttpHeader.SEC_FETCH_MODE, HttpHeader.SEC_FETCH_SITE,
65                        HttpHeader.SEC_FETCH_USER, HttpHeader.PRIORITY})
66      public void headers() throws Exception {
67          final String response = "HTTP/1.1 200 OK\r\n"
68              + "Content-Length: 2\r\n"
69              + "Content-Type: text/plain\r\n"
70              + "\r\n"
71              + "Hi";
72  
73          shutDownAll();
74          try (PrimitiveWebServer primitiveWebServer = new PrimitiveWebServer(null, response, null)) {
75              final WebDriver driver = getWebDriver();
76  
77              driver.get("http://localhost:" + primitiveWebServer.getPort());
78              final String request = primitiveWebServer.getRequests().get(0);
79              final String[] headers = request.split("\\r\\n");
80              final String[] result = new String[headers.length - 1];
81              for (int i = 0; i < result.length; i++) {
82                  final String header = headers[i + 1];
83                  result[i] = header.substring(0, header.indexOf(':'));
84              }
85              assertEquals(Arrays.asList(getExpectedAlerts()).toString(), Arrays.asList(result).toString());
86          }
87      }
88  
89      /**
90       * @throws Exception if the test fails
91       */
92      @Test
93      @Alerts(DEFAULT = {HttpHeader.HOST, HttpHeader.CONNECTION,
94                         HttpHeader.SEC_CH_UA, HttpHeader.SEC_CH_UA_MOBILE,
95                         HttpHeader.SEC_CH_UA_PLATFORM,
96                         HttpHeader.UPGRADE_INSECURE_REQUESTS,
97                         HttpHeader.USER_AGENT, HttpHeader.ACCEPT, HttpHeader.SEC_FETCH_SITE,
98                         HttpHeader.SEC_FETCH_MODE, HttpHeader.SEC_FETCH_USER, HttpHeader.SEC_FETCH_DEST,
99                         HttpHeader.REFERER, HttpHeader.ACCEPT_ENCODING, HttpHeader.ACCEPT_LANGUAGE,
100                        HttpHeader.COOKIE},
101             FF = {HttpHeader.HOST, HttpHeader.USER_AGENT, HttpHeader.ACCEPT, HttpHeader.ACCEPT_LANGUAGE,
102                   HttpHeader.ACCEPT_ENCODING, HttpHeader.CONNECTION, HttpHeader.REFERER, HttpHeader.COOKIE,
103                   HttpHeader.UPGRADE_INSECURE_REQUESTS, HttpHeader.SEC_FETCH_DEST, HttpHeader.SEC_FETCH_MODE,
104                   HttpHeader.SEC_FETCH_SITE, HttpHeader.SEC_FETCH_USER, HttpHeader.PRIORITY},
105             FF_ESR = {HttpHeader.HOST, HttpHeader.USER_AGENT, HttpHeader.ACCEPT, HttpHeader.ACCEPT_LANGUAGE,
106                       HttpHeader.ACCEPT_ENCODING, HttpHeader.CONNECTION, HttpHeader.REFERER, HttpHeader.COOKIE,
107                       HttpHeader.UPGRADE_INSECURE_REQUESTS, HttpHeader.SEC_FETCH_DEST, HttpHeader.SEC_FETCH_MODE,
108                       HttpHeader.SEC_FETCH_SITE, HttpHeader.SEC_FETCH_USER, HttpHeader.PRIORITY})
109     public void headers_cookie_referer() throws Exception {
110         final String htmlResponse = "<a href='2.html'>Click me</a>";
111         final String response = "HTTP/1.1 200 OK\r\n"
112             + "Content-Length: " + htmlResponse.length() + "\r\n"
113             + "Content-Type: text/html\r\n"
114             + "Set-Cookie: name=value\r\n"
115             + "\r\n"
116             + htmlResponse;
117 
118         shutDownAll();
119         try (PrimitiveWebServer primitiveWebServer = new PrimitiveWebServer(null, response, null)) {
120             final WebDriver driver = getWebDriver();
121 
122             driver.get("http://localhost:" + primitiveWebServer.getPort());
123             driver.findElement(By.linkText("Click me")).click();
124 
125             final Wait<WebDriver> wait = new WebDriverWait(driver, Duration.ofSeconds(5));
126             wait.until(currentUrlContains("2.html"));
127 
128             int index = 1;
129             String request;
130             do {
131                 request = primitiveWebServer.getRequests().get(index++);
132             }
133             while (request.contains("/favicon.ico"));
134 
135             final String[] headers = request.split("\\r\\n");
136             final String[] result = new String[headers.length - 1];
137             for (int i = 0; i < result.length; i++) {
138                 final String header = headers[i + 1];
139                 result[i] = header.substring(0, header.indexOf(':'));
140             }
141             assertEquals(Arrays.asList(getExpectedAlerts()).toString(), Arrays.asList(result).toString());
142         }
143     }
144 
145     /**
146      * @throws Exception if the test fails
147      */
148     @Test
149     @Alerts("gzip, deflate, br, zstd")
150     @HtmlUnitNYI(CHROME = "gzip, deflate, br",
151             EDGE = "gzip, deflate, br",
152             FF = "gzip, deflate, br",
153             FF_ESR = "gzip, deflate, br")
154     public void acceptEncoding() throws Exception {
155         final String response = "HTTP/1.1 200 OK\r\n"
156             + "Content-Length: 2\r\n"
157             + "Content-Type: text/plain\r\n"
158             + "\r\n"
159             + "Hi";
160 
161         shutDownAll();
162         try (PrimitiveWebServer primitiveWebServer = new PrimitiveWebServer(null, response, null)) {
163             final WebDriver driver = getWebDriver();
164 
165             driver.get("http://localhost:" + primitiveWebServer.getPort());
166             final String request = primitiveWebServer.getRequests().get(0);
167             final String[] headers = request.split("\\r\\n");
168             for (int i = 0; i < headers.length; i++) {
169                 final String header = headers[i];
170                 if (StringUtils.startsWithIgnoreCase(header, HttpHeader.ACCEPT_ENCODING_LC)) {
171                     final String value = header.substring(header.indexOf(':') + 1);
172                     assertEquals(getExpectedAlerts()[0], value.trim());
173                     return;
174                 }
175             }
176             fail("No accept-encoding header found.");
177         }
178     }
179 
180     /**
181      * An expectation for checking that the current url contains a case-sensitive substring.
182      *
183      * @param url the fragment of url expected
184      * @return true when the url matches, false otherwise
185      */
186     public static ExpectedCondition<Boolean> currentUrlContains(final String url) {
187         return new ExpectedCondition<Boolean>() {
188             @Override
189             public Boolean apply(final WebDriver driver) {
190                 final String currentUrl = driver.getCurrentUrl();
191                 return currentUrl != null && currentUrl.contains(url);
192             }
193         };
194     }
195 
196     /**
197      * Test for bug #1898.
198      *
199      * @throws Exception if an error occurs
200      */
201     @Test
202     @Alerts("§§URL§§?????")
203     // seems to work only when running alone
204     public void locationUTF() throws Exception {
205         final String url = "http://localhost:" + PORT_PRIMITIVE_SERVER + "/";
206 
207         final String response = "HTTP/1.1 302 Found\r\n"
208                 + "Content-Length: 0\r\n"
209                 + "Location: " +  url + "\u0623\u0647\u0644\u0627\u064b" + "\r\n"
210                 + "\r\n";
211 
212         final String response2 = "HTTP/1.1 200 OK\r\n"
213                 + "Content-Length: 2\r\n"
214                 + "Content-Type: text/html\r\n"
215                 + "\r\n"
216                 + "Hi";
217 
218         expandExpectedAlertsVariables(new URL(url));
219 
220         shutDownAll();
221         try (PrimitiveWebServer primitiveWebServer = new PrimitiveWebServer(null, response, response2)) {
222             final WebDriver driver = getWebDriver();
223 
224             driver.get(url);
225             assertEquals(getExpectedAlerts()[0], driver.getCurrentUrl());
226             assertTrue(driver.getPageSource().contains("Hi"));
227 
228             assertEquals(2, primitiveWebServer.getRequests().size());
229         }
230     }
231 
232     /**
233      * Test for bug #1898.
234      *
235      * @throws Exception if an error occurs
236      */
237     @Test
238     @Alerts("§§URL§§test?%D8%A3%D9%87%D9%84%D8%A7%D9%8B")
239     public void locationQueryUTF8Encoded() throws Exception {
240         final String url = "http://localhost:" + PORT_PRIMITIVE_SERVER + "/";
241 
242         final String response = "HTTP/1.1 302 Found\r\n"
243                 + "Content-Length: 0\r\n"
244                 + "Location: "
245                     +  url
246                     + "test?"
247                     + URLEncoder.encode("\u0623\u0647\u0644\u0627\u064b", "UTF-8")
248                     + "\r\n"
249                 + "\r\n";
250 
251         final String response2 = "HTTP/1.1 200 OK\r\n"
252                 + "Content-Length: 2\r\n"
253                 + "Content-Type: text/html\r\n"
254                 + "\r\n"
255                 + "Hi";
256 
257         expandExpectedAlertsVariables(new URL(url));
258 
259         shutDownAll();
260         try (PrimitiveWebServer primitiveWebServer = new PrimitiveWebServer(null, response, response2)) {
261             final WebDriver driver = getWebDriver();
262 
263             driver.get(url);
264             Thread.sleep(DEFAULT_WAIT_TIME.toMillis());
265             assertEquals(getExpectedAlerts()[0], driver.getCurrentUrl());
266             assertEquals(2, primitiveWebServer.getRequests().size());
267             assertTrue(driver.getPageSource(), driver.getPageSource().contains("Hi"));
268         }
269     }
270 
271     /**
272      * Test for bug #1898.
273      *
274      * @throws Exception if an error occurs
275      */
276     @Test
277     @Alerts("§§URL§§%D8%A3%D9%87%D9%84%D8%A7%D9%8B")
278     public void locationUTF8Encoded() throws Exception {
279         final String url = "http://localhost:" + PORT_PRIMITIVE_SERVER + "/";
280 
281         final String response = "HTTP/1.1 302 Found\r\n"
282                 + "Content-Length: 0\r\n"
283                 + "Location: "
284                     +  url
285                     + URLEncoder.encode("\u0623\u0647\u0644\u0627\u064b", "UTF-8")
286                     + "\r\n"
287                 + "\r\n";
288 
289         final String response2 = "HTTP/1.1 200 OK\r\n"
290                 + "Content-Length: 2\r\n"
291                 + "Content-Type: text/html\r\n"
292                 + "\r\n"
293                 + "Hi";
294 
295         expandExpectedAlertsVariables(new URL(url));
296 
297         shutDownAll();
298         try (PrimitiveWebServer primitiveWebServer = new PrimitiveWebServer(null, response, response2)) {
299             final WebDriver driver = getWebDriver();
300 
301             driver.get(url);
302             assertEquals(getExpectedAlerts()[0], driver.getCurrentUrl());
303             assertTrue(driver.getPageSource().contains("Hi"));
304 
305             assertEquals(2, primitiveWebServer.getRequests().size());
306         }
307     }
308 
309     /**
310      * Test case for Bug #1882.
311      *
312      * @throws Exception if the test fails
313      */
314     @Test
315     @Alerts("para=%u65E5")
316     @HtmlUnitNYI(CHROME = "para=%25u65E5",
317             EDGE = "para=%25u65E5",
318             FF = "para=%25u65E5",
319             FF_ESR = "para=%25u65E5")
320     public void queryString() throws Exception {
321         final String response = "HTTP/1.1 302 Found\r\n"
322                 + "Content-Length: 0\r\n"
323                 + "\r\n";
324 
325         shutDownAll();
326         try (PrimitiveWebServer primitiveWebServer = new PrimitiveWebServer(null, response, null)) {
327             final WebDriver driver = getWebDriver();
328 
329             driver.get("http://localhost:" + primitiveWebServer.getPort() + "?para=%u65E5");
330             assertTrue(primitiveWebServer.getRequests().get(0),
331                         primitiveWebServer.getRequests().get(0).contains(getExpectedAlerts()[0]));
332         }
333     }
334 
335     /**
336      * Tests a form get request.
337      * @throws Exception if the test fails
338      */
339     @Test
340     @Alerts(CHROME = {"GET /foo?text1=me+%26amp%3B+you&text2=Hello%0D%0Aworld%21 HTTP/1.1",
341                       "Host: localhost:§§PORT§§",
342                       "Connection: keep-alive",
343                       "sec-ch-ua: §§SEC_USER_AGENT§§",
344                       "sec-ch-ua-mobile: ?0",
345                       "sec-ch-ua-platform: \"Windows\"",
346                       "Upgrade-Insecure-Requests: 1",
347                       "User-Agent: §§USER_AGENT§§",
348                       "Accept: §§ACCEPT§§",
349                       "Sec-Fetch-Site: same-origin",
350                       "Sec-Fetch-Mode: navigate",
351                       "Sec-Fetch-User: ?1",
352                       "Sec-Fetch-Dest: document",
353                       "Referer: http://localhost:§§PORT§§/",
354                       "Accept-Encoding: gzip, deflate, br, zstd",
355                       "Accept-Language: en-US,en;q=0.9"},
356             EDGE = {"GET /foo?text1=me+%26amp%3B+you&text2=Hello%0D%0Aworld%21 HTTP/1.1",
357                     "Host: localhost:§§PORT§§",
358                     "Connection: keep-alive",
359                     "sec-ch-ua: §§SEC_USER_AGENT§§",
360                     "sec-ch-ua-mobile: ?0",
361                     "sec-ch-ua-platform: \"Windows\"",
362                     "Upgrade-Insecure-Requests: 1",
363                     "User-Agent: §§USER_AGENT§§",
364                     "Accept: §§ACCEPT§§",
365                     "Sec-Fetch-Site: same-origin",
366                     "Sec-Fetch-Mode: navigate",
367                     "Sec-Fetch-User: ?1",
368                     "Sec-Fetch-Dest: document",
369                     "Referer: http://localhost:§§PORT§§/",
370                     "Accept-Encoding: gzip, deflate, br, zstd",
371                     "Accept-Language: en-US,en;q=0.9"},
372             FF = {"GET /foo?text1=me+%26amp%3B+you&text2=Hello%0D%0Aworld%21 HTTP/1.1",
373                   "Host: localhost:§§PORT§§",
374                   "User-Agent: §§USER_AGENT§§",
375                   "Accept: §§ACCEPT§§",
376                   "Accept-Language: en-US,en;q=0.5",
377                   "Accept-Encoding: gzip, deflate, br, zstd",
378                   "Connection: keep-alive",
379                   "Referer: http://localhost:§§PORT§§/",
380                   "Upgrade-Insecure-Requests: 1",
381                   "Sec-Fetch-Dest: document",
382                   "Sec-Fetch-Mode: navigate",
383                   "Sec-Fetch-Site: same-origin",
384                   "Sec-Fetch-User: ?1",
385                   "Priority: u=0, i"},
386             FF_ESR = {"GET /foo?text1=me+%26amp%3B+you&text2=Hello%0D%0Aworld%21 HTTP/1.1",
387                       "Host: localhost:§§PORT§§",
388                       "User-Agent: §§USER_AGENT§§",
389                       "Accept: §§ACCEPT§§",
390                       "Accept-Language: en-US,en;q=0.5",
391                       "Accept-Encoding: gzip, deflate, br, zstd",
392                       "Connection: keep-alive",
393                       "Referer: http://localhost:§§PORT§§/",
394                       "Upgrade-Insecure-Requests: 1",
395                       "Sec-Fetch-Dest: document",
396                       "Sec-Fetch-Mode: navigate",
397                       "Sec-Fetch-Site: same-origin",
398                       "Sec-Fetch-User: ?1",
399                       "Priority: u=0, i"})
400     @HtmlUnitNYI(CHROME = {"GET /foo?text1=me+%26amp%3B+you&text2=Hello%0D%0Aworld%21 HTTP/1.1",
401                            "Host: localhost:§§PORT§§",
402                            "Connection: keep-alive",
403                            "sec-ch-ua: §§SEC_USER_AGENT§§",
404                            "sec-ch-ua-mobile: ?0",
405                            "sec-ch-ua-platform: \"Windows\"",
406                            "Upgrade-Insecure-Requests: 1",
407                            "User-Agent: §§USER_AGENT§§",
408                            "Accept: §§ACCEPT§§",
409                            "Sec-Fetch-Site: same-origin",
410                            "Sec-Fetch-Mode: navigate",
411                            "Sec-Fetch-User: ?1",
412                            "Sec-Fetch-Dest: document",
413                            "Referer: http://localhost:§§PORT§§/",
414                            "Accept-Encoding: gzip, deflate, br",
415                            "Accept-Language: en-US,en;q=0.9"},
416             EDGE = {"GET /foo?text1=me+%26amp%3B+you&text2=Hello%0D%0Aworld%21 HTTP/1.1",
417                     "Host: localhost:§§PORT§§",
418                     "Connection: keep-alive",
419                     "sec-ch-ua: §§SEC_USER_AGENT§§",
420                     "sec-ch-ua-mobile: ?0",
421                     "sec-ch-ua-platform: \"Windows\"",
422                     "Upgrade-Insecure-Requests: 1",
423                     "User-Agent: §§USER_AGENT§§",
424                     "Accept: §§ACCEPT§§",
425                     "Sec-Fetch-Site: same-origin",
426                     "Sec-Fetch-Mode: navigate",
427                     "Sec-Fetch-User: ?1",
428                     "Sec-Fetch-Dest: document",
429                     "Referer: http://localhost:§§PORT§§/",
430                     "Accept-Encoding: gzip, deflate, br",
431                     "Accept-Language: en-US,en;q=0.9"},
432             FF = {"GET /foo?text1=me+%26amp%3B+you&text2=Hello%0D%0Aworld%21 HTTP/1.1",
433                   "Host: localhost:§§PORT§§",
434                   "User-Agent: §§USER_AGENT§§",
435                   "Accept: §§ACCEPT§§",
436                   "Accept-Language: en-US,en;q=0.5",
437                   "Accept-Encoding: gzip, deflate, br",
438                   "Connection: keep-alive",
439                   "Referer: http://localhost:§§PORT§§/",
440                   "Upgrade-Insecure-Requests: 1",
441                   "Sec-Fetch-Dest: document",
442                   "Sec-Fetch-Mode: navigate",
443                   "Sec-Fetch-Site: same-origin",
444                   "Sec-Fetch-User: ?1",
445                   "Priority: u=0, i"},
446             FF_ESR = {"GET /foo?text1=me+%26amp%3B+you&text2=Hello%0D%0Aworld%21 HTTP/1.1",
447                       "Host: localhost:§§PORT§§",
448                       "User-Agent: §§USER_AGENT§§",
449                       "Accept: §§ACCEPT§§",
450                       "Accept-Language: en-US,en;q=0.5",
451                       "Accept-Encoding: gzip, deflate, br",
452                       "Connection: keep-alive",
453                       "Referer: http://localhost:§§PORT§§/",
454                       "Upgrade-Insecure-Requests: 1",
455                       "Sec-Fetch-Dest: document",
456                       "Sec-Fetch-Mode: navigate",
457                       "Sec-Fetch-Site: same-origin",
458                       "Sec-Fetch-User: ?1",
459                       "Priority: u=0, i"})
460     public void formGet() throws Exception {
461         String html = DOCTYPE_HTML
462             + "<html><body><form action='foo' method='get' accept-charset='iso-8859-1'>\n"
463             + "<input name='text1' value='me &amp;amp; you'>\n"
464             + "<textarea name='text2'>Hello\nworld!</textarea>\n"
465             + "<input type='submit' id='submit'>\n"
466             + "</form></body></html>";
467         html = "HTTP/1.1 200 OK\r\n"
468                 + "Content-Length: " + (html.length()) + "\r\n"
469                 + "Content-Type: text/html\r\n"
470                 + "\r\n"
471                 + html;
472         final String hi = "HTTP/1.1 200 OK\r\n"
473                 + "Content-Length: 2\r\n"
474                 + "Content-Type: text/plain\r\n"
475                 + "\r\n"
476                 + "Hi";
477 
478         shutDownAll();
479         try (PrimitiveWebServer primitiveWebServer = new PrimitiveWebServer(null, html, hi)) {
480             final WebDriver driver = getWebDriver();
481 
482             driver.get("http://localhost:" + primitiveWebServer.getPort());
483             driver.findElement(By.id("submit")).click();
484 
485             final String[] expectedHeaders = getExpectedAlerts();
486             for (int i = 0; i < expectedHeaders.length; i++) {
487                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§PORT§§", "" + primitiveWebServer.getPort());
488                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§USER_AGENT§§",
489                         getBrowserVersion().getUserAgent());
490                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§SEC_USER_AGENT§§",
491                         getBrowserVersion().getSecClientHintUserAgentHeader());
492                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§ACCEPT§§",
493                         getBrowserVersion().getHtmlAcceptHeader());
494             }
495             final String request = primitiveWebServer.getRequests().get(1);
496             final String[] headers = request.split("\\r\\n");
497             assertEquals(Arrays.asList(expectedHeaders).toString(), Arrays.asList(headers).toString());
498         }
499     }
500 
501     /**
502      * Tests a form post request.
503      * @throws Exception if the test fails
504      */
505     @Test
506     @Alerts(CHROME = {"POST /foo HTTP/1.1",
507                       "Host: localhost:§§PORT§§",
508                       "Connection: keep-alive",
509                       "Content-Length: 48",
510                       "Cache-Control: max-age=0",
511                       "sec-ch-ua: §§SEC_USER_AGENT§§",
512                       "sec-ch-ua-mobile: ?0",
513                       "sec-ch-ua-platform: \"Windows\"",
514                       "Origin: http://localhost:§§PORT§§",
515                       "Content-Type: application/x-www-form-urlencoded",
516                       "Upgrade-Insecure-Requests: 1",
517                       "User-Agent: §§USER_AGENT§§",
518                       "Accept: §§ACCEPT§§",
519                       "Sec-Fetch-Site: same-origin",
520                       "Sec-Fetch-Mode: navigate",
521                       "Sec-Fetch-User: ?1",
522                       "Sec-Fetch-Dest: document",
523                       "Referer: http://localhost:§§PORT§§/",
524                       "Accept-Encoding: gzip, deflate, br, zstd",
525                       "Accept-Language: en-US,en;q=0.9",
526                       "",
527                       "text1=me+%26amp%3B+you&text2=Hello%0D%0Aworld%21"},
528             EDGE = {"POST /foo HTTP/1.1",
529                     "Host: localhost:§§PORT§§",
530                     "Connection: keep-alive",
531                     "Content-Length: 48",
532                     "Cache-Control: max-age=0",
533                     "sec-ch-ua: §§SEC_USER_AGENT§§",
534                     "sec-ch-ua-mobile: ?0",
535                     "sec-ch-ua-platform: \"Windows\"",
536                     "Origin: http://localhost:§§PORT§§",
537                     "Content-Type: application/x-www-form-urlencoded",
538                     "Upgrade-Insecure-Requests: 1",
539                     "User-Agent: §§USER_AGENT§§",
540                     "Accept: §§ACCEPT§§",
541                     "Sec-Fetch-Site: same-origin",
542                     "Sec-Fetch-Mode: navigate",
543                     "Sec-Fetch-User: ?1",
544                     "Sec-Fetch-Dest: document",
545                     "Referer: http://localhost:§§PORT§§/",
546                     "Accept-Encoding: gzip, deflate, br, zstd",
547                     "Accept-Language: en-US,en;q=0.9",
548                     "",
549                     "text1=me+%26amp%3B+you&text2=Hello%0D%0Aworld%21"},
550             FF = {"POST /foo HTTP/1.1",
551                   "Host: localhost:§§PORT§§",
552                   "User-Agent: §§USER_AGENT§§",
553                   "Accept: §§ACCEPT§§",
554                   "Accept-Language: en-US,en;q=0.5",
555                   "Accept-Encoding: gzip, deflate, br, zstd",
556                   "Content-Type: application/x-www-form-urlencoded",
557                   "Content-Length: 48",
558                   "Origin: http://localhost:§§PORT§§",
559                   "Connection: keep-alive",
560                   "Referer: http://localhost:§§PORT§§/",
561                   "Upgrade-Insecure-Requests: 1",
562                   "Sec-Fetch-Dest: document",
563                   "Sec-Fetch-Mode: navigate",
564                   "Sec-Fetch-Site: same-origin",
565                   "Sec-Fetch-User: ?1",
566                   "Priority: u=0, i",
567                   "",
568                   "text1=me+%26amp%3B+you&text2=Hello%0D%0Aworld%21"},
569             FF_ESR = {"POST /foo HTTP/1.1",
570                       "Host: localhost:§§PORT§§",
571                       "User-Agent: §§USER_AGENT§§",
572                       "Accept: §§ACCEPT§§",
573                       "Accept-Language: en-US,en;q=0.5",
574                       "Accept-Encoding: gzip, deflate, br, zstd",
575                       "Content-Type: application/x-www-form-urlencoded",
576                       "Content-Length: 48",
577                       "Origin: http://localhost:§§PORT§§",
578                       "Connection: keep-alive",
579                       "Referer: http://localhost:§§PORT§§/",
580                       "Upgrade-Insecure-Requests: 1",
581                       "Sec-Fetch-Dest: document",
582                       "Sec-Fetch-Mode: navigate",
583                       "Sec-Fetch-Site: same-origin",
584                       "Sec-Fetch-User: ?1",
585                       "Priority: u=0, i",
586                       "",
587                       "text1=me+%26amp%3B+you&text2=Hello%0D%0Aworld%21"})
588     @HtmlUnitNYI(CHROME = {"POST /foo HTTP/1.1",
589                            "Host: localhost:§§PORT§§",
590                            "Connection: keep-alive",
591                            "sec-ch-ua: §§SEC_USER_AGENT§§",
592                            "sec-ch-ua-mobile: ?0",
593                            "sec-ch-ua-platform: \"Windows\"",
594                            "Upgrade-Insecure-Requests: 1",
595                            "User-Agent: §§USER_AGENT§§",
596                            "Accept: §§ACCEPT§§",
597                            "Sec-Fetch-Site: same-origin",
598                            "Sec-Fetch-Mode: navigate",
599                            "Sec-Fetch-User: ?1",
600                            "Sec-Fetch-Dest: document",
601                            "Referer: http://localhost:§§PORT§§/",
602                            "Accept-Encoding: gzip, deflate, br",
603                            "Accept-Language: en-US,en;q=0.9",
604                            "Origin: http://localhost:§§PORT§§",
605                            "Cache-Control: max-age=0",
606                            "Content-Length: 48",
607                            "Content-Type: application/x-www-form-urlencoded",
608                            "",
609                            "text1=me+%26amp%3B+you&text2=Hello%0D%0Aworld%21"},
610             EDGE = {"POST /foo HTTP/1.1",
611                     "Host: localhost:§§PORT§§",
612                     "Connection: keep-alive",
613                     "sec-ch-ua: §§SEC_USER_AGENT§§",
614                     "sec-ch-ua-mobile: ?0",
615                     "sec-ch-ua-platform: \"Windows\"",
616                     "Upgrade-Insecure-Requests: 1",
617                     "User-Agent: §§USER_AGENT§§",
618                     "Accept: §§ACCEPT§§",
619                     "Sec-Fetch-Site: same-origin",
620                     "Sec-Fetch-Mode: navigate",
621                     "Sec-Fetch-User: ?1",
622                     "Sec-Fetch-Dest: document",
623                     "Referer: http://localhost:§§PORT§§/",
624                     "Accept-Encoding: gzip, deflate, br",
625                     "Accept-Language: en-US,en;q=0.9",
626                     "Origin: http://localhost:§§PORT§§",
627                     "Cache-Control: max-age=0",
628                     "Content-Length: 48",
629                     "Content-Type: application/x-www-form-urlencoded",
630                     "",
631                     "text1=me+%26amp%3B+you&text2=Hello%0D%0Aworld%21"},
632             FF = {"POST /foo HTTP/1.1",
633                   "Host: localhost:§§PORT§§",
634                   "User-Agent: §§USER_AGENT§§",
635                   "Accept: §§ACCEPT§§",
636                   "Accept-Language: en-US,en;q=0.5",
637                   "Accept-Encoding: gzip, deflate, br",
638                   "Connection: keep-alive",
639                   "Referer: http://localhost:§§PORT§§/",
640                   "Upgrade-Insecure-Requests: 1",
641                   "Sec-Fetch-Dest: document",
642                   "Sec-Fetch-Mode: navigate",
643                   "Sec-Fetch-Site: same-origin",
644                   "Sec-Fetch-User: ?1",
645                   "Priority: u=0, i",
646                   "Origin: http://localhost:§§PORT§§",
647                   "Content-Length: 48",
648                   "Content-Type: application/x-www-form-urlencoded",
649                   "",
650                   "text1=me+%26amp%3B+you&text2=Hello%0D%0Aworld%21"},
651             FF_ESR = {"POST /foo HTTP/1.1",
652                       "Host: localhost:§§PORT§§",
653                       "User-Agent: §§USER_AGENT§§",
654                       "Accept: §§ACCEPT§§",
655                       "Accept-Language: en-US,en;q=0.5",
656                       "Accept-Encoding: gzip, deflate, br",
657                       "Connection: keep-alive",
658                       "Referer: http://localhost:§§PORT§§/",
659                       "Upgrade-Insecure-Requests: 1",
660                       "Sec-Fetch-Dest: document",
661                       "Sec-Fetch-Mode: navigate",
662                       "Sec-Fetch-Site: same-origin",
663                       "Sec-Fetch-User: ?1",
664                       "Priority: u=0, i",
665                       "Origin: http://localhost:§§PORT§§",
666                       "Content-Length: 48",
667                       "Content-Type: application/x-www-form-urlencoded",
668                       "",
669                       "text1=me+%26amp%3B+you&text2=Hello%0D%0Aworld%21"})
670     public void formPost() throws Exception {
671         String html = DOCTYPE_HTML
672             + "<html><body><form action='foo' method='post' accept-charset='iso-8859-1'>\n"
673             + "<input name='text1' value='me &amp;amp; you'>\n"
674             + "<textarea name='text2'>Hello\nworld!</textarea>\n"
675             + "<input type='submit' id='submit'>\n"
676             + "</form></body></html>";
677         html = "HTTP/1.1 200 OK\r\n"
678                 + "Content-Length: " + (html.length()) + "\r\n"
679                 + "Content-Type: text/html\r\n"
680                 + "\r\n"
681                 + html;
682         final String hi = "HTTP/1.1 200 OK\r\n"
683                 + "Content-Length: 2\r\n"
684                 + "Content-Type: text/plain\r\n"
685                 + "\r\n"
686                 + "Hi";
687 
688         shutDownAll();
689         try (PrimitiveWebServer primitiveWebServer = new PrimitiveWebServer(null, html, hi)) {
690             final WebDriver driver = getWebDriver();
691 
692             driver.get("http://localhost:" + primitiveWebServer.getPort());
693             Thread.sleep(4_000);
694             driver.findElement(By.id("submit")).click();
695 
696             final String[] expectedHeaders = getExpectedAlerts();
697             for (int i = 0; i < expectedHeaders.length; i++) {
698                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§PORT§§", "" + primitiveWebServer.getPort());
699                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§USER_AGENT§§",
700                         getBrowserVersion().getUserAgent());
701                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§SEC_USER_AGENT§§",
702                         getBrowserVersion().getSecClientHintUserAgentHeader());
703                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§ACCEPT§§",
704                         getBrowserVersion().getHtmlAcceptHeader());
705             }
706             final String request = primitiveWebServer.getRequests().get(1);
707             final String[] headers = request.split("\\r\\n");
708             assertEquals(Arrays.asList(expectedHeaders).toString(), Arrays.asList(headers).toString());
709         }
710     }
711 
712     /**
713      * Tests a anchor click request.
714      * @throws Exception if the test fails
715      */
716     @Test
717     @Alerts(CHROME = {"GET /2.html HTTP/1.1",
718                       "Host: localhost:§§PORT§§",
719                       "Connection: keep-alive",
720                       "sec-ch-ua: §§SEC_USER_AGENT§§",
721                       "sec-ch-ua-mobile: ?0",
722                       "sec-ch-ua-platform: \"Windows\"",
723                       "Upgrade-Insecure-Requests: 1",
724                       "User-Agent: §§USER_AGENT§§",
725                       "Accept: §§ACCEPT§§",
726                       "Sec-Fetch-Site: same-origin",
727                       "Sec-Fetch-Mode: navigate",
728                       "Sec-Fetch-User: ?1",
729                       "Sec-Fetch-Dest: document",
730                       "Referer: http://localhost:§§PORT§§/",
731                       "Accept-Encoding: gzip, deflate, br, zstd",
732                       "Accept-Language: en-US,en;q=0.9"},
733             EDGE = {"GET /2.html HTTP/1.1",
734                     "Host: localhost:§§PORT§§",
735                     "Connection: keep-alive",
736                     "sec-ch-ua: §§SEC_USER_AGENT§§",
737                     "sec-ch-ua-mobile: ?0",
738                     "sec-ch-ua-platform: \"Windows\"",
739                     "Upgrade-Insecure-Requests: 1",
740                     "User-Agent: §§USER_AGENT§§",
741                     "Accept: §§ACCEPT§§",
742                     "Sec-Fetch-Site: same-origin",
743                     "Sec-Fetch-Mode: navigate",
744                     "Sec-Fetch-User: ?1",
745                     "Sec-Fetch-Dest: document",
746                     "Referer: http://localhost:§§PORT§§/",
747                     "Accept-Encoding: gzip, deflate, br, zstd",
748                     "Accept-Language: en-US,en;q=0.9"},
749             FF = {"GET /2.html HTTP/1.1",
750                   "Host: localhost:§§PORT§§",
751                   "User-Agent: §§USER_AGENT§§",
752                   "Accept: §§ACCEPT§§",
753                   "Accept-Language: en-US,en;q=0.5",
754                   "Accept-Encoding: gzip, deflate, br, zstd",
755                   "Connection: keep-alive",
756                   "Referer: http://localhost:§§PORT§§/",
757                   "Upgrade-Insecure-Requests: 1",
758                   "Sec-Fetch-Dest: document",
759                   "Sec-Fetch-Mode: navigate",
760                   "Sec-Fetch-Site: same-origin",
761                   "Sec-Fetch-User: ?1",
762                   "Priority: u=0, i"},
763             FF_ESR = {"GET /2.html HTTP/1.1",
764                       "Host: localhost:§§PORT§§",
765                       "User-Agent: §§USER_AGENT§§",
766                       "Accept: §§ACCEPT§§",
767                       "Accept-Language: en-US,en;q=0.5",
768                       "Accept-Encoding: gzip, deflate, br, zstd",
769                       "Connection: keep-alive",
770                       "Referer: http://localhost:§§PORT§§/",
771                       "Upgrade-Insecure-Requests: 1",
772                       "Sec-Fetch-Dest: document",
773                       "Sec-Fetch-Mode: navigate",
774                       "Sec-Fetch-Site: same-origin",
775                       "Sec-Fetch-User: ?1",
776                       "Priority: u=0, i"})
777     @HtmlUnitNYI(CHROME = {"GET /2.html HTTP/1.1",
778                            "Host: localhost:§§PORT§§",
779                            "Connection: keep-alive",
780                            "sec-ch-ua: §§SEC_USER_AGENT§§",
781                            "sec-ch-ua-mobile: ?0",
782                            "sec-ch-ua-platform: \"Windows\"",
783                            "Upgrade-Insecure-Requests: 1",
784                            "User-Agent: §§USER_AGENT§§",
785                            "Accept: §§ACCEPT§§",
786                            "Sec-Fetch-Site: same-origin",
787                            "Sec-Fetch-Mode: navigate",
788                            "Sec-Fetch-User: ?1",
789                            "Sec-Fetch-Dest: document",
790                            "Referer: http://localhost:§§PORT§§/",
791                            "Accept-Encoding: gzip, deflate, br",
792                            "Accept-Language: en-US,en;q=0.9"},
793             EDGE = {"GET /2.html HTTP/1.1",
794                     "Host: localhost:§§PORT§§",
795                     "Connection: keep-alive",
796                     "sec-ch-ua: §§SEC_USER_AGENT§§",
797                     "sec-ch-ua-mobile: ?0",
798                     "sec-ch-ua-platform: \"Windows\"",
799                     "Upgrade-Insecure-Requests: 1",
800                     "User-Agent: §§USER_AGENT§§",
801                     "Accept: §§ACCEPT§§",
802                     "Sec-Fetch-Site: same-origin",
803                     "Sec-Fetch-Mode: navigate",
804                     "Sec-Fetch-User: ?1",
805                     "Sec-Fetch-Dest: document",
806                     "Referer: http://localhost:§§PORT§§/",
807                     "Accept-Encoding: gzip, deflate, br",
808                     "Accept-Language: en-US,en;q=0.9"},
809             FF = {"GET /2.html HTTP/1.1",
810                   "Host: localhost:§§PORT§§",
811                   "User-Agent: §§USER_AGENT§§",
812                   "Accept: §§ACCEPT§§",
813                   "Accept-Language: en-US,en;q=0.5",
814                   "Accept-Encoding: gzip, deflate, br",
815                   "Connection: keep-alive",
816                   "Referer: http://localhost:§§PORT§§/",
817                   "Upgrade-Insecure-Requests: 1",
818                   "Sec-Fetch-Dest: document",
819                   "Sec-Fetch-Mode: navigate",
820                   "Sec-Fetch-Site: same-origin",
821                   "Sec-Fetch-User: ?1",
822                   "Priority: u=0, i"},
823             FF_ESR = {"GET /2.html HTTP/1.1",
824                       "Host: localhost:§§PORT§§",
825                       "User-Agent: §§USER_AGENT§§",
826                       "Accept: §§ACCEPT§§",
827                       "Accept-Language: en-US,en;q=0.5",
828                       "Accept-Encoding: gzip, deflate, br",
829                       "Connection: keep-alive",
830                       "Referer: http://localhost:§§PORT§§/",
831                       "Upgrade-Insecure-Requests: 1",
832                       "Sec-Fetch-Dest: document",
833                       "Sec-Fetch-Mode: navigate",
834                       "Sec-Fetch-Site: same-origin",
835                       "Sec-Fetch-User: ?1",
836                       "Priority: u=0, i"})
837     public void anchor() throws Exception {
838         String html = DOCTYPE_HTML
839                 + "<html><body><a id='my' href='2.html'>Click me</a></body></html>";
840         html = "HTTP/1.1 200 OK\r\n"
841                 + "Content-Length: " + (html.length()) + "\r\n"
842                 + "Content-Type: text/html\r\n"
843                 + "\r\n"
844                 + html;
845         final String hi = "HTTP/1.1 200 OK\r\n"
846                 + "Content-Length: 2\r\n"
847                 + "Content-Type: text/plain\r\n"
848                 + "\r\n"
849                 + "Hi";
850 
851         shutDownAll();
852         try (PrimitiveWebServer primitiveWebServer = new PrimitiveWebServer(null, html, hi)) {
853             final WebDriver driver = getWebDriver();
854 
855             driver.get("http://localhost:" + primitiveWebServer.getPort());
856             driver.findElement(By.id("my")).click();
857 
858             final String[] expectedHeaders = getExpectedAlerts();
859             for (int i = 0; i < expectedHeaders.length; i++) {
860                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§PORT§§", "" + primitiveWebServer.getPort());
861                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§USER_AGENT§§",
862                         getBrowserVersion().getUserAgent());
863                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§SEC_USER_AGENT§§",
864                         getBrowserVersion().getSecClientHintUserAgentHeader());
865                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§ACCEPT§§",
866                         getBrowserVersion().getHtmlAcceptHeader());
867             }
868             final String request = primitiveWebServer.getRequests().get(1);
869             final String[] headers = request.split("\\r\\n");
870             assertEquals(Arrays.asList(expectedHeaders).toString(), Arrays.asList(headers).toString());
871         }
872     }
873 
874     /**
875      * Tests a location href change.
876      * @throws Exception if the test fails
877      */
878     @Test
879     @Alerts(CHROME = {"GET /foo HTTP/1.1",
880                       "Host: localhost:§§PORT§§",
881                       "Connection: keep-alive",
882                       "sec-ch-ua: §§SEC_USER_AGENT§§",
883                       "sec-ch-ua-mobile: ?0",
884                       "sec-ch-ua-platform: \"Windows\"",
885                       "Upgrade-Insecure-Requests: 1",
886                       "User-Agent: §§USER_AGENT§§",
887                       "Accept: §§ACCEPT§§",
888                       "Sec-Fetch-Site: same-origin",
889                       "Sec-Fetch-Mode: navigate",
890                       "Sec-Fetch-Dest: document",
891                       "Referer: http://localhost:§§PORT§§/",
892                       "Accept-Encoding: gzip, deflate, br, zstd",
893                       "Accept-Language: en-US,en;q=0.9"},
894             EDGE = {"GET /foo HTTP/1.1",
895                     "Host: localhost:§§PORT§§",
896                     "Connection: keep-alive",
897                     "sec-ch-ua: §§SEC_USER_AGENT§§",
898                     "sec-ch-ua-mobile: ?0",
899                     "sec-ch-ua-platform: \"Windows\"",
900                     "Upgrade-Insecure-Requests: 1",
901                     "User-Agent: §§USER_AGENT§§",
902                     "Accept: §§ACCEPT§§",
903                     "Sec-Fetch-Site: same-origin",
904                     "Sec-Fetch-Mode: navigate",
905                     "Sec-Fetch-Dest: document",
906                     "Referer: http://localhost:§§PORT§§/",
907                     "Accept-Encoding: gzip, deflate, br, zstd",
908                     "Accept-Language: en-US,en;q=0.9"},
909             FF = {"GET /foo HTTP/1.1",
910                   "Host: localhost:§§PORT§§",
911                   "User-Agent: §§USER_AGENT§§",
912                   "Accept: §§ACCEPT§§",
913                   "Accept-Language: en-US,en;q=0.5",
914                   "Accept-Encoding: gzip, deflate, br, zstd",
915                   "Connection: keep-alive",
916                   "Referer: http://localhost:§§PORT§§/",
917                   "Upgrade-Insecure-Requests: 1",
918                   "Sec-Fetch-Dest: document",
919                   "Sec-Fetch-Mode: navigate",
920                   "Sec-Fetch-Site: same-origin",
921                   "Priority: u=0, i"},
922             FF_ESR = {"GET /foo HTTP/1.1",
923                       "Host: localhost:§§PORT§§",
924                       "User-Agent: §§USER_AGENT§§",
925                       "Accept: §§ACCEPT§§",
926                       "Accept-Language: en-US,en;q=0.5",
927                       "Accept-Encoding: gzip, deflate, br, zstd",
928                       "Connection: keep-alive",
929                       "Referer: http://localhost:§§PORT§§/",
930                       "Upgrade-Insecure-Requests: 1",
931                       "Sec-Fetch-Dest: document",
932                       "Sec-Fetch-Mode: navigate",
933                       "Sec-Fetch-Site: same-origin",
934                       "Priority: u=0, i"})
935     @HtmlUnitNYI(CHROME = {"GET /foo HTTP/1.1",
936                            "Host: localhost:§§PORT§§",
937                            "Connection: keep-alive",
938                            "sec-ch-ua: §§SEC_USER_AGENT§§",
939                            "sec-ch-ua-mobile: ?0",
940                            "sec-ch-ua-platform: \"Windows\"",
941                            "Upgrade-Insecure-Requests: 1",
942                            "User-Agent: §§USER_AGENT§§",
943                            "Accept: §§ACCEPT§§",
944                            "Sec-Fetch-Site: same-origin",
945                            "Sec-Fetch-Mode: navigate",
946                            "Sec-Fetch-User: ?1",
947                            "Sec-Fetch-Dest: document",
948                            "Referer: http://localhost:§§PORT§§/",
949                            "Accept-Encoding: gzip, deflate, br",
950                            "Accept-Language: en-US,en;q=0.9"},
951             EDGE = {"GET /foo HTTP/1.1",
952                     "Host: localhost:§§PORT§§",
953                     "Connection: keep-alive",
954                     "sec-ch-ua: §§SEC_USER_AGENT§§",
955                     "sec-ch-ua-mobile: ?0",
956                     "sec-ch-ua-platform: \"Windows\"",
957                     "Upgrade-Insecure-Requests: 1",
958                     "User-Agent: §§USER_AGENT§§",
959                     "Accept: §§ACCEPT§§",
960                     "Sec-Fetch-Site: same-origin",
961                     "Sec-Fetch-Mode: navigate",
962                     "Sec-Fetch-User: ?1",
963                     "Sec-Fetch-Dest: document",
964                     "Referer: http://localhost:§§PORT§§/",
965                     "Accept-Encoding: gzip, deflate, br",
966                     "Accept-Language: en-US,en;q=0.9"},
967             FF = {"GET /foo HTTP/1.1",
968                   "Host: localhost:§§PORT§§",
969                   "User-Agent: §§USER_AGENT§§",
970                   "Accept: §§ACCEPT§§",
971                   "Accept-Language: en-US,en;q=0.5",
972                   "Accept-Encoding: gzip, deflate, br",
973                   "Connection: keep-alive",
974                   "Referer: http://localhost:§§PORT§§/",
975                   "Upgrade-Insecure-Requests: 1",
976                   "Sec-Fetch-Dest: document",
977                   "Sec-Fetch-Mode: navigate",
978                   "Sec-Fetch-Site: same-origin",
979                   "Sec-Fetch-User: ?1",
980                   "Priority: u=0, i"},
981             FF_ESR = {"GET /foo HTTP/1.1",
982                       "Host: localhost:§§PORT§§",
983                       "User-Agent: §§USER_AGENT§§",
984                       "Accept: §§ACCEPT§§",
985                       "Accept-Language: en-US,en;q=0.5",
986                       "Accept-Encoding: gzip, deflate, br",
987                       "Connection: keep-alive",
988                       "Referer: http://localhost:§§PORT§§/",
989                       "Upgrade-Insecure-Requests: 1",
990                       "Sec-Fetch-Dest: document",
991                       "Sec-Fetch-Mode: navigate",
992                       "Sec-Fetch-Site: same-origin",
993                       "Sec-Fetch-User: ?1",
994                       "Priority: u=0, i"})
995     public void locationSetHref() throws Exception {
996         final String url = "http://localhost:" + WebTestCase.PORT_PRIMITIVE_SERVER;
997         String html = DOCTYPE_HTML
998                 + "<html><body><script>location.href='" + url + "/foo';</script></body></html>";
999         html = "HTTP/1.1 200 OK\r\n"
1000                 + "Content-Length: " + (html.length()) + "\r\n"
1001                 + "Content-Type: text/html\r\n"
1002                 + "\r\n"
1003                 + html;
1004         final String hi = "HTTP/1.1 200 OK\r\n"
1005                 + "Content-Length: 2\r\n"
1006                 + "Content-Type: text/plain\r\n"
1007                 + "\r\n"
1008                 + "Hi";
1009 
1010         shutDownAll();
1011         try (PrimitiveWebServer primitiveWebServer = new PrimitiveWebServer(null, html, hi)) {
1012             final WebDriver driver = getWebDriver();
1013 
1014             driver.get("http://localhost:" + primitiveWebServer.getPort());
1015 
1016             final String[] expectedHeaders = getExpectedAlerts();
1017             for (int i = 0; i < expectedHeaders.length; i++) {
1018                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§PORT§§", "" + primitiveWebServer.getPort());
1019                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§USER_AGENT§§",
1020                         getBrowserVersion().getUserAgent());
1021                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§SEC_USER_AGENT§§",
1022                         getBrowserVersion().getSecClientHintUserAgentHeader());
1023                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§ACCEPT§§",
1024                         getBrowserVersion().getHtmlAcceptHeader());
1025             }
1026             final String request = primitiveWebServer.getRequests().get(1);
1027             final String[] headers = request.split("\\r\\n");
1028             assertEquals(Arrays.asList(expectedHeaders).toString(), Arrays.asList(headers).toString());
1029         }
1030     }
1031 
1032     /**
1033      * Tests a location href change.
1034      * @throws Exception if the test fails
1035      */
1036     @Test
1037     @Alerts(CHROME = {"GET /?newSearch HTTP/1.1",
1038                       "Host: localhost:§§PORT§§",
1039                       "Connection: keep-alive",
1040                       "sec-ch-ua: §§SEC_USER_AGENT§§",
1041                       "sec-ch-ua-mobile: ?0",
1042                       "sec-ch-ua-platform: \"Windows\"",
1043                       "Upgrade-Insecure-Requests: 1",
1044                       "User-Agent: §§USER_AGENT§§",
1045                       "Accept: §§ACCEPT§§",
1046                       "Sec-Fetch-Site: same-origin",
1047                       "Sec-Fetch-Mode: navigate",
1048                       "Sec-Fetch-Dest: document",
1049                       "Referer: http://localhost:§§PORT§§/",
1050                       "Accept-Encoding: gzip, deflate, br, zstd",
1051                       "Accept-Language: en-US,en;q=0.9"},
1052             EDGE = {"GET /?newSearch HTTP/1.1",
1053                     "Host: localhost:§§PORT§§",
1054                     "Connection: keep-alive",
1055                     "sec-ch-ua: §§SEC_USER_AGENT§§",
1056                     "sec-ch-ua-mobile: ?0",
1057                     "sec-ch-ua-platform: \"Windows\"",
1058                     "Upgrade-Insecure-Requests: 1",
1059                     "User-Agent: §§USER_AGENT§§",
1060                     "Accept: §§ACCEPT§§",
1061                     "Sec-Fetch-Site: same-origin",
1062                     "Sec-Fetch-Mode: navigate",
1063                     "Sec-Fetch-Dest: document",
1064                     "Referer: http://localhost:§§PORT§§/",
1065                     "Accept-Encoding: gzip, deflate, br, zstd",
1066                     "Accept-Language: en-US,en;q=0.9"},
1067             FF = {"GET /?newSearch HTTP/1.1",
1068                   "Host: localhost:§§PORT§§",
1069                   "User-Agent: §§USER_AGENT§§",
1070                   "Accept: §§ACCEPT§§",
1071                   "Accept-Language: en-US,en;q=0.5",
1072                   "Accept-Encoding: gzip, deflate, br, zstd",
1073                   "Connection: keep-alive",
1074                   "Referer: http://localhost:§§PORT§§/",
1075                   "Upgrade-Insecure-Requests: 1",
1076                   "Sec-Fetch-Dest: document",
1077                   "Sec-Fetch-Mode: navigate",
1078                   "Sec-Fetch-Site: same-origin",
1079                   "Priority: u=0, i"},
1080             FF_ESR = {"GET /?newSearch HTTP/1.1",
1081                       "Host: localhost:§§PORT§§",
1082                       "User-Agent: §§USER_AGENT§§",
1083                       "Accept: §§ACCEPT§§",
1084                       "Accept-Language: en-US,en;q=0.5",
1085                       "Accept-Encoding: gzip, deflate, br, zstd",
1086                       "Connection: keep-alive",
1087                       "Referer: http://localhost:§§PORT§§/",
1088                       "Upgrade-Insecure-Requests: 1",
1089                       "Sec-Fetch-Dest: document",
1090                       "Sec-Fetch-Mode: navigate",
1091                       "Sec-Fetch-Site: same-origin",
1092                       "Priority: u=0, i"})
1093     @HtmlUnitNYI(CHROME = {"GET /?newSearch HTTP/1.1",
1094                            "Host: localhost:§§PORT§§",
1095                            "Connection: keep-alive",
1096                            "sec-ch-ua: §§SEC_USER_AGENT§§",
1097                            "sec-ch-ua-mobile: ?0",
1098                            "sec-ch-ua-platform: \"Windows\"",
1099                            "Upgrade-Insecure-Requests: 1",
1100                            "User-Agent: §§USER_AGENT§§",
1101                            "Accept: §§ACCEPT§§",
1102                            "Sec-Fetch-Site: same-origin",
1103                            "Sec-Fetch-Mode: navigate",
1104                            "Sec-Fetch-User: ?1",
1105                            "Sec-Fetch-Dest: document",
1106                            "Referer: http://localhost:§§PORT§§/",
1107                            "Accept-Encoding: gzip, deflate, br",
1108                            "Accept-Language: en-US,en;q=0.9"},
1109             EDGE = {"GET /?newSearch HTTP/1.1",
1110                     "Host: localhost:§§PORT§§",
1111                     "Connection: keep-alive",
1112                     "sec-ch-ua: §§SEC_USER_AGENT§§",
1113                     "sec-ch-ua-mobile: ?0",
1114                     "sec-ch-ua-platform: \"Windows\"",
1115                     "Upgrade-Insecure-Requests: 1",
1116                     "User-Agent: §§USER_AGENT§§",
1117                     "Accept: §§ACCEPT§§",
1118                     "Sec-Fetch-Site: same-origin",
1119                     "Sec-Fetch-Mode: navigate",
1120                     "Sec-Fetch-User: ?1",
1121                     "Sec-Fetch-Dest: document",
1122                     "Referer: http://localhost:§§PORT§§/",
1123                     "Accept-Encoding: gzip, deflate, br",
1124                     "Accept-Language: en-US,en;q=0.9"},
1125             FF = {"GET /?newSearch HTTP/1.1",
1126                   "Host: localhost:§§PORT§§",
1127                   "User-Agent: §§USER_AGENT§§",
1128                   "Accept: §§ACCEPT§§",
1129                   "Accept-Language: en-US,en;q=0.5",
1130                   "Accept-Encoding: gzip, deflate, br",
1131                   "Connection: keep-alive",
1132                   "Referer: http://localhost:§§PORT§§/",
1133                   "Upgrade-Insecure-Requests: 1",
1134                   "Sec-Fetch-Dest: document",
1135                   "Sec-Fetch-Mode: navigate",
1136                   "Sec-Fetch-Site: same-origin",
1137                   "Sec-Fetch-User: ?1",
1138                   "Priority: u=0, i"},
1139             FF_ESR = {"GET /?newSearch HTTP/1.1",
1140                       "Host: localhost:§§PORT§§",
1141                       "User-Agent: §§USER_AGENT§§",
1142                       "Accept: §§ACCEPT§§",
1143                       "Accept-Language: en-US,en;q=0.5",
1144                       "Accept-Encoding: gzip, deflate, br",
1145                       "Connection: keep-alive",
1146                       "Referer: http://localhost:§§PORT§§/",
1147                       "Upgrade-Insecure-Requests: 1",
1148                       "Sec-Fetch-Dest: document",
1149                       "Sec-Fetch-Mode: navigate",
1150                       "Sec-Fetch-Site: same-origin",
1151                       "Sec-Fetch-User: ?1",
1152                       "Priority: u=0, i"})
1153     public void locationSetSearch() throws Exception {
1154         String html = DOCTYPE_HTML
1155                 + "<html><body><script>location.search='newSearch';</script></body></html>";
1156         html = "HTTP/1.1 200 OK\r\n"
1157                 + "Content-Length: " + (html.length()) + "\r\n"
1158                 + "Content-Type: text/html\r\n"
1159                 + "\r\n"
1160                 + html;
1161         final String hi = "HTTP/1.1 200 OK\r\n"
1162                 + "Content-Length: 2\r\n"
1163                 + "Content-Type: text/plain\r\n"
1164                 + "\r\n"
1165                 + "Hi";
1166 
1167         shutDownAll();
1168         try (PrimitiveWebServer primitiveWebServer = new PrimitiveWebServer(null, html, hi)) {
1169             final WebDriver driver = getWebDriver();
1170 
1171             driver.get("http://localhost:" + primitiveWebServer.getPort());
1172 
1173             final String[] expectedHeaders = getExpectedAlerts();
1174             for (int i = 0; i < expectedHeaders.length; i++) {
1175                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§PORT§§", "" + primitiveWebServer.getPort());
1176                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§USER_AGENT§§",
1177                         getBrowserVersion().getUserAgent());
1178                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§SEC_USER_AGENT§§",
1179                         getBrowserVersion().getSecClientHintUserAgentHeader());
1180                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§ACCEPT§§",
1181                         getBrowserVersion().getHtmlAcceptHeader());
1182             }
1183             final String request = primitiveWebServer.getRequests().get(1);
1184             final String[] headers = request.split("\\r\\n");
1185             assertEquals(Arrays.asList(expectedHeaders).toString(), Arrays.asList(headers).toString());
1186         }
1187     }
1188 
1189     /**
1190      * @throws Exception if the test fails
1191      */
1192     @Test
1193     @Alerts(CHROME = {"GET /script.js HTTP/1.1",
1194                       "Host: localhost:§§PORT§§",
1195                       "Connection: keep-alive",
1196                       "sec-ch-ua-platform: \"Windows\"",
1197                       "User-Agent: §§USER_AGENT§§",
1198                       "sec-ch-ua: §§SEC_USER_AGENT§§",
1199                       "sec-ch-ua-mobile: ?0",
1200                       "Accept: §§ACCEPT§§",
1201                       "Sec-Fetch-Site: same-origin",
1202                       "Sec-Fetch-Mode: no-cors",
1203                       "Sec-Fetch-Dest: script",
1204                       "Referer: http://localhost:§§PORT§§/",
1205                       "Accept-Encoding: gzip, deflate, br, zstd",
1206                       "Accept-Language: en-US,en;q=0.9"},
1207             EDGE = {"GET /script.js HTTP/1.1",
1208                     "Host: localhost:§§PORT§§",
1209                     "Connection: keep-alive",
1210                     "sec-ch-ua-platform: \"Windows\"",
1211                     "User-Agent: §§USER_AGENT§§",
1212                     "sec-ch-ua: §§SEC_USER_AGENT§§",
1213                     "sec-ch-ua-mobile: ?0",
1214                     "Accept: §§ACCEPT§§",
1215                     "Sec-Fetch-Site: same-origin",
1216                     "Sec-Fetch-Mode: no-cors",
1217                     "Sec-Fetch-Dest: script",
1218                     "Referer: http://localhost:§§PORT§§/",
1219                     "Accept-Encoding: gzip, deflate, br, zstd",
1220                     "Accept-Language: en-US,en;q=0.9"},
1221             FF = {"GET /script.js HTTP/1.1",
1222                   "Host: localhost:§§PORT§§",
1223                   "User-Agent: §§USER_AGENT§§",
1224                   "Accept: §§ACCEPT§§",
1225                   "Accept-Language: en-US,en;q=0.5",
1226                   "Accept-Encoding: gzip, deflate, br, zstd",
1227                   "Connection: keep-alive",
1228                   "Referer: http://localhost:§§PORT§§/",
1229                   "Sec-Fetch-Dest: script",
1230                   "Sec-Fetch-Mode: no-cors",
1231                   "Sec-Fetch-Site: same-origin",
1232                   "Priority: u=2"},
1233             FF_ESR = {"GET /script.js HTTP/1.1",
1234                       "Host: localhost:§§PORT§§",
1235                       "User-Agent: §§USER_AGENT§§",
1236                       "Accept: §§ACCEPT§§",
1237                       "Accept-Language: en-US,en;q=0.5",
1238                       "Accept-Encoding: gzip, deflate, br, zstd",
1239                       "Connection: keep-alive",
1240                       "Referer: http://localhost:§§PORT§§/",
1241                       "Sec-Fetch-Dest: script",
1242                       "Sec-Fetch-Mode: no-cors",
1243                       "Sec-Fetch-Site: same-origin",
1244                       "Priority: u=2"})
1245     @HtmlUnitNYI(CHROME = {"GET /script.js HTTP/1.1",
1246                            "Host: localhost:§§PORT§§",
1247                            "Connection: keep-alive",
1248                            "sec-ch-ua: §§SEC_USER_AGENT§§",
1249                            "sec-ch-ua-mobile: ?0",
1250                            "sec-ch-ua-platform: \"Windows\"",
1251                            "Upgrade-Insecure-Requests: 1", // wrong
1252                            "User-Agent: §§USER_AGENT§§",
1253                            "Accept: §§ACCEPT§§",
1254                            "Sec-Fetch-Site: same-origin",
1255                            "Sec-Fetch-Mode: no-cors",
1256                            "Sec-Fetch-User: ?1", // wrong
1257                            "Sec-Fetch-Dest: script",
1258                            "Referer: http://localhost:§§PORT§§/",
1259                            "Accept-Encoding: gzip, deflate, br",
1260                            "Accept-Language: en-US,en;q=0.9"},
1261             EDGE = {"GET /script.js HTTP/1.1",
1262                     "Host: localhost:§§PORT§§",
1263                     "Connection: keep-alive",
1264                     "sec-ch-ua: §§SEC_USER_AGENT§§",
1265                     "sec-ch-ua-mobile: ?0",
1266                     "sec-ch-ua-platform: \"Windows\"",
1267                     "Upgrade-Insecure-Requests: 1", // wrong
1268                     "User-Agent: §§USER_AGENT§§",
1269                     "Accept: §§ACCEPT§§",
1270                     "Sec-Fetch-Site: same-origin",
1271                     "Sec-Fetch-Mode: no-cors",
1272                     "Sec-Fetch-User: ?1", // wrong
1273                     "Sec-Fetch-Dest: script",
1274                     "Referer: http://localhost:§§PORT§§/",
1275                     "Accept-Encoding: gzip, deflate, br",
1276                     "Accept-Language: en-US,en;q=0.9"},
1277             FF = {"GET /script.js HTTP/1.1",
1278                   "Host: localhost:§§PORT§§",
1279                   "User-Agent: §§USER_AGENT§§",
1280                   "Accept: §§ACCEPT§§",
1281                   "Accept-Language: en-US,en;q=0.5",
1282                   "Accept-Encoding: gzip, deflate, br",
1283                   "Connection: keep-alive",
1284                   "Referer: http://localhost:§§PORT§§/",
1285                   "Upgrade-Insecure-Requests: 1", // wrong
1286                   "Sec-Fetch-Dest: script",
1287                   "Sec-Fetch-Mode: no-cors",
1288                   "Sec-Fetch-Site: same-origin",
1289                   "Sec-Fetch-User: ?1", /* wrong */
1290                   "Priority: u=0, i"},
1291             FF_ESR = {"GET /script.js HTTP/1.1",
1292                       "Host: localhost:§§PORT§§",
1293                       "User-Agent: §§USER_AGENT§§",
1294                       "Accept: §§ACCEPT§§",
1295                       "Accept-Language: en-US,en;q=0.5",
1296                       "Accept-Encoding: gzip, deflate, br",
1297                       "Connection: keep-alive",
1298                       "Referer: http://localhost:§§PORT§§/",
1299                       "Upgrade-Insecure-Requests: 1", // wrong
1300                       "Sec-Fetch-Dest: script",
1301                       "Sec-Fetch-Mode: no-cors",
1302                       "Sec-Fetch-Site: same-origin",
1303                       "Sec-Fetch-User: ?1", /* wrong */
1304                       "Priority: u=0, i"})
1305     public void loadJavascript() throws Exception {
1306         String html = DOCTYPE_HTML
1307                 + "<html><head> <script src=\"script.js\"></script> </head><body></body></html>";
1308         html = "HTTP/1.1 200 OK\r\n"
1309                 + "Content-Length: " + (html.length()) + "\r\n"
1310                 + "Content-Type: text/html\r\n"
1311                 + "\r\n"
1312                 + html;
1313         final String hi = "HTTP/1.1 200 OK\r\n"
1314                 + "Content-Length: 2\r\n"
1315                 + "Content-Type: text/javascript\r\n"
1316                 + "\r\n"
1317                 + ";;";
1318 
1319         shutDownAll();
1320         try (PrimitiveWebServer primitiveWebServer = new PrimitiveWebServer(null, html, hi)) {
1321             final WebDriver driver = getWebDriver();
1322 
1323             driver.get("http://localhost:" + primitiveWebServer.getPort());
1324 
1325             final String[] expectedHeaders = getExpectedAlerts();
1326             for (int i = 0; i < expectedHeaders.length; i++) {
1327                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§PORT§§", "" + primitiveWebServer.getPort());
1328                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§USER_AGENT§§",
1329                         getBrowserVersion().getUserAgent());
1330                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§SEC_USER_AGENT§§",
1331                         getBrowserVersion().getSecClientHintUserAgentHeader());
1332                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§ACCEPT§§",
1333                         getBrowserVersion().getScriptAcceptHeader());
1334             }
1335             final String request = primitiveWebServer.getRequests().get(1);
1336             final String[] headers = request.split("\\r\\n");
1337             assertEquals(Arrays.asList(expectedHeaders).toString(), Arrays.asList(headers).toString());
1338         }
1339     }
1340 
1341     /**
1342      * @throws Exception if the test fails
1343      */
1344     @Test
1345     @Alerts(CHROME = {"GET /script.js?x=%CE%D2%CA%C7%CE%D2%B5%C4%20?%20Abc HTTP/1.1",
1346                       "Host: localhost:§§PORT§§",
1347                       "Connection: keep-alive",
1348                       "sec-ch-ua-platform: \"Windows\"",
1349                       "User-Agent: §§USER_AGENT§§",
1350                       "sec-ch-ua: §§SEC_USER_AGENT§§",
1351                       "sec-ch-ua-mobile: ?0",
1352                       "Accept: §§ACCEPT§§",
1353                       "Sec-Fetch-Site: same-origin",
1354                       "Sec-Fetch-Mode: no-cors",
1355                       "Sec-Fetch-Dest: script",
1356                       "Referer: http://localhost:§§PORT§§/",
1357                       "Accept-Encoding: gzip, deflate, br, zstd",
1358                       "Accept-Language: en-US,en;q=0.9"},
1359             EDGE = {"GET /script.js?x=%CE%D2%CA%C7%CE%D2%B5%C4%20?%20Abc HTTP/1.1",
1360                     "Host: localhost:§§PORT§§",
1361                     "Connection: keep-alive",
1362                     "sec-ch-ua-platform: \"Windows\"",
1363                     "User-Agent: §§USER_AGENT§§",
1364                     "sec-ch-ua: §§SEC_USER_AGENT§§",
1365                     "sec-ch-ua-mobile: ?0",
1366                     "Accept: §§ACCEPT§§",
1367                     "Sec-Fetch-Site: same-origin",
1368                     "Sec-Fetch-Mode: no-cors",
1369                     "Sec-Fetch-Dest: script",
1370                     "Referer: http://localhost:§§PORT§§/",
1371                     "Accept-Encoding: gzip, deflate, br, zstd",
1372                     "Accept-Language: en-US,en;q=0.9"},
1373             FF = {"GET /script.js?x=%CE%D2%CA%C7%CE%D2%B5%C4%20?%20Abc HTTP/1.1",
1374                   "Host: localhost:§§PORT§§",
1375                   "User-Agent: §§USER_AGENT§§",
1376                   "Accept: §§ACCEPT§§",
1377                   "Accept-Language: en-US,en;q=0.5",
1378                   "Accept-Encoding: gzip, deflate, br, zstd",
1379                   "Connection: keep-alive",
1380                   "Referer: http://localhost:§§PORT§§/",
1381                   "Sec-Fetch-Dest: script",
1382                   "Sec-Fetch-Mode: no-cors",
1383                   "Sec-Fetch-Site: same-origin",
1384                   "Priority: u=2"},
1385             FF_ESR = {"GET /script.js?x=%CE%D2%CA%C7%CE%D2%B5%C4%20?%20Abc HTTP/1.1",
1386                       "Host: localhost:§§PORT§§",
1387                       "User-Agent: §§USER_AGENT§§",
1388                       "Accept: §§ACCEPT§§",
1389                       "Accept-Language: en-US,en;q=0.5",
1390                       "Accept-Encoding: gzip, deflate, br, zstd",
1391                       "Connection: keep-alive",
1392                       "Referer: http://localhost:§§PORT§§/",
1393                       "Sec-Fetch-Dest: script",
1394                       "Sec-Fetch-Mode: no-cors",
1395                       "Sec-Fetch-Site: same-origin",
1396                       "Priority: u=2"})
1397     @HtmlUnitNYI(CHROME = {"GET /script.js?x=%CE%D2%CA%C7%CE%D2%B5%C4%20?%20Abc HTTP/1.1",
1398                            "Host: localhost:§§PORT§§",
1399                            "Connection: keep-alive",
1400                            "sec-ch-ua: §§SEC_USER_AGENT§§",
1401                            "sec-ch-ua-mobile: ?0",
1402                            "sec-ch-ua-platform: \"Windows\"",
1403                            "Upgrade-Insecure-Requests: 1", // wrong
1404                            "User-Agent: §§USER_AGENT§§",
1405                            "Accept: §§ACCEPT§§",
1406                            "Sec-Fetch-Site: same-origin",
1407                            "Sec-Fetch-Mode: no-cors",
1408                            "Sec-Fetch-User: ?1", // wrong
1409                            "Sec-Fetch-Dest: script",
1410                            "Referer: http://localhost:§§PORT§§/",
1411                            "Accept-Encoding: gzip, deflate, br",
1412                            "Accept-Language: en-US,en;q=0.9"},
1413             EDGE = {"GET /script.js?x=%CE%D2%CA%C7%CE%D2%B5%C4%20?%20Abc HTTP/1.1",
1414                     "Host: localhost:§§PORT§§",
1415                     "Connection: keep-alive",
1416                     "sec-ch-ua: §§SEC_USER_AGENT§§",
1417                     "sec-ch-ua-mobile: ?0",
1418                     "sec-ch-ua-platform: \"Windows\"",
1419                     "Upgrade-Insecure-Requests: 1", // wrong
1420                     "User-Agent: §§USER_AGENT§§",
1421                     "Accept: §§ACCEPT§§",
1422                     "Sec-Fetch-Site: same-origin",
1423                     "Sec-Fetch-Mode: no-cors",
1424                     "Sec-Fetch-User: ?1", // wrong
1425                     "Sec-Fetch-Dest: script",
1426                     "Referer: http://localhost:§§PORT§§/",
1427                     "Accept-Encoding: gzip, deflate, br",
1428                     "Accept-Language: en-US,en;q=0.9"},
1429             FF = {"GET /script.js?x=%CE%D2%CA%C7%CE%D2%B5%C4%20?%20Abc HTTP/1.1",
1430                   "Host: localhost:§§PORT§§",
1431                   "User-Agent: §§USER_AGENT§§",
1432                   "Accept: §§ACCEPT§§",
1433                   "Accept-Language: en-US,en;q=0.5",
1434                   "Accept-Encoding: gzip, deflate, br",
1435                   "Connection: keep-alive",
1436                   "Referer: http://localhost:§§PORT§§/",
1437                   "Upgrade-Insecure-Requests: 1", // wrong
1438                   "Sec-Fetch-Dest: script",
1439                   "Sec-Fetch-Mode: no-cors",
1440                   "Sec-Fetch-Site: same-origin",
1441                   "Sec-Fetch-User: ?1", /* wrong */
1442                   "Priority: u=0, i"},
1443             FF_ESR = {"GET /script.js?x=%CE%D2%CA%C7%CE%D2%B5%C4%20?%20Abc HTTP/1.1",
1444                       "Host: localhost:§§PORT§§",
1445                       "User-Agent: §§USER_AGENT§§",
1446                       "Accept: §§ACCEPT§§",
1447                       "Accept-Language: en-US,en;q=0.5",
1448                       "Accept-Encoding: gzip, deflate, br",
1449                       "Connection: keep-alive",
1450                       "Referer: http://localhost:§§PORT§§/",
1451                       "Upgrade-Insecure-Requests: 1", // wrong
1452                       "Sec-Fetch-Dest: script",
1453                       "Sec-Fetch-Mode: no-cors",
1454                       "Sec-Fetch-Site: same-origin",
1455                       "Sec-Fetch-User: ?1", /* wrong */
1456                       "Priority: u=0, i"})
1457     // this fails on our CI but I have no idea why
1458     // seems like the request for downloading the script never reaches the
1459     // PrimitiveWebServer
1460     @NotYetImplemented(value = {}, os = OS.Linux)
1461     public void loadJavascriptCharset() throws Exception {
1462         String html = DOCTYPE_HTML
1463                 + "<html><head>"
1464                 + "<meta http-equiv='Content-Type' content='text/html; charset=GB2312'>"
1465                 + "<script src=\"script.js?x=\u6211\u662F\u6211\u7684 \u4eb8 Abc\"></script>"
1466                 + "</head><body></body></html>";
1467         html = "HTTP/1.1 200 OK\r\n"
1468                 + "Content-Length: " + (html.length()) + "\r\n"
1469                 + "Content-Type: text/html\r\n"
1470                 + "\r\n"
1471                 + html;
1472         final String hi = "HTTP/1.1 200 OK\r\n"
1473                 + "Content-Length: 0\r\n"
1474                 + "Content-Type: text/javascript\r\n"
1475                 + "\r\n"
1476                 + "";
1477 
1478         shutDownAll();
1479         try (PrimitiveWebServer primitiveWebServer = new PrimitiveWebServer(Charset.forName("GB2312"), html, hi)) {
1480             final WebDriver driver = getWebDriver();
1481 
1482             driver.get("http://localhost:" + primitiveWebServer.getPort());
1483 
1484             final String[] expectedHeaders = getExpectedAlerts();
1485             for (int i = 0; i < expectedHeaders.length; i++) {
1486                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§PORT§§", "" + primitiveWebServer.getPort());
1487                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§USER_AGENT§§",
1488                         getBrowserVersion().getUserAgent());
1489                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§SEC_USER_AGENT§§",
1490                         getBrowserVersion().getSecClientHintUserAgentHeader());
1491                 expectedHeaders[i] = expectedHeaders[i].replaceAll("§§ACCEPT§§",
1492                         getBrowserVersion().getScriptAcceptHeader());
1493             }
1494 
1495             // let's try some wait on our CI server
1496             final long endTime = System.currentTimeMillis() + Duration.ofSeconds(4).toMillis();
1497             while (primitiveWebServer.getRequests().size() < 1
1498                         && System.currentTimeMillis() < endTime) {
1499                 Thread.sleep(100);
1500             }
1501 
1502             if (primitiveWebServer.getRequests().size() < 2) {
1503                 Assert.fail("Still no request / request count:" + primitiveWebServer.getRequests().size());
1504             }
1505 
1506             final String request = primitiveWebServer.getRequests().get(1);
1507             final String[] headers = request.split("\\r\\n");
1508             assertEquals(Arrays.asList(expectedHeaders).toString(), Arrays.asList(headers).toString());
1509         }
1510     }
1511 }