1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit;
16
17 import static java.nio.charset.StandardCharsets.UTF_8;
18 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
19
20 import java.net.URL;
21 import java.nio.charset.Charset;
22 import java.nio.charset.StandardCharsets;
23 import java.security.SecureRandom;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.zip.Deflater;
27
28 import org.apache.commons.io.IOUtils;
29 import org.htmlunit.html.HtmlInlineFrame;
30 import org.htmlunit.junit.annotation.Alerts;
31 import org.htmlunit.junit.annotation.HtmlUnitNYI;
32 import org.htmlunit.util.MimeType;
33 import org.htmlunit.util.NameValuePair;
34 import org.junit.jupiter.api.Test;
35 import org.openqa.selenium.By;
36 import org.openqa.selenium.WebDriver;
37 import org.openqa.selenium.WebElement;
38 import org.openqa.selenium.htmlunit.HtmlUnitDriver;
39
40
41
42
43
44
45
46
47 public class WebClient3Test extends WebDriverTestCase {
48
49 static final SecureRandom RANDOM = new SecureRandom();
50
51
52
53
54
55 @Test
56 public void bug3012067_npe() throws Exception {
57 final String html = DOCTYPE_HTML
58 + "<html><body>\n"
59 + "<form action='" + URL_FIRST + "#foo' method='post'></form>\n"
60 + "<script>\n"
61 + "function doWork() {\n"
62 + " var f = document.forms[0];\n"
63 + " f.submit();\n"
64 + " f.submit();\n"
65 + "}\n"
66 + "</script>\n"
67 + "<span id='clickMe' onclick='doWork()'>click</span>\n"
68 + "</body></html>";
69
70 final WebDriver driver = loadPage2(html);
71 driver.findElement(By.id("clickMe")).click();
72 }
73
74
75
76
77
78 @Test
79 public void readStreamTwice() throws Exception {
80 final String html = DOCTYPE_HTML
81 + "<html>\n"
82 + "<body>\n"
83 + "<iframe src='binaryFile.bin'></iframe>\n"
84 + "<iframe src='foo.html'></iframe>\n"
85 + "</body></html>";
86
87 final MockWebConnection mockConnection = getMockWebConnection();
88 final byte[] binaryContent = new byte[4818];
89 for (int i = 0; i < binaryContent.length; i++) {
90 binaryContent[i] = (byte) (RANDOM.nextInt(Byte.MAX_VALUE));
91 }
92 mockConnection.setDefaultResponse(binaryContent, 200, "OK", MimeType.APPLICATION_OCTET_STREAM);
93 final URL urlFoo = new URL(URL_FIRST, "foo.html");
94 mockConnection.setResponse(urlFoo, DOCTYPE_HTML + "<html></html>");
95
96 final WebDriver driver = loadPage2(html);
97 final WebElement iframe1 = driver.findElement(By.tagName("iframe"));
98 if (driver instanceof HtmlUnitDriver) {
99 final HtmlInlineFrame htmlUnitIFrame1 = (HtmlInlineFrame) toHtmlElement(iframe1);
100 final WebResponse iframeWebResponse = htmlUnitIFrame1.getEnclosedPage().getWebResponse();
101 byte[] receivedBytes = IOUtils.toByteArray(iframeWebResponse.getContentAsStream());
102 receivedBytes = IOUtils.toByteArray(iframeWebResponse.getContentAsStream());
103 assertArrayEquals(binaryContent, receivedBytes);
104 }
105 }
106
107
108
109
110
111
112 @Test
113 public void escapeRequestQuery() throws Exception {
114 getMockWebConnection().setDefaultResponse("");
115
116 loadPage2("", new URL(URL_FIRST, "foo?a=<b>i</b>"));
117 }
118
119
120
121
122
123
124
125
126
127 @Test
128 @Alerts("0")
129 @HtmlUnitNYI(CHROME = "1",
130 EDGE = "1",
131 FF = "1",
132 FF_ESR = "1")
133 public void escapeRequestQuery2a() throws Exception {
134 getMockWebConnection().setDefaultResponse("");
135
136 final URL url = new URL(URL_FIRST, "foo.png?cb=%%RANDOM_NUMBER%%");
137 loadPage2("", url);
138
139
140
141 assertEquals(Integer.parseInt(getExpectedAlerts()[0]), getMockWebConnection().getRequestCount());
142 }
143
144
145
146
147
148
149
150
151 @Test
152 public void escapeRequestQuery2b() throws Exception {
153 getMockWebConnection().setDefaultResponse("");
154
155 final URL url = new URL(URL_FIRST, "foo.png?cb=%%RANDOM_NUMBER%%");
156 loadPage2("", url);
157 }
158
159
160
161
162
163
164 @Test
165 public void clickReturnsWhenThePageHasBeenCompleteLoaded() throws Exception {
166 final String firstContent = DOCTYPE_HTML
167 + "<html><head>\n"
168 + "<script>window.setInterval(\'',1);</script></head>\n"
169 + "<body><a href='" + URL_SECOND + "'>to second</a></body></html>";
170 final String secondContent = DOCTYPE_HTML + "<html><body></body></html>";
171
172 final MockWebConnection webConnection = getMockWebConnection();
173 webConnection.setResponse(URL_SECOND, secondContent);
174
175 for (int i = 1; i < 100; i++) {
176 final WebDriver webDriver = loadPage2(firstContent);
177 webDriver.findElement(By.tagName("a")).click();
178 assertEquals("Run " + i, URL_SECOND.toExternalForm(), webDriver.getCurrentUrl());
179 }
180 }
181
182
183
184
185
186
187
188 @Test
189 @Alerts({"open", "first", "second"})
190 public void windowOpenedByAnchorTargetIsAttachedToJavascriptEventLoop() throws Exception {
191 final String firstContent = DOCTYPE_HTML
192 + "<html>\n"
193 + "<head>\n"
194 + "<script type='text/javascript'>\n"
195 + " function info(msg) {\n"
196 + " alert(msg);\n"
197 + " }\n"
198 + "</script>\n"
199 + "</head>\n"
200 + "<body>\n"
201 + " <a id='testAnchor' href='" + URL_SECOND + "' target='_blank' onclick='info(\"open\")'>to second</a>\n"
202 + "</body></html>";
203 final String secondContent = DOCTYPE_HTML
204 + "<html><head>\n"
205 + "<script type='text/javascript'>\n"
206 + " function first() {\n"
207 + " window.opener.info('first');\n"
208 + " window.setTimeout(second, 10);\n"
209 + " }\n"
210 + " function second() {\n"
211 + " window.opener.info('second');\n"
212 + " window.close();\n"
213 + " }\n"
214 + "</script>\n"
215 + "</head>\n"
216
217 + "<body onLoad='window.setTimeout(first, 5);'></body></html>";
218
219 getMockWebConnection().setResponse(URL_SECOND, secondContent);
220
221 final WebDriver driver = loadPage2(firstContent);
222 driver.findElement(By.id("testAnchor")).click();
223 if (useRealBrowser()) {
224 Thread.sleep(400);
225 }
226
227 verifyAlerts(driver, getExpectedAlerts());
228 }
229
230
231
232
233
234
235
236 @Test
237 @Alerts({"open", "first", "second"})
238 public void windowOpenedByFormTargetIsAttachedToJavascriptEventLoop() throws Exception {
239 final String firstContent = DOCTYPE_HTML
240 + "<html>\n"
241 + "<head>\n"
242 + "<script type='text/javascript'>\n"
243 + " function info(msg) {\n"
244 + " alert(msg);\n"
245 + " }\n"
246 + "</script>\n"
247 + "</head>\n"
248 + "<body>\n"
249 + "<form action='" + URL_SECOND + "' target='_blank'>\n"
250 + " <input id='testSubmit' type='submit' value='Submit' onclick='info(\"open\")'>\n"
251 + "</form>\n"
252 + "</body></html>";
253 final String secondContent = DOCTYPE_HTML
254 + "<html><head>\n"
255 + "<script type='text/javascript'>\n"
256 + " function first() {\n"
257 + " window.opener.info('first');\n"
258 + " window.setTimeout(second, 10);\n"
259 + " }\n"
260 + " function second() {\n"
261 + " window.opener.info('second');\n"
262 + " window.close();\n"
263 + " }\n"
264 + "</script>\n"
265 + "</head>\n"
266
267 + "<body onLoad='window.setTimeout(first, 5);'></body></html>";
268
269 getMockWebConnection().setResponse(URL_SECOND, secondContent);
270
271 final WebDriver driver = loadPage2(firstContent);
272 driver.findElement(By.id("testSubmit")).click();
273 if (useRealBrowser()) {
274 Thread.sleep(400);
275 }
276
277 verifyAlerts(driver, getExpectedAlerts());
278 }
279
280
281
282
283
284
285
286 @Test
287 @Alerts({"open", "first", "second"})
288 public void windowOpenedByJavascriptIsAttachedToJavascriptEventLoop() throws Exception {
289 final String firstContent = DOCTYPE_HTML
290 + "<html>\n"
291 + "<head>\n"
292 + "<script type='text/javascript'>\n"
293 + " function info(msg) {\n"
294 + " alert(msg);\n"
295 + " }\n"
296 + "</script>\n"
297 + "</head>\n"
298 + "<body>\n"
299 + " <a id='testAnchor' href='#'"
300 + " onclick='info(\"open\");window.open(\"" + URL_SECOND + "\", \"Popup\", \"\");'>open window</a>\n"
301 + "</body></html>";
302 final String secondContent = DOCTYPE_HTML
303 + "<html><head>\n"
304 + "<script type='text/javascript'>\n"
305 + " function first() {\n"
306 + " window.opener.info('first');\n"
307 + " window.setTimeout(second, 10);\n"
308 + " }\n"
309 + " function second() {\n"
310 + " window.opener.info('second');\n"
311 + " window.close();\n"
312 + " }\n"
313 + "</script>\n"
314 + "</head>\n"
315
316 + "<body onLoad='window.setTimeout(first, 5);'></body></html>";
317
318 getMockWebConnection().setResponse(URL_SECOND, secondContent);
319
320 final WebDriver driver = loadPage2(firstContent);
321 driver.findElement(By.id("testAnchor")).click();
322
323 verifyAlerts(driver, getExpectedAlerts());
324 }
325
326
327
328
329
330
331
332 @Test
333 @Alerts({"open", "first", "second"})
334 public void windowOpenedByJavascriptFilledByFormTargetIsAttachedToJavascriptEventLoop() throws Exception {
335 final String firstContent = DOCTYPE_HTML
336 + "<html>\n"
337 + "<head>\n"
338 + "<script type='text/javascript'>\n"
339 + " function info(msg) {\n"
340 + " alert(msg);\n"
341 + " }\n"
342 + "</script>\n"
343 + "</head>\n"
344 + "<body>\n"
345 + "<form action='" + URL_SECOND + "' name='myForm'>\n"
346 + " <input id='testSubmit' type='button' value='Submit' "
347 + " onclick='info(\"open\");"
348 + " window.open(\"" + URL_SECOND + "\", \"Popup\");"
349 + " document.myForm.target = \"Popup\";'"
350 + " >\n"
351 + "</form>\n"
352 + "</body></html>";
353 final String secondContent = DOCTYPE_HTML
354 + "<html><head>\n"
355 + "<script type='text/javascript'>\n"
356 + " function first() {\n"
357 + " window.opener.info('first');\n"
358 + " window.setTimeout(second, 10);\n"
359 + " }\n"
360 + " function second() {\n"
361 + " window.opener.info('second');\n"
362 + " window.close();\n"
363 + " }\n"
364 + "</script>\n"
365 + "</head>\n"
366
367 + "<body onLoad='window.setTimeout(first, 5);'></body></html>";
368
369 getMockWebConnection().setResponse(URL_SECOND, secondContent);
370
371 final WebDriver driver = loadPage2(firstContent);
372 driver.findElement(By.id("testSubmit")).click();
373
374 verifyAlerts(driver, getExpectedAlerts());
375 }
376
377
378
379
380 @Test
381 @Alerts({"Executed", "later"})
382 public void execJavascriptOnErrorPages() throws Exception {
383 final String errorHtml = DOCTYPE_HTML
384 + "<html>\n"
385 + "<head>\n"
386 + "</head>\n"
387 + "<body>\n"
388 + "<script type='text/javascript'>\n"
389 + LOG_TITLE_FUNCTION
390 + " log('Executed');\n"
391 + " setTimeout(\"log('later')\", 10);\n"
392 + "</script>\n"
393 + "</body></html>\n";
394
395 final MockWebConnection conn = getMockWebConnection();
396 conn.setResponse(URL_FIRST, errorHtml, 404, "Not Found", MimeType.TEXT_HTML, new ArrayList<>());
397
398 loadPage2(URL_FIRST, StandardCharsets.UTF_8);
399 verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
400 }
401
402
403
404
405
406
407 @Test
408 @Alerts("hello")
409 public void urlEncodingPercent20() throws Exception {
410 final String html = DOCTYPE_HTML
411 + "<html><body>\n"
412 + "<script src='a%20b.js'></script>\n"
413 + "</body></html>";
414
415 final MockWebConnection conn = getMockWebConnection();
416 conn.setResponse(new URL(URL_FIRST, "a%20b.js"), "alert('hello');", "text/javascript");
417
418 loadPageWithAlerts2(html);
419 }
420
421
422
423
424
425 @Test
426 @Alerts("modified")
427 public void deflateCompressionGZipCompatible() throws Exception {
428 doTestDeflateCompression(true);
429 }
430
431
432
433
434
435 @Test
436 @Alerts("modified")
437
438 public void deflateCompressionNonGZipCompatible() throws Exception {
439 doTestDeflateCompression(false);
440 }
441
442 private void doTestDeflateCompression(final boolean gzipCompatibleCompression) throws Exception {
443 final byte[] input = "document.title = 'modified';".getBytes(UTF_8);
444
445 final byte[] buffer = new byte[100];
446 final Deflater deflater = new Deflater(Deflater.DEFAULT_COMPRESSION, gzipCompatibleCompression);
447 deflater.setInput(input);
448 deflater.finish();
449
450 final int compressedDataLength = deflater.deflate(buffer);
451 final byte[] content = new byte[compressedDataLength];
452 System.arraycopy(buffer, 0, content, 0, compressedDataLength);
453
454 final List<NameValuePair> headers = new ArrayList<>();
455 headers.add(new NameValuePair("Content-Encoding", "deflate"));
456 headers.add(new NameValuePair(HttpHeader.CONTENT_LENGTH, String.valueOf(compressedDataLength)));
457
458 final MockWebConnection conn = getMockWebConnection();
459 conn.setResponse(URL_SECOND, content, 200, "OK", "text/javascript", headers);
460
461 final String html = DOCTYPE_HTML
462 + "<html><head>\n"
463 + "<title>Hello world</title>\n"
464 + "<script src='" + URL_SECOND + "'></script>\n"
465 + "</head><body><script>alert(document.title)</script></body></html>";
466 loadPageWithAlerts2(html);
467 }
468
469
470
471
472 @Test
473 @Alerts("executed")
474 public void javascriptContentDetectorWithoutContentType() throws Exception {
475 final MockWebConnection conn = getMockWebConnection();
476 conn.setDefaultResponse("<script>alert('executed')</script>", 200, "OK", null);
477 loadPageWithAlerts2(URL_FIRST);
478 }
479
480
481
482
483 @Test
484 @Alerts("executed")
485 public void javascriptContentDetectorWithoutContentType500() throws Exception {
486 final MockWebConnection conn = getMockWebConnection();
487 conn.setDefaultResponse("<script>alert('executed')</script>", 500, "OK", null);
488 loadPageWithAlerts2(URL_FIRST);
489 }
490
491
492
493
494 @Test
495 @Alerts("executed")
496 public void javascriptContentDetectorWithoutContentTypeWhitespace() throws Exception {
497 final MockWebConnection conn = getMockWebConnection();
498 conn.setDefaultResponse(" \t \r\n \n <script>alert('executed')</script>", 200, "OK", null);
499 loadPageWithAlerts2(URL_FIRST);
500 }
501
502
503
504
505 @Test
506 public void javascriptContentDetectorWithoutContentTypeTextBefore() throws Exception {
507 final MockWebConnection conn = getMockWebConnection();
508 conn.setDefaultResponse("Attention<script>alert('executed')</script>", 200, "OK", null);
509 loadPageWithAlerts2(URL_FIRST);
510 }
511
512
513
514
515 @Test
516 @Alerts("executed")
517 public void javascriptContentDetectorWithoutContentUppercase() throws Exception {
518 final MockWebConnection conn = getMockWebConnection();
519 conn.setDefaultResponse("<SCRIPT>alert('executed')</SCRIPT>", 200, "OK", null);
520 loadPageWithAlerts2(URL_FIRST);
521 }
522
523
524
525
526 @Test
527 @Alerts("executed")
528 public void javascriptContentDetectorWithoutContentMixedCase() throws Exception {
529 final MockWebConnection conn = getMockWebConnection();
530 conn.setDefaultResponse("<scRIPt>alert('executed')</scRIPt>", 200, "OK", null);
531 loadPageWithAlerts2(URL_FIRST);
532 }
533
534
535
536
537 @Test
538 public void javascriptContentDetectorContentTypeTextPlain() throws Exception {
539 final MockWebConnection conn = getMockWebConnection();
540 conn.setDefaultResponse("<script>alert('executed')</script>", 200, "OK", MimeType.TEXT_PLAIN);
541 loadPageWithAlerts2(URL_FIRST);
542 }
543
544
545
546
547 @Test
548 @Alerts({})
549 @HtmlUnitNYI(CHROME = "executed",
550 EDGE = "executed",
551 FF = "executed",
552 FF_ESR = "executed")
553 public void javascriptContentDetectorContentTypeApplicationJavascript() throws Exception {
554 final MockWebConnection conn = getMockWebConnection();
555 conn.setDefaultResponse("<script>alert('executed')</script>", 200, "OK", MimeType.TEXT_JAVASCRIPT);
556 loadPageWithAlerts2(URL_FIRST);
557 }
558
559
560
561
562 @Test
563 public void encodingCharsetGB2312() throws Exception {
564 encodingCharset("\u6211\u662F\u6211\u7684 Abc", "GB2312", "GB2312");
565 }
566
567
568
569
570 @Test
571 public void encodingCharsetGB2312GBKChar() throws Exception {
572 encodingCharset("\u4eb8 Abc", "GB2312", "GBK");
573 }
574
575
576
577
578 @Test
579 public void encodingCharsetGBK() throws Exception {
580 encodingCharset("\u6211\u662F\u6211\u7684 \u4eb8 Abc", "GBK", "GBK");
581 }
582
583 private void encodingCharset(final String title,
584 final String metaCharset, final String responseCharset) throws Exception {
585 final String html = DOCTYPE_HTML
586 + "<html><head>\n"
587 + "<meta http-equiv='Content-Type' content='text/html; charset=" + metaCharset + "'>\n"
588 + "<title>" + title + "</title>\n"
589 + "</head>\n"
590 + "<body>\n"
591 + "</body></html>";
592
593 final String firstResponse = "HTTP/1.1 200 OK\r\n"
594 + "Content-Length: " + html.length() + "\r\n"
595 + "Content-Type: text/html\r\n"
596 + "Connection: close\r\n"
597 + "\r\n" + html;
598
599 shutDownAll();
600 try (PrimitiveWebServer primitiveWebServer =
601 new PrimitiveWebServer(Charset.forName(responseCharset), firstResponse, firstResponse)) {
602 final String url = "http://localhost:" + primitiveWebServer.getPort() + "/";
603 final WebDriver driver = getWebDriver();
604
605 driver.get(url);
606 assertEquals(title, driver.getTitle());
607 }
608 }
609
610
611
612
613 @Test
614 @Alerts(DEFAULT = {"en-US", "en-US"},
615 FF = {"en-US", "en-US,en"},
616 FF_ESR = {"en-US", "en-US,en"})
617 @HtmlUnitNYI(CHROME = {"en-US", "en-US,en"},
618 EDGE = {"en-US", "en-US,en"})
619 public void language() throws Exception {
620 final String html = DOCTYPE_HTML
621 + "<html><head><script>\n"
622 + LOG_TITLE_FUNCTION
623 + "function test() {\n"
624 + " log(navigator.language);\n"
625 + " log(navigator.languages);\n"
626 + "}\n"
627 + "</script></head><body onload='test()'>\n"
628 + "</body></html>";
629
630 shutDownAll();
631 try {
632 loadPageVerifyTitle2(html);
633 }
634 finally {
635 shutDownAll();
636 }
637 }
638
639
640
641
642 @Test
643 @Alerts(DEFAULT = {"de-DE", "de-DE"},
644 FF = {"de-DE", "de-DE,de"},
645 FF_ESR = {"de-DE", "de-DE,de"})
646 @HtmlUnitNYI(CHROME = {"de-DE", "de-DE,de"},
647 EDGE = {"de-DE", "de-DE,de"})
648 public void languageDE() throws Exception {
649 final String html = DOCTYPE_HTML
650 + "<html><head><script>\n"
651 + LOG_TITLE_FUNCTION
652 + "function test() {\n"
653 + " log(navigator.language);\n"
654 + " log(navigator.languages);\n"
655 + "}\n"
656 + "</script></head><body onload='test()'>\n"
657 + "</body></html>";
658
659 shutDownAll();
660 try {
661 final BrowserVersion.BrowserVersionBuilder builder
662 = new BrowserVersion.BrowserVersionBuilder(getBrowserVersion());
663 builder.setBrowserLanguage("de-DE");
664 builder.setAcceptLanguageHeader("de-DE,de");
665 setBrowserVersion(builder.build());
666
667 loadPageVerifyTitle2(html);
668 }
669 finally {
670 shutDownAll();
671 }
672 }
673 }