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