1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.javascript.host.xml;
16
17 import static java.nio.charset.StandardCharsets.ISO_8859_1;
18 import static java.nio.charset.StandardCharsets.UTF_8;
19
20 import java.io.ByteArrayOutputStream;
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.OutputStream;
24 import java.io.Writer;
25 import java.net.URL;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.zip.GZIPOutputStream;
32
33 import javax.servlet.Servlet;
34 import javax.servlet.ServletException;
35 import javax.servlet.http.HttpServlet;
36 import javax.servlet.http.HttpServletRequest;
37 import javax.servlet.http.HttpServletResponse;
38
39 import org.apache.commons.io.FileUtils;
40 import org.apache.commons.io.IOUtils;
41 import org.htmlunit.HttpHeader;
42 import org.htmlunit.HttpMethod;
43 import org.htmlunit.WebDriverTestCase;
44 import org.htmlunit.WebRequest;
45 import org.htmlunit.javascript.host.xml.XMLHttpRequestTest.BasicAuthenticationServlet;
46 import org.htmlunit.junit.annotation.Alerts;
47 import org.htmlunit.junit.annotation.HtmlUnitNYI;
48 import org.htmlunit.util.MimeType;
49 import org.htmlunit.util.NameValuePair;
50 import org.junit.jupiter.api.Disabled;
51 import org.junit.jupiter.api.Test;
52 import org.openqa.selenium.By;
53 import org.openqa.selenium.WebDriver;
54
55
56
57
58
59
60
61
62
63
64
65
66 public class XMLHttpRequest2Test extends WebDriverTestCase {
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84 @Test
85 @Disabled
86 public void deadlock() throws Exception {
87 final String jsCallSynchXHR = "function callSynchXHR(url) {\n"
88 + " var xhr = new XMLHttpRequest();\n"
89 + " xhr.open('GET', url, false);\n"
90 + " xhr.send('');\n"
91 + "}\n";
92 final String jsCallASynchXHR = "function callASynchXHR(url) {\n"
93 + " var xhr = new XMLHttpRequest();\n"
94 + " var handler = function() {\n"
95 + " if (xhr.readyState == 4)\n"
96 + " log(xhr.responseText);\n"
97 + " }\n"
98 + " xhr.onreadystatechange = handler;\n"
99 + " xhr.open('GET', url, true);\n"
100 + " xhr.send('');\n"
101 + "}\n";
102
103 final String html = DOCTYPE_HTML
104 + "<html><head><script>\n"
105 + jsCallSynchXHR
106 + jsCallASynchXHR
107 + "function testMain() {\n"
108 + " // set state 1 and wait for state 2\n"
109 + " callSynchXHR('/setState1/setState3');\n"
110 + " // call function with XHR and handler in frame\n"
111 + " myFrame.contentWindow.callASynchXHR('/fooCalledFromFrameCalledFromMain');\n"
112 + "}\n"
113 + "</script></head>\n"
114 + "<body onload='testMain()'>\n"
115 + "<iframe id='myFrame' src='frame.html'></iframe>\n"
116 + "</body></html>";
117
118 final String frame = DOCTYPE_HTML
119 + "<html><head><script>\n"
120 + jsCallSynchXHR
121 + jsCallASynchXHR
122 + "function testFrame() {\n"
123 + " // set state 2\n"
124 + " callSynchXHR('/setState2');\n"
125 + " // call function with XHR and handler in parent\n"
126 + " parent.callASynchXHR('/fooCalledFromMainCalledFromFrame');\n"
127 + "}\n"
128 + "setTimeout(testFrame, 10);\n"
129 + "</script></head>\n"
130 + "<body></body></html>";
131
132 getMockWebConnection().setResponse(new URL(URL_FIRST, "frame.html"), frame);
133 getMockWebConnection().setDefaultResponse("");
134
135 loadPage2(html);
136 }
137
138
139
140
141 @Test
142 public void setRequestHeader() throws Exception {
143 final String html = DOCTYPE_HTML
144 + "<html><head><script>\n"
145 + " function test() {\n"
146 + " var xhr = new XMLHttpRequest();\n"
147 + " xhr.open('GET', 'second.html', false);\n"
148 + " xhr.setRequestHeader('Accept', 'text/javascript, application/javascript, */*');\n"
149 + " xhr.setRequestHeader('Accept-Language', 'ar-eg');\n"
150 + " xhr.send('');\n"
151 + " }\n"
152 + "</script></head><body onload='test()'></body></html>";
153
154 getMockWebConnection().setDefaultResponse("");
155 loadPage2(html);
156
157 final WebRequest lastRequest = getMockWebConnection().getLastWebRequest();
158 final Map<String, String> headers = lastRequest.getAdditionalHeaders();
159 assertEquals("text/javascript, application/javascript, */*", headers.get(HttpHeader.ACCEPT));
160 assertEquals("ar-eg", headers.get(HttpHeader.ACCEPT_LANGUAGE));
161 }
162
163
164
165
166
167
168 @Test
169 public void requestHeader_contentLength() throws Exception {
170 requestHeader_contentLength("1234");
171 requestHeader_contentLength("11");
172 requestHeader_contentLength(null);
173 }
174
175 private void requestHeader_contentLength(final String headerValue) throws Exception {
176 final String body = "hello world";
177 final String setHeader = headerValue == null ? ""
178 : "xhr.setRequestHeader('Content-length', 1234);\n";
179 final String html = DOCTYPE_HTML
180 + "<html><body><script>\n"
181 + "var xhr = new XMLHttpRequest();\n"
182 + "xhr.open('POST', 'second.html', false);\n"
183 + "var body = '" + body + "';\n"
184 + "xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');\n"
185 + setHeader
186 + "xhr.send(body);\n"
187 + "</script></body></html>";
188
189 getMockWebConnection().setDefaultResponse("");
190 loadPage2(html);
191
192 final WebRequest lastRequest = getMockWebConnection().getLastWebRequest();
193 final Map<String, String> headers = lastRequest.getAdditionalHeaders();
194 assertEquals("" + body.length(), headers.get(HttpHeader.CONTENT_LENGTH));
195 }
196
197
198
199
200 @Test
201 public void requestHeaderSendBlob() throws Exception {
202 final String html = DOCTYPE_HTML
203 + "<html><body><script>\n"
204 + "var xhr = new XMLHttpRequest();\n"
205 + "xhr.open('POST', 'second.html', false);\n"
206 + "xhr.setRequestHeader('Content-Type', 'text/plain');\n"
207 + "xhr.setRequestHeader('Content-length', 1234);\n"
208
209 + "var body = ['hello world'];\n"
210 + "var blob = new Blob(body);\n"
211 + "xhr.send(blob);\n"
212 + "</script></body></html>";
213
214 getMockWebConnection().setDefaultResponse("");
215 loadPage2(html);
216
217 final WebRequest lastRequest = getMockWebConnection().getLastWebRequest();
218 final Map<String, String> headers = lastRequest.getAdditionalHeaders();
219 assertEquals("11", headers.get(HttpHeader.CONTENT_LENGTH));
220 assertEquals("text/plain", headers.get(HttpHeader.CONTENT_TYPE));
221 }
222
223
224
225
226 @Test
227 public void requestHeaderSendFile() throws Exception {
228 final String html = DOCTYPE_HTML
229 + "<html><body>\n"
230
231 + "<input id='fileupload' type='file'/>"
232 + "<button id='testBtn' onclick='test()'>Tester</button>\n"
233
234 + "<script>\n"
235 + "function test() {\n"
236 + " var xhr = new XMLHttpRequest();\n"
237 + " xhr.open('POST', 'second.html', false);\n"
238 + " xhr.setRequestHeader('Content-Type', 'text/csv');\n"
239
240 + " var fileInput = document.getElementById('fileupload');"
241
242 + " xhr.send(fileInput.files[0]);\n"
243 + "}\n"
244 + "</script></body></html>";
245
246 final WebDriver driver = loadPage2(html);
247
248 final File tstFile = File.createTempFile("HtmlUnitUploadTest", ".txt");
249 try {
250 FileUtils.writeStringToFile(tstFile, "Hello HtmlUnit", ISO_8859_1);
251
252 final String path = tstFile.getCanonicalPath();
253 driver.findElement(By.id("fileupload")).sendKeys(path);
254
255 driver.findElement(By.id("testBtn")).click();
256
257 final WebRequest lastRequest = getMockWebConnection().getLastWebRequest();
258 final Map<String, String> headers = lastRequest.getAdditionalHeaders();
259 assertEquals("text/csv", headers.get(HttpHeader.CONTENT_TYPE));
260 }
261 finally {
262 FileUtils.deleteQuietly(tstFile);
263 }
264 }
265
266
267
268
269
270 @Test
271 @Alerts({"5", "pass", "pass", "pass", "pass"})
272 public void openThrowOnEmptyUrl() throws Exception {
273 final String html = DOCTYPE_HTML
274 + "<html><head>\n"
275 + "<script>\n"
276 + LOG_TITLE_FUNCTION
277 + "var xhr = new XMLHttpRequest();\n"
278 + "var values = [null, '', ' ', ' \\t '];\n"
279 + "for (var i = 0; i < values.length; i++) {\n"
280 + " try {\n"
281 + " xhr.open('GET', values[i], false);\n"
282 + " xhr.send('');\n"
283 + " log('pass');\n"
284 + " } catch(e) { logEx(e) }\n"
285 + "}\n"
286 + "</script>\n"
287 + "</head>\n"
288 + "<body></body>\n</html>";
289 getMockWebConnection().setDefaultResponse("Error: not found", 404, "Not Found", MimeType.TEXT_HTML);
290
291 final int expectedRequests = Integer.parseInt(getExpectedAlerts()[0]);
292 setExpectedAlerts(Arrays.copyOfRange(getExpectedAlerts(), 1, getExpectedAlerts().length));
293
294 loadPageVerifyTitle2(html);
295
296 assertEquals(expectedRequests, getMockWebConnection().getRequestCount());
297 }
298
299
300
301
302
303 @Test
304 @Alerts({"1", "bla", "someAttr", "someValue", "true", "foo", "2", "fi1"})
305 public void responseXML() throws Exception {
306 testResponseXML(MimeType.TEXT_XML);
307 testResponseXML(null);
308 }
309
310
311
312
313
314 @Test
315 @Alerts("null")
316 public void responseXML_badContentType() throws Exception {
317 final String html = DOCTYPE_HTML
318 + "<html><head>\n"
319 + "<script>\n"
320 + LOG_TITLE_FUNCTION
321 + "function test() {\n"
322 + " var xhr = new XMLHttpRequest();\n"
323 + " xhr.open('GET', 'foo.xml', false);\n"
324 + " xhr.send('');\n"
325 + " log(xhr.responseXML);\n"
326 + "}\n"
327 + "</script>\n"
328 + "</head>\n"
329 + "<body onload='test()'></body></html>";
330
331 final URL urlFoo = new URL(URL_FIRST, "foo.xml");
332 getMockWebConnection().setResponse(urlFoo, "<bla someAttr='someValue'><foo><fi id='fi1'/><fi/></foo></bla>\n",
333 MimeType.TEXT_PLAIN);
334 loadPageVerifyTitle2(html);
335 }
336
337 private void testResponseXML(final String contentType) throws Exception {
338 final String html = DOCTYPE_HTML
339 + "<html><head>\n"
340 + "<script>\n"
341 + LOG_TITLE_FUNCTION
342 + "function test() {\n"
343 + " var xhr = new XMLHttpRequest();\n"
344 + " xhr.open('GET', 'foo.xml', false);\n"
345 + " xhr.send('');\n"
346 + " var childNodes = xhr.responseXML.childNodes;\n"
347 + " log(childNodes.length);\n"
348 + " var rootNode = childNodes[0];\n"
349 + " log(rootNode.nodeName);\n"
350 + " log(rootNode.attributes[0].nodeName);\n"
351 + " log(rootNode.attributes[0].nodeValue);\n"
352 + " log(rootNode.attributes['someAttr'] == rootNode.attributes[0]);\n"
353 + " log(rootNode.firstChild.nodeName);\n"
354 + " log(rootNode.firstChild.childNodes.length);\n"
355 + " log(xhr.responseXML.getElementsByTagName('fi').item(0).attributes[0].nodeValue);\n"
356 + "}\n"
357 + "</script>\n"
358 + "</head>\n"
359 + "<body onload='test()'></body></html>";
360
361 final URL urlFoo = new URL(URL_FIRST, "foo.xml");
362 getMockWebConnection().setResponse(urlFoo, "<bla someAttr='someValue'><foo><fi id='fi1'/><fi/></foo></bla>\n",
363 contentType);
364 loadPageVerifyTitle2(html);
365 }
366
367
368
369
370
371 @Test
372 @Alerts("null")
373 public void responseXML_sendNotCalled() throws Exception {
374 final String html = DOCTYPE_HTML
375 + "<html><head>\n"
376 + "<script>\n"
377 + LOG_TITLE_FUNCTION
378 + "function test() {\n"
379 + " var xhr = new XMLHttpRequest();\n"
380 + " xhr.open('GET', 'foo.xml', false);\n"
381 + " log(xhr.responseXML);\n"
382 + "}\n"
383 + "</script>\n"
384 + "</head>\n"
385 + "<body onload='test()'></body></html>";
386
387 final URL urlFoo = new URL(URL_FIRST, "foo.xml");
388 getMockWebConnection().setResponse(urlFoo, "<bla someAttr='someValue'><foo><fi id='fi1'/><fi/></foo></bla>\n",
389 MimeType.TEXT_PLAIN);
390 loadPageVerifyTitle2(html);
391 }
392
393
394
395
396
397
398 @Test
399 @Alerts("ok")
400 public void sameOriginPolicy() throws Exception {
401 sameOriginPolicy(URL_THIRD.toString());
402 }
403
404
405
406
407 @Test
408 @Alerts("ok")
409 public void sameOriginPolicy_aboutBlank() throws Exception {
410 sameOriginPolicy("about:blank");
411 }
412
413 private void sameOriginPolicy(final String url) throws Exception {
414 final String html = DOCTYPE_HTML
415 + "<html><head>\n"
416 + "<script>\n"
417 + LOG_TITLE_FUNCTION
418 + "function test() {\n"
419 + " var xhr = new XMLHttpRequest();\n"
420 + " try {\n"
421 + " xhr.open('GET', '" + url + "', false);\n"
422 + " log('ok');\n"
423 + " } catch(e) { logEx(e); }\n"
424 + "}\n"
425 + "</script>\n"
426 + "</head>\n"
427 + "<body onload='test()'></body></html>";
428
429 getMockWebConnection().setResponse(URL_THIRD, "<bla/>", MimeType.TEXT_XML);
430 loadPageVerifyTitle2(html);
431 }
432
433
434
435
436 @Test
437 public void put() throws Exception {
438 final String html = DOCTYPE_HTML
439 + "<html><head><script>\n"
440 + " function test() {\n"
441 + " var xhr = new XMLHttpRequest();\n"
442 + " xhr.open('PUT', 'second.html', false);\n"
443 + " xhr.send('Something');\n"
444 + " }\n"
445 + "</script></head><body onload='test()'></body></html>";
446
447 getMockWebConnection().setDefaultResponse("");
448 loadPage2(html);
449
450 final String requestBody = getMockWebConnection().getLastWebRequest().getRequestBody();
451 assertEquals("Something", requestBody);
452 }
453
454
455
456
457
458
459
460 @Test
461 @Alerts("[object XMLDocument]")
462 public void iframeInResponse() throws Exception {
463 final String html = DOCTYPE_HTML
464 + "<html><head>\n"
465 + "<script>\n"
466 + LOG_TITLE_FUNCTION
467 + "var xhr = new XMLHttpRequest();\n"
468 + "xhr.open('GET', 'foo.xml', false);\n"
469 + "xhr.send('');\n"
470 + "log(xhr.responseXML);\n"
471 + "</script></head><body></body></html>";
472
473 final String xml = DOCTYPE_HTML
474 + "<html xmlns='http://www.w3.org/1999/xhtml'>\n"
475 + "<body><iframe></iframe></body></html>";
476 getMockWebConnection().setDefaultResponse(xml, MimeType.TEXT_XML);
477 loadPageVerifyTitle2(html);
478 }
479
480
481
482
483
484
485
486 @Test
487 @Alerts({"in timeout", "hello"})
488 @HtmlUnitNYI(CHROME = {"hello", "in timeout"},
489 EDGE = {"hello", "in timeout"},
490 FF = {"hello", "in timeout"},
491 FF_ESR = {"hello", "in timeout"})
492 public void xhrDownloadInBackground() throws Exception {
493 final String html = DOCTYPE_HTML
494 + "<html><head>\n"
495 + "<script>\n"
496 + LOG_TITLE_FUNCTION
497 + "var xhr = new XMLHttpRequest();\n"
498 + "var handler = function() {\n"
499 + " if (xhr.readyState == 4)\n"
500 + " log(xhr.responseText);\n"
501 + "}\n"
502 + "xhr.onreadystatechange = handler;\n"
503 + "xhr.open('GET', '/delay200/foo.txt', true);\n"
504 + "xhr.send('');\n"
505 + "setTimeout(function() { log('in timeout');}, 5);\n"
506 + "</script></head><body></body></html>";
507
508 getMockWebConnection().setDefaultResponse("hello", MimeType.TEXT_PLAIN);
509 loadPage2(html);
510 verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
511 }
512
513
514
515
516
517
518 @Test
519 @Alerts("hello in timeout")
520 public void xhrCallbackBeforeTimeout() throws Exception {
521 final String html = DOCTYPE_HTML
522 + "<html><head><script>\n"
523 + "function wait() {\n"
524 + " var xhr = new XMLHttpRequest();\n"
525 + " xhr.open('GET', '/delay200/foo.txt', false);\n"
526 + " xhr.send('');\n"
527 + "}\n"
528 + "function doTest() {\n"
529 + " setTimeout(function() { document.title += ' in timeout'; }, 5);\n"
530 + " wait();\n"
531 + " var xhr2 = new XMLHttpRequest();\n"
532 + " var handler = function() {\n"
533 + " if (xhr2.readyState == 4)\n"
534 + " document.title += xhr2.responseText;\n"
535 + " }\n"
536 + " xhr2.onreadystatechange = handler;\n"
537 + " xhr2.open('GET', '/foo.txt', true);\n"
538 + " xhr2.send('');\n"
539 + " wait();\n"
540 + "}\n"
541 + "setTimeout(doTest, 10);\n"
542 + "</script></head><body></body></html>";
543
544 getMockWebConnection().setDefaultResponse("hello", MimeType.TEXT_PLAIN);
545 final WebDriver driver = loadPage2(html);
546 assertTitle(driver, getExpectedAlerts()[0]);
547 }
548
549
550
551
552 @Test
553 @Alerts("a=b,0; cookie: null")
554 public void post() throws Exception {
555 final String html = DOCTYPE_HTML
556 + "<html><head>\n"
557 + "<script>\n"
558 + LOG_TITLE_FUNCTION
559 + "function test() {\n"
560 + " var xhr = new XMLHttpRequest();\n"
561 + " xhr.open('POST', '/test2?a=b', false);\n"
562 + " xhr.send('');\n"
563 + " log(xhr.responseText);\n"
564 + "}\n"
565 + "</script></head><body onload='test()'></body></html>";
566
567 final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
568 servlets.put("/test2", PostServlet2.class);
569
570 loadPage2(html, servlets);
571 verifyTitle2(getWebDriver(), getExpectedAlerts());
572 }
573
574
575
576
577 @Test
578 @Alerts("a=b,0; cookie: cookie=sweet")
579 public void post_cookies() throws Exception {
580 final String html = DOCTYPE_HTML
581 + "<html><head>\n"
582 + "<script>\n"
583 + LOG_TITLE_FUNCTION
584 + "function test() {\n"
585 + " var xhr = new XMLHttpRequest();\n"
586 + " xhr.open('POST', '/test2?a=b', false);\n"
587 + " xhr.send('');\n"
588 + " log(xhr.responseText);\n"
589 + "}\n"
590 + "</script></head><body onload='test()'></body></html>";
591
592 final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
593 servlets.put("/test2", PostServlet2.class);
594
595 List<NameValuePair> responseHeader = null;
596 responseHeader = new ArrayList<>();
597 responseHeader.add(new NameValuePair("Set-Cookie", "cookie=sweet"));
598
599 getMockWebConnection().setResponse(URL_FIRST, html,
600 200, "OK", "text/html;charset=ISO-8859-1", ISO_8859_1, responseHeader);
601 loadPage2(URL_FIRST, null);
602
603 loadPage2(html, servlets);
604 verifyTitle2(getWebDriver(), getExpectedAlerts());
605 }
606
607
608
609
610 public static class PostServlet2 extends HttpServlet {
611
612 @Override
613 protected void doPost(final HttpServletRequest req, final HttpServletResponse resp)
614 throws ServletException, IOException {
615 final Writer writer = resp.getWriter();
616
617 writer.write(req.getQueryString() + ',' + req.getContentLength());
618
619 final String cookie = req.getHeader(HttpHeader.COOKIE);
620 writer.write("; cookie: " + cookie);
621 }
622 }
623
624
625
626
627
628 @Test
629 @Alerts("4")
630 public void onreadystatechange_sync() throws Exception {
631 final String html = DOCTYPE_HTML
632 + "<html>\n"
633 + " <head>\n"
634 + " <script>\n"
635 + LOG_TITLE_FUNCTION
636 + " var xhr;\n"
637 + " function test() {\n"
638 + " xhr = new XMLHttpRequest();\n"
639 + " xhr.open('GET', '" + URL_SECOND + "', false);\n"
640 + " xhr.onreadystatechange = onStateChange;\n"
641 + " xhr.send('');\n"
642 + " }\n"
643 + " function onStateChange() {\n"
644 + " log(xhr.readyState);\n"
645 + " }\n"
646 + " </script>\n"
647 + " </head>\n"
648 + " <body onload='test()'>\n"
649 + " </body>\n"
650 + "</html>";
651
652 final String xml =
653 "<xml>\n"
654 + "<content>blah</content>\n"
655 + "<content>blah2</content>\n"
656 + "</xml>";
657
658 getMockWebConnection().setResponse(URL_SECOND, xml, MimeType.TEXT_XML);
659 loadPageVerifyTitle2(html);
660 }
661
662
663
664
665
666
667 @Test
668 @Alerts("[object Event]#[object XMLHttpRequest]")
669 public void onreadystatechangeSyncWithParam() throws Exception {
670 final String html = DOCTYPE_HTML
671 + "<html>\n"
672 + " <head>\n"
673 + " <script>\n"
674 + LOG_TITLE_FUNCTION
675 + " var xhr;\n"
676 + " function test() {\n"
677 + " xhr = new XMLHttpRequest();\n"
678 + " xhr.open('GET', '" + URL_SECOND + "', false);\n"
679 + " xhr.onreadystatechange = onStateChange;\n"
680 + " xhr.send('');\n"
681 + " }\n"
682 + " function onStateChange(e) {\n"
683 + " if (xhr.readyState == 4) {\n"
684 + " if(e) log(e + '#' + e.target);\n"
685 + " else log('no param');\n"
686 + " }\n"
687 + " }\n"
688 + " </script>\n"
689 + " </head>\n"
690 + " <body onload='test()'>\n"
691 + " </body>\n"
692 + "</html>";
693
694 final String xml =
695 "<xml>\n"
696 + "<content>blah</content>\n"
697 + "</xml>";
698
699 getMockWebConnection().setResponse(URL_SECOND, xml, MimeType.TEXT_XML);
700 loadPageVerifyTitle2(html);
701 }
702
703
704
705
706
707
708 @Test
709 @Alerts("[object Event]#[object XMLHttpRequest]")
710 public void onreadystatechangeAsyncWithParam() throws Exception {
711 final String html = DOCTYPE_HTML
712 + "<html>\n"
713 + " <head>\n"
714 + " <script>\n"
715 + LOG_TITLE_FUNCTION
716 + " var xhr;\n"
717 + " function test() {\n"
718 + " xhr = new XMLHttpRequest();\n"
719 + " xhr.open('GET', '" + URL_SECOND + "', true);\n"
720 + " xhr.onreadystatechange = onStateChange;\n"
721 + " xhr.send('');\n"
722 + " }\n"
723 + " function onStateChange(e) {\n"
724 + " if (xhr.readyState == 4) {\n"
725 + " if(e) log(e + '#' + e.target);\n"
726 + " else log('no param');\n"
727 + " }\n"
728 + " }\n"
729 + " </script>\n"
730 + " </head>\n"
731 + " <body onload='test()'>\n"
732 + " </body>\n"
733 + "</html>";
734
735 final String xml =
736 "<xml>\n"
737 + "<content>blah</content>\n"
738 + "</xml>";
739
740 getMockWebConnection().setResponse(URL_SECOND, xml, MimeType.TEXT_XML);
741 loadPage2(html);
742 verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
743 }
744
745
746
747
748
749
750 @Test
751 @Alerts({"ok", "4"})
752 public void sameOriginCorsSimple() throws Exception {
753 final String html = DOCTYPE_HTML
754 + "<html><head>\n"
755 + "<script>\n"
756 + LOG_TITLE_FUNCTION
757 + "function test() {\n"
758 + " var xhr = new XMLHttpRequest();\n"
759 + " try {\n"
760 + " xhr.open('GET', '" + URL_CROSS_ORIGIN + "', false);\n"
761 + " log('ok');\n"
762 + " xhr.send();\n"
763 + " log(xhr.readyState);\n"
764 + " } catch(e) { logEx(e); }\n"
765 + "}\n"
766 + "</script>\n"
767 + "</head>\n"
768 + "<body onload='test()'></body></html>";
769
770 final List<NameValuePair> responseHeaders = new ArrayList<>();
771 responseHeaders.add(new NameValuePair("access-control-allow-origin", "*"));
772 getMockWebConnection().setResponse(URL_CROSS_ORIGIN,
773 "<empty/>",
774 200,
775 "OK",
776 MimeType.TEXT_XML,
777 UTF_8, responseHeaders);
778 loadPageVerifyTitle2(html);
779 }
780
781
782
783
784
785 @Test
786 @Alerts({"ok", "4", "<null>"})
787 public void baseUrlAbsoluteRequest() throws Exception {
788 final String html = DOCTYPE_HTML
789 + "<html><head>\n"
790 + "<base href='" + URL_CROSS_ORIGIN_BASE + "'>\n"
791 + "<script>\n"
792 + LOG_TITLE_FUNCTION
793 + "function test() {\n"
794 + " var xhr = new XMLHttpRequest();\n"
795 + " try {\n"
796 + " xhr.open('GET', '" + URL_SECOND + "', false);\n"
797 + " log('ok');\n"
798 + " xhr.send();\n"
799 + " log(xhr.readyState);\n"
800 + " } catch(e) { logEx(e); }\n"
801 + "}\n"
802 + "</script>\n"
803 + "</head>\n"
804 + "<body onload='test()'></body></html>";
805
806 final List<NameValuePair> responseHeaders = new ArrayList<>();
807 responseHeaders.add(new NameValuePair("access-control-allow-origin", "*"));
808 getMockWebConnection().setResponse(URL_SECOND,
809 "<empty/>",
810 200,
811 "OK",
812 MimeType.TEXT_XML,
813 UTF_8, responseHeaders);
814
815 final WebDriver driver = loadPage2(html);
816 verifyTitle2(driver, Arrays.copyOfRange(getExpectedAlerts(), 0, 2));
817
818 final Map<String, String> lastAdditionalHeaders = getMockWebConnection().getLastAdditionalHeaders();
819 String origin = lastAdditionalHeaders.get(HttpHeader.ORIGIN);
820 if (origin == null) {
821 origin = "<null>";
822 }
823 assertEquals(getExpectedAlerts()[2], origin);
824 }
825
826
827
828
829
830 @Test
831 @Alerts({"ok", "4", "§§URL§§"})
832 public void baseUrlAbsoluteRequestOtherUrl() throws Exception {
833 final String html = DOCTYPE_HTML
834 + "<html><head>\n"
835 + "<base href='" + URL_CROSS_ORIGIN_BASE + "'>\n"
836 + "<script>\n"
837 + LOG_TITLE_FUNCTION
838 + "function test() {\n"
839 + " var xhr = new XMLHttpRequest();\n"
840 + " try {\n"
841 + " xhr.open('GET', '" + URL_CROSS_ORIGIN2 + "', false);\n"
842 + " log('ok');\n"
843 + " xhr.send();\n"
844 + " log(xhr.readyState);\n"
845 + " } catch(e) { logEx(e); }\n"
846 + "}\n"
847 + "</script>\n"
848 + "</head>\n"
849 + "<body onload='test()'></body></html>";
850
851 final List<NameValuePair> responseHeaders = new ArrayList<>();
852 responseHeaders.add(new NameValuePair("access-control-allow-origin", "*"));
853 getMockWebConnection().setResponse(URL_CROSS_ORIGIN2,
854 "<empty/>",
855 200,
856 "OK",
857 MimeType.TEXT_XML,
858 UTF_8, responseHeaders);
859
860 expandExpectedAlertsVariables("http://localhost:" + PORT);
861 final WebDriver driver = loadPage2(html);
862 verifyTitle2(driver, Arrays.copyOfRange(getExpectedAlerts(), 0, 2));
863
864 final Map<String, String> lastAdditionalHeaders = getMockWebConnection().getLastAdditionalHeaders();
865 String origin = lastAdditionalHeaders.get(HttpHeader.ORIGIN);
866 if (origin == null) {
867 origin = "<null>";
868 }
869 assertEquals(getExpectedAlerts()[2], origin);
870 }
871
872
873
874
875
876 @Test
877 @Alerts({"ok", "4", "§§URL§§"})
878 public void baseUrlRelativeRequest() throws Exception {
879 final String html = DOCTYPE_HTML
880 + "<html><head>\n"
881 + "<base href='" + URL_CROSS_ORIGIN_BASE + "'>\n"
882 + "<script>\n"
883 + LOG_TITLE_FUNCTION
884 + "function test() {\n"
885 + " var xhr = new XMLHttpRequest();\n"
886 + " try {\n"
887 + " xhr.open('GET', 'corsAllowAll', false);\n"
888 + " log('ok');\n"
889 + " xhr.send();\n"
890 + " log(xhr.readyState);\n"
891 + " } catch(e) { log('exception ' + e); }\n"
892 + "}\n"
893 + "</script>\n"
894 + "</head>\n"
895 + "<body onload='test()'></body></html>";
896
897 final List<NameValuePair> responseHeaders = new ArrayList<>();
898 responseHeaders.add(new NameValuePair("access-control-allow-origin", "*"));
899 getMockWebConnection().setResponse(new URL(URL_CROSS_ORIGIN_BASE, "/corsAllowAll"),
900 "<empty/>",
901 200,
902 "OK",
903 MimeType.TEXT_XML,
904 UTF_8, responseHeaders);
905
906 expandExpectedAlertsVariables("http://localhost:" + PORT);
907 final WebDriver driver = loadPage2(html);
908 verifyTitle2(driver, Arrays.copyOfRange(getExpectedAlerts(), 0, 2));
909
910 final Map<String, String> lastAdditionalHeaders = getMockWebConnection().getLastAdditionalHeaders();
911 String origin = lastAdditionalHeaders.get(HttpHeader.ORIGIN);
912 if (origin == null) {
913 origin = "<null>";
914 }
915 assertEquals(getExpectedAlerts()[2], origin);
916 }
917
918 @Override
919 protected boolean needThreeConnections() {
920 return true;
921 }
922
923
924
925
926
927 @Test
928 @Alerts("Basic:Zm9vOmJhcg==")
929 public void basicAuthenticationRequest() throws Exception {
930 final String html = DOCTYPE_HTML
931 + "<html>\n"
932 + " <head>\n"
933 + " <script>\n"
934 + LOG_TITLE_FUNCTION
935 + " var request;\n"
936 + " function testBasicAuth() {\n"
937 + " var request = new XMLHttpRequest();\n"
938 + " request.open('GET', '/protected/token', false, 'foo', 'bar');\n"
939 + " request.send();\n"
940 + " log(request.responseText);\n"
941 + " }\n"
942 + " </script>\n"
943 + " </head>\n"
944 + " <body onload='testBasicAuth()'>\n"
945 + " </body>\n"
946 + "</html>";
947
948 final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
949 servlets.put("/protected/token", BasicAuthenticationServlet.class);
950
951 loadPage2(html, servlets);
952 verifyTitle2(getWebDriver(), getExpectedAlerts());
953 }
954
955
956
957
958
959 @Test
960 @Alerts("<xml></xml>")
961 public void openNullUserIdNullPassword() throws Exception {
962 final String html =
963 "<html>\n"
964 + " <head>\n"
965 + " <script>\n"
966 + LOG_TITLE_FUNCTION
967 + " var request;\n"
968 + " function testBasicAuth() {\n"
969 + " var request = new XMLHttpRequest();\n"
970 + " request.open('GET', '" + URL_SECOND + "', false, null, null);\n"
971 + " request.send();\n"
972 + " log(request.responseText);\n"
973 + " }\n"
974 + " </script>\n"
975 + " </head>\n"
976 + " <body onload='testBasicAuth()'>\n"
977 + " </body>\n"
978 + "</html>";
979
980 getMockWebConnection().setResponse(URL_SECOND, "<xml></xml>", MimeType.TEXT_XML);
981
982 loadPageVerifyTitle2(html);
983 }
984
985
986
987
988 @Test
989 @Alerts("PATCH|some body data")
990 public void patch() throws Exception {
991 final String html = DOCTYPE_HTML
992 + "<html><head>\n"
993 + "<script>\n"
994 + LOG_TITLE_FUNCTION
995 + "function test() {\n"
996 + " var xhr = new XMLHttpRequest();\n"
997 + " xhr.open('PATCH', '/test2', false);\n"
998 + " xhr.send('some body data');\n"
999 + " log(xhr.responseText);\n"
1000 + "}\n"
1001 + "</script></head><body onload='test()'></body></html>";
1002
1003 final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
1004 servlets.put("/test2", PatchServlet2.class);
1005
1006 loadPage2(html, servlets);
1007 verifyTitle2(getWebDriver(), getExpectedAlerts());
1008 }
1009
1010
1011
1012
1013 public static class PatchServlet2 extends HttpServlet {
1014
1015 @Override
1016 protected void service(final HttpServletRequest req, final HttpServletResponse resp)
1017 throws ServletException, IOException {
1018 final Writer writer = resp.getWriter();
1019 writer.write(req.getMethod());
1020 writer.write('|');
1021 writer.write(IOUtils.toString(req.getReader()));
1022 }
1023 }
1024
1025
1026
1027
1028 public static class EncodedXmlServlet extends HttpServlet {
1029 private static final String RESPONSE = "<xml><content>blah</content></xml>";
1030
1031
1032
1033
1034 @Override
1035 protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
1036 final byte[] bytes = RESPONSE.getBytes(UTF_8);
1037 final ByteArrayOutputStream bos = new ByteArrayOutputStream();
1038 final GZIPOutputStream gout = new GZIPOutputStream(bos);
1039 gout.write(bytes);
1040 gout.finish();
1041
1042 final byte[] encoded = bos.toByteArray();
1043
1044 response.setContentType(MimeType.TEXT_XML);
1045 response.setCharacterEncoding(UTF_8.name());
1046 response.setStatus(200);
1047 response.setContentLength(encoded.length);
1048 response.setHeader("Content-Encoding", "gzip");
1049
1050 final OutputStream rout = response.getOutputStream();
1051 rout.write(encoded);
1052 }
1053 }
1054
1055
1056
1057
1058 @Test
1059 @Alerts({"<xml><content>blah</content></xml>", "text/xml;charset=utf-8", "gzip", "45"})
1060 public void encodedXml() throws Exception {
1061 final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
1062 servlets.put("/test", EncodedXmlServlet.class);
1063
1064 final String html = DOCTYPE_HTML
1065 + "<html>\n"
1066 + " <head>\n"
1067 + " <script>\n"
1068 + LOG_TITLE_FUNCTION
1069 + " var request;\n"
1070 + " function testBasicAuth() {\n"
1071 + " var request = new XMLHttpRequest();\n"
1072 + " request.open('GET', '/test', false, null, null);\n"
1073 + " request.send();\n"
1074 + " log(request.responseText);\n"
1075 + " log(request.getResponseHeader('content-type'));\n"
1076 + " log(request.getResponseHeader('content-encoding'));\n"
1077 + " log(request.getResponseHeader('content-length'));\n"
1078 + " }\n"
1079 + " </script>\n"
1080 + " </head>\n"
1081 + " <body onload='testBasicAuth()'>\n"
1082 + " </body>\n"
1083 + "</html>";
1084
1085 loadPage2(html, servlets);
1086 verifyTitle2(getWebDriver(), getExpectedAlerts());
1087 }
1088
1089
1090
1091
1092 @Test
1093 @Alerts({"", "", "content-type: text/xml;charset=iso-8859-1\\n"
1094 + "date XYZ GMT\\n"
1095 + "server: Jetty(XXX)\\n"
1096 + "transfer-encoding: chunked\\n"})
1097 @HtmlUnitNYI(CHROME = {"", "", "Date XYZ GMT\\nContent-Type: text/xml;charset=iso-8859-1\\n"
1098 + "Transfer-Encoding: chunked\\n"
1099 + "Server: Jetty(XXX)\\n"},
1100 EDGE = {"", "", "Date XYZ GMT\\nContent-Type: text/xml;charset=iso-8859-1\\n"
1101 + "Transfer-Encoding: chunked\\n"
1102 + "Server: Jetty(XXX)\\n"},
1103 FF = {"", "", "Date XYZ GMT\\nContent-Type: text/xml;charset=iso-8859-1\\n"
1104 + "Transfer-Encoding: chunked\\n"
1105 + "Server: Jetty(XXX)\\n"},
1106 FF_ESR = {"", "", "Date XYZ GMT\\nContent-Type: text/xml;charset=iso-8859-1\\n"
1107 + "Transfer-Encoding: chunked\\n"
1108 + "Server: Jetty(XXX)\\n"})
1109 public void getAllResponseHeaders() throws Exception {
1110 final String html = DOCTYPE_HTML
1111 + "<html>\n"
1112 + " <head>\n"
1113 + " <script>\n"
1114 + " function log(msg) {\n"
1115 + " msg = ('' + msg).replace(/\\r\\n/g, '\\\\n');"
1116 + " msg = msg.replace(/\\n/g, '\\\\n');"
1117 + " window.document.title += msg + '§';"
1118 + " }\n"
1119 + " var request;\n"
1120 + " function testBasicAuth() {\n"
1121 + " var request = new XMLHttpRequest();\n"
1122 + " try {\n"
1123 + " log(request.getAllResponseHeaders());\n"
1124 + " } catch(e) { log('exception-created'); }\n"
1125
1126 + " request.open('GET', '" + URL_SECOND + "', false, null, null);\n"
1127 + " try {\n"
1128 + " log(request.getAllResponseHeaders());\n"
1129 + " } catch(e) { log('exception-opened'); }\n"
1130
1131 + " request.send();\n"
1132 + " try {\n"
1133 + " log(request.getAllResponseHeaders().replace(/Jetty\\(.*\\)/, 'Jetty(XXX)')"
1134 + " .replace(/Date.*GMT/, 'Date XYZ GMT').replace(/date.*GMT/, 'date XYZ GMT'));\n"
1135 + " } catch(e) { log('exception-sent'); }\n"
1136 + " }\n"
1137 + " </script>\n"
1138 + " </head>\n"
1139 + " <body onload='testBasicAuth()'>\n"
1140 + " </body>\n"
1141 + "</html>";
1142
1143 getMockWebConnection().setResponse(URL_SECOND, "<xml></xml>", MimeType.TEXT_XML);
1144
1145 loadPageVerifyTitle2(html);
1146 }
1147
1148
1149
1150
1151 @Test
1152 @Alerts({"null", "null", "null", "null",
1153 "text/xml;charset=iso-8859-1", "text/xml;charset=iso-8859-1",
1154 "text/xml;charset=iso-8859-1", "null"})
1155 public void getResponseHeader() throws Exception {
1156 final String html = DOCTYPE_HTML
1157 + "<html>\n"
1158 + " <head>\n"
1159 + " <script>\n"
1160 + LOG_TITLE_FUNCTION
1161 + " var request;\n"
1162 + " function testBasicAuth() {\n"
1163 + " var request = new XMLHttpRequest();\n"
1164 + " try {\n"
1165 + " log(request.getResponseHeader('Content-Type'));\n"
1166 + " log(request.getResponseHeader('unknown'));\n"
1167 + " } catch(e) { log('exception-created'); }\n"
1168
1169 + " request.open('GET', '" + URL_SECOND + "', false, null, null);\n"
1170 + " try {\n"
1171 + " log(request.getResponseHeader('Content-Type'));\n"
1172 + " log(request.getResponseHeader('unknown'));\n"
1173 + " } catch(e) { log('exception-opened'); }\n"
1174
1175 + " request.send();\n"
1176 + " try {\n"
1177 + " log(request.getResponseHeader('Content-Type'));\n"
1178 + " log(request.getResponseHeader('content-type'));\n"
1179 + " log(request.getResponseHeader('coNTENt-type'));\n"
1180 + " log(request.getResponseHeader('unknown'));\n"
1181 + " } catch(e) { log('exception-sent'); }\n"
1182 + " }\n"
1183 + " </script>\n"
1184 + " </head>\n"
1185 + " <body onload='testBasicAuth()'>\n"
1186 + " </body>\n"
1187 + "</html>";
1188
1189 getMockWebConnection().setResponse(URL_SECOND, "<xml></xml>", MimeType.TEXT_XML);
1190
1191 loadPageVerifyTitle2(html);
1192 }
1193
1194
1195
1196
1197 @Test
1198 @Alerts("exception catched")
1199 public void createFromPrototypeAndDefineProperty() throws Exception {
1200 final String html = DOCTYPE_HTML
1201 + "<html><body>\n"
1202 + "<script>\n"
1203 + LOG_TITLE_FUNCTION
1204 + "var f = function() {};\n"
1205 + "f.prototype = Object.create(window.XMLHttpRequest.prototype);\n"
1206 + "try {\n"
1207 + " f.prototype['onerror'] = function() {};\n"
1208 + " log('no exception');\n"
1209 + "} catch(e) { log('exception catched'); }\n"
1210 + "</script></body></html>";
1211
1212 loadPageVerifyTitle2(html);
1213 }
1214
1215
1216
1217
1218 @Test
1219 @Alerts("exception for onerror")
1220 @HtmlUnitNYI(CHROME = "read onerror",
1221 EDGE = "read onerror",
1222 FF = "read onerror",
1223 FF_ESR = "read onerror")
1224 public void readPropertyFromPrototypeShouldThrow() throws Exception {
1225 final String html = DOCTYPE_HTML
1226 + "<html><body>\n"
1227 + "<script>\n"
1228 + LOG_TITLE_FUNCTION
1229 + "var p = 'onerror';\n"
1230 + "try {\n"
1231 + " var x = window.XMLHttpRequest.prototype[p];\n"
1232 + " log('read ' + p);\n"
1233 + "} catch(e) { log('exception for ' + p); }\n"
1234 + "</script></body></html>";
1235
1236 loadPageVerifyTitle2(html);
1237 }
1238
1239
1240
1241
1242 @Test
1243 @Alerts("4")
1244 public void onreadystatechange_eventListener() throws Exception {
1245 final String html = DOCTYPE_HTML
1246 + "<html>\n"
1247 + " <head>\n"
1248 + " <script>\n"
1249 + LOG_TITLE_FUNCTION
1250 + " var xhr;\n"
1251 + " function test() {\n"
1252 + " xhr = new XMLHttpRequest();\n"
1253 + " xhr.open('GET', '" + URL_SECOND + "', false);\n"
1254 + " xhr.addEventListener('readystatechange', onStateChange);\n"
1255 + " xhr.send('');\n"
1256 + " }\n"
1257 + " function onStateChange() {\n"
1258 + " log(xhr.readyState);\n"
1259 + " }\n"
1260 + " </script>\n"
1261 + " </head>\n"
1262 + " <body onload='test()'>\n"
1263 + " </body>\n"
1264 + "</html>";
1265
1266 final String xml =
1267 "<xml>\n"
1268 + "<content>blah</content>\n"
1269 + "<content>blah2</content>\n"
1270 + "</xml>";
1271
1272 getMockWebConnection().setResponse(URL_SECOND, xml, MimeType.TEXT_XML);
1273 loadPageVerifyTitle2(html);
1274 }
1275
1276
1277
1278
1279 @Test
1280 @Alerts("3")
1281 public void sendPostWithRedirect307() throws Exception {
1282 postRedirect(307, HttpMethod.POST, new URL(URL_FIRST, "/page2.html").toExternalForm(), "param=content");
1283 }
1284
1285
1286
1287
1288 @Test
1289 @Alerts("3")
1290 public void sendPostWithRedirect308() throws Exception {
1291 postRedirect(308, HttpMethod.POST, new URL(URL_FIRST, "/page2.html").toExternalForm(), "param=content");
1292 }
1293
1294 private void postRedirect(final int code, final HttpMethod httpMethod,
1295 final String redirectUrl, final String content) throws Exception {
1296 final String html = DOCTYPE_HTML
1297 + "<html><head><script>\n"
1298 + " function test() {\n"
1299 + " var xhr = new XMLHttpRequest();\n"
1300 + " try {\n"
1301 + " xhr.open('POST', 'redirect.html', false);\n"
1302 + " xhr.send('" + content + "');\n"
1303 + " } catch(e) { logEx(e); }\n"
1304 + " }\n"
1305 + "</script></head>\n"
1306 + "<body onload='test()'></body></html>";
1307
1308 final int reqCount = getMockWebConnection().getRequestCount();
1309
1310 final URL url = new URL(URL_FIRST, "page2.html");
1311 getMockWebConnection().setResponse(url, html);
1312
1313 final List<NameValuePair> headers = new ArrayList<>();
1314 headers.add(new NameValuePair("Location", redirectUrl));
1315 getMockWebConnection().setDefaultResponse("", code, "* Redirect", null, headers);
1316
1317 expandExpectedAlertsVariables(URL_FIRST);
1318 loadPage2(html);
1319
1320 assertEquals(reqCount + Integer.parseInt(getExpectedAlerts()[0]), getMockWebConnection().getRequestCount());
1321 assertEquals(httpMethod, getMockWebConnection().getLastWebRequest().getHttpMethod());
1322 assertNotNull(getMockWebConnection().getLastWebRequest().getRequestBody());
1323 assertFalse(getMockWebConnection().getLastWebRequest().getRequestBody().isEmpty());
1324 assertEquals(content, getMockWebConnection().getLastWebRequest().getRequestBody());
1325 }
1326 }