1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.attachment;
16
17 import java.io.ByteArrayInputStream;
18 import java.io.InputStream;
19 import java.util.ArrayList;
20 import java.util.List;
21
22 import org.htmlunit.HttpWebConnectionTest;
23 import org.htmlunit.MockWebConnection;
24 import org.htmlunit.Page;
25 import org.htmlunit.SimpleWebTestCase;
26 import org.htmlunit.TextPage;
27 import org.htmlunit.WebClient;
28 import org.htmlunit.WebResponse;
29 import org.htmlunit.html.HtmlAnchor;
30 import org.htmlunit.html.HtmlElement;
31 import org.htmlunit.html.HtmlPage;
32 import org.htmlunit.util.MimeType;
33 import org.htmlunit.util.NameValuePair;
34 import org.junit.jupiter.api.Test;
35
36
37
38
39
40
41
42
43
44
45 public class AttachmentTest extends SimpleWebTestCase {
46
47
48
49
50
51 @Test
52 public void basic() throws Exception {
53 final String content1 = DOCTYPE_HTML
54 + "<html><body>\n"
55 + "<form method='POST' name='form' action='" + URL_SECOND + "'>\n"
56 + "<input type='submit' value='ok'>\n"
57 + "</form>\n"
58 + "<a href='#' onclick='document.form.submit()'>click me</a>\n"
59 + "</body></html>";
60 final String content2 = "download file contents";
61
62 final WebClient client = getWebClient();
63 final List<Attachment> attachments = new ArrayList<>();
64 client.setAttachmentHandler(new CollectingAttachmentHandler(attachments));
65
66 final List<NameValuePair> headers = new ArrayList<>();
67 headers.add(new NameValuePair("Content-Disposition", "attachment"));
68
69 final MockWebConnection conn = new MockWebConnection();
70 conn.setResponse(URL_FIRST, content1);
71 conn.setResponse(URL_SECOND, content2, 200, "OK", MimeType.TEXT_HTML, headers);
72 client.setWebConnection(conn);
73 assertTrue(attachments.isEmpty());
74
75 final HtmlPage result = client.getPage(URL_FIRST);
76 final HtmlAnchor anchor = result.getAnchors().get(0);
77 final Page clickResult = anchor.click();
78 assertEquals(result, clickResult);
79 assertEquals(1, attachments.size());
80 assertTrue(HtmlPage.class.isInstance(attachments.get(0).getPage()));
81
82 assertEquals(2, client.getWebWindows().size());
83
84 final Attachment attachment = attachments.get(0);
85 final Page attachedPage = attachment.getPage();
86 final WebResponse attachmentResponse = attachedPage.getWebResponse();
87 final InputStream attachmentStream = attachmentResponse.getContentAsStream();
88 HttpWebConnectionTest.assertEquals(new ByteArrayInputStream(content2.getBytes()), attachmentStream);
89 assertEquals(MimeType.TEXT_HTML, attachmentResponse.getContentType());
90 assertEquals(200, attachmentResponse.getStatusCode());
91 assertEquals(URL_SECOND, attachmentResponse.getWebRequest().getUrl());
92 }
93
94
95
96
97
98 @Test
99 public void contentDispositionCaseInsensitive() throws Exception {
100 final String content1 = DOCTYPE_HTML
101 + "<html><body>\n"
102 + "<form method='POST' name='form' action='" + URL_SECOND + "'>\n"
103 + "<input type='submit' value='ok'>\n"
104 + "</form>\n"
105 + "<a href='#' onclick='document.form.submit()'>click me</a>\n"
106 + "</body></html>";
107 final String content2 = "download file contents";
108
109 final WebClient client = getWebClient();
110 final List<Attachment> attachments = new ArrayList<>();
111 client.setAttachmentHandler(new CollectingAttachmentHandler(attachments));
112
113 final List<NameValuePair> headers = new ArrayList<>();
114 headers.add(new NameValuePair("Content-Disposition", "AttachMent"));
115
116 final MockWebConnection conn = new MockWebConnection();
117 conn.setResponse(URL_FIRST, content1);
118 conn.setResponse(URL_SECOND, content2, 200, "OK", MimeType.TEXT_HTML, headers);
119 client.setWebConnection(conn);
120 assertTrue(attachments.isEmpty());
121
122 final HtmlPage result = client.getPage(URL_FIRST);
123 final HtmlAnchor anchor = result.getAnchors().get(0);
124 final Page clickResult = anchor.click();
125 assertEquals(result, clickResult);
126 assertEquals(1, attachments.size());
127 }
128
129
130
131
132
133 @Test
134 public void filename() throws Exception {
135 final String content = DOCTYPE_HTML + "<html>But is it really?</html>";
136
137 final WebClient client = getWebClient();
138 final MockWebConnection conn = new MockWebConnection();
139 client.setWebConnection(conn);
140 final List<Attachment> attachments = new ArrayList<>();
141 client.setAttachmentHandler(new CollectingAttachmentHandler(attachments));
142
143 final List<NameValuePair> headers1 = new ArrayList<>();
144 headers1.add(new NameValuePair("Content-Disposition", "attachment;filename=\"hello.html\""));
145 conn.setResponse(URL_FIRST, content, 200, "OK", MimeType.TEXT_HTML, headers1);
146 client.getPage(URL_FIRST);
147 final Attachment result = attachments.get(0);
148 assertEquals(result.getSuggestedFilename(), "hello.html");
149 attachments.clear();
150
151 final List<NameValuePair> headers2 = new ArrayList<>();
152 headers2.add(new NameValuePair("Content-Disposition", "attachment; filename=hello2.html; something=else"));
153 conn.setResponse(URL_SECOND, content, 200, "OK", MimeType.TEXT_PLAIN, headers2);
154 client.getPage(URL_SECOND);
155 final Attachment result2 = attachments.get(0);
156 assertEquals(result2.getSuggestedFilename(), "hello2.html");
157 assertEquals(content, ((TextPage) result2.getPage()).getContent());
158 attachments.clear();
159
160 final List<NameValuePair> headers3 = new ArrayList<>();
161 headers3.add(new NameValuePair("Content-Disposition", "attachment; filename="));
162 conn.setResponse(URL_SECOND, content, 200, "OK", MimeType.TEXT_PLAIN, headers3);
163 client.getPage(URL_SECOND);
164 final Attachment result3 = attachments.get(0);
165 assertNull(result3.getSuggestedFilename());
166 assertEquals(content, ((TextPage) result3.getPage()).getContent());
167 attachments.clear();
168
169 final List<NameValuePair> headers4 = new ArrayList<>();
170 headers4.add(new NameValuePair("Content-Disposition", "attachment"));
171 final byte[] contentb = new byte[] {(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE};
172 conn.setResponse(URL_THIRD, contentb, 200, "OK", "application/x-rubbish", headers4);
173 client.getPage(URL_THIRD);
174 final Attachment result4 = attachments.get(0);
175 final InputStream result4Stream = result4.getPage().getWebResponse().getContentAsStream();
176 assertNull(result4.getSuggestedFilename());
177 assertEquals(result4.getPage().getWebResponse().getContentType(), "application/x-rubbish");
178 HttpWebConnectionTest.assertEquals(new ByteArrayInputStream(contentb), result4Stream);
179 attachments.clear();
180 }
181
182
183
184
185 @Test
186 public void filenameFromAnchor() throws Exception {
187 final WebClient client = getWebClient();
188 final MockWebConnection conn = new MockWebConnection();
189 client.setWebConnection(conn);
190 final List<Attachment> attachments = new ArrayList<>();
191 client.setAttachmentHandler(new CollectingAttachmentHandler(attachments));
192
193 final String content = DOCTYPE_HTML
194 + "<html>\n"
195 + "<head>\n"
196 + "<script>\n"
197 + "var blob = new Blob(['foo'], {type: 'text/plain'}),\n"
198 + " url = URL.createObjectURL(blob),\n"
199 + " elem = document.createElement('a');\n"
200 + "elem.href = url, elem.download = 'foo.txt', elem.click();\n"
201 + "</script>\n"
202 + "</head>\n"
203 + "</html>\n";
204
205 conn.setResponse(URL_FIRST, content);
206 client.getPage(URL_FIRST);
207
208 final Attachment result = attachments.get(0);
209 assertEquals(result.getSuggestedFilename(), "foo.txt");
210 assertEquals("foo", ((TextPage) result.getPage()).getContent());
211 attachments.clear();
212 }
213
214
215
216
217 @Test
218 public void filenameFromFile() throws Exception {
219 final WebClient client = getWebClient();
220 final MockWebConnection conn = new MockWebConnection();
221 client.setWebConnection(conn);
222 final List<Attachment> attachments = new ArrayList<>();
223 client.setAttachmentHandler(new CollectingAttachmentHandler(attachments));
224
225 final String content = DOCTYPE_HTML
226 + "<html>\n"
227 + "<head>\n"
228 + "<script>\n"
229 + "var blob = new File(['bar'], 'bar.txt', {type: 'text/plain'}),\n"
230 + " url = URL.createObjectURL(blob),\n"
231 + " elem = document.createElement('a');\n"
232 + "elem.href = url, elem.download = '', elem.click();\n"
233 + "</script>\n"
234 + "</head>\n"
235 + "</html>\n";
236
237 conn.setResponse(URL_FIRST, content);
238 client.getPage(URL_FIRST);
239
240 final Attachment result = attachments.get(0);
241 assertEquals(result.getSuggestedFilename(), "bar.txt");
242 assertEquals("bar", ((TextPage) result.getPage()).getContent());
243 attachments.clear();
244 }
245
246
247
248
249
250
251 @Test
252 public void filenameFromFilePrioritizeAnchorDownloadOverFileName() throws Exception {
253 final WebClient client = getWebClient();
254 final MockWebConnection conn = new MockWebConnection();
255 client.setWebConnection(conn);
256 final List<Attachment> attachments = new ArrayList<>();
257 client.setAttachmentHandler(new CollectingAttachmentHandler(attachments));
258
259 final String content = DOCTYPE_HTML
260 + "<html>\n"
261 + "<head>\n"
262 + "<script>\n"
263 + "var blob = new File(['bar'], 'bar.txt', {type: 'text/plain'}),\n"
264 + " url = URL.createObjectURL(blob),\n"
265 + " elem = document.createElement('a');\n"
266 + "elem.href = url, elem.download = 'foobar.txt', elem.click();\n"
267 + "</script>\n"
268 + "</head>\n"
269 + "</html>\n";
270
271 conn.setResponse(URL_FIRST, content);
272 client.getPage(URL_FIRST);
273
274 final Attachment result = attachments.get(0);
275 assertEquals(result.getSuggestedFilename(), "foobar.txt");
276 assertEquals("bar", ((TextPage) result.getPage()).getContent());
277 attachments.clear();
278 }
279
280
281
282
283
284
285 @Test
286 public void jsChangeLocationAfterReceptionOfAttachment() throws Exception {
287 final String html = DOCTYPE_HTML
288 + "<html><body>\n"
289 + "<form action='action'>\n"
290 + "<input type='submit' onclick='window.location=\"foo\"; return false'>\n"
291 + "</form>\n"
292 + "<a href='" + URL_SECOND + "'>download</a>\n"
293 + "</body></html>";
294
295 final WebClient client = getWebClient();
296 final List<Attachment> attachments = new ArrayList<>();
297 client.setAttachmentHandler(new CollectingAttachmentHandler(attachments));
298
299 final List<NameValuePair> headers = new ArrayList<>();
300 headers.add(new NameValuePair("Content-Disposition", "attachment"));
301
302 final MockWebConnection conn = getMockWebConnection();
303 conn.setDefaultResponse("");
304 conn.setResponse(URL_SECOND, "some text", 200, "OK", MimeType.TEXT_PLAIN, headers);
305
306 final HtmlPage page = loadPage(html);
307
308 page.getAnchors().get(0).click();
309 assertEquals(1, attachments.size());
310
311 final HtmlElement htmlElement = (HtmlElement) page.getFirstByXPath("//input");
312 htmlElement.click();
313 }
314
315
316
317
318
319 @Test
320 public void handleResponseFromHandler() throws Exception {
321 final String content1 = DOCTYPE_HTML
322 + "<html><body>\n"
323 + "<form method='POST' name='form' action='" + URL_SECOND + "'>\n"
324 + "<input type='submit' value='ok'>\n"
325 + "</form>\n"
326 + "<a href='#' onclick='document.form.submit()'>click me</a>\n"
327 + "</body></html>";
328 final String content2 = "download file contents";
329
330 final WebClient client = getWebClient();
331 final List<WebResponse> attachments = new ArrayList<>();
332 final List<String> attachmentFilenames = new ArrayList<>();
333
334 client.setAttachmentHandler(new AttachmentHandler() {
335 @Override
336 public boolean handleAttachment(final WebResponse response, final String attachmentFilename) {
337 attachments.add(response);
338 attachmentFilenames.add(attachmentFilename);
339 return true;
340 }
341
342 @Override
343 public void handleAttachment(final Page page, final String attachmentFilename) {
344 throw new IllegalAccessError("handleAttachment(Page, String) called");
345 }
346 });
347
348 final List<NameValuePair> headers = new ArrayList<>();
349 headers.add(new NameValuePair("Content-Disposition", "attachment"));
350
351 final MockWebConnection conn = new MockWebConnection();
352 conn.setResponse(URL_FIRST, content1);
353 conn.setResponse(URL_SECOND, content2, 200, "OK", MimeType.TEXT_HTML, headers);
354 client.setWebConnection(conn);
355 assertTrue(attachments.isEmpty());
356 assertTrue(attachmentFilenames.isEmpty());
357
358 final HtmlPage result = client.getPage(URL_FIRST);
359 final HtmlAnchor anchor = result.getAnchors().get(0);
360 final Page clickResult = anchor.click();
361 assertEquals(result, clickResult);
362 assertEquals(1, attachments.size());
363 assertEquals(1, attachmentFilenames.size());
364 assertEquals(1, client.getWebWindows().size());
365
366 final WebResponse attachmentResponse = attachments.get(0);
367 final InputStream attachmentStream = attachmentResponse.getContentAsStream();
368 HttpWebConnectionTest.assertEquals(new ByteArrayInputStream(content2.getBytes()), attachmentStream);
369 assertEquals(MimeType.TEXT_HTML, attachmentResponse.getContentType());
370 assertEquals(200, attachmentResponse.getStatusCode());
371 assertEquals(URL_SECOND, attachmentResponse.getWebRequest().getUrl());
372
373 assertNull(attachmentFilenames.get(0));
374 }
375
376
377
378
379
380 @Test
381 public void handleResponseFromHandlerWithFileName() throws Exception {
382 final String content1 = DOCTYPE_HTML
383 + "<html><body>\n"
384 + "<form method='POST' name='form' action='" + URL_SECOND + "'>\n"
385 + "<input type='submit' value='ok'>\n"
386 + "</form>\n"
387 + "<a href='#' onclick='document.form.submit()'>click me</a>\n"
388 + "</body></html>";
389 final String content2 = "download file contents";
390
391 final WebClient client = getWebClient();
392 final List<WebResponse> attachments = new ArrayList<>();
393 final List<String> attachmentFilenames = new ArrayList<>();
394
395 client.setAttachmentHandler(new AttachmentHandler() {
396 @Override
397 public boolean handleAttachment(final WebResponse response, final String attachmentFilename) {
398 attachments.add(response);
399 attachmentFilenames.add(attachmentFilename);
400 return true;
401 }
402
403 @Override
404 public void handleAttachment(final Page page, final String attachmentFilename) {
405 throw new IllegalAccessError("handleAttachment(Page, String) called");
406 }
407 });
408
409 final List<NameValuePair> headers = new ArrayList<>();
410 headers.add(new NameValuePair("Content-Disposition", "attachment; filename=htmlunit.zip"));
411
412 final MockWebConnection conn = new MockWebConnection();
413 conn.setResponse(URL_FIRST, content1);
414 conn.setResponse(URL_SECOND, content2, 200, "OK", MimeType.TEXT_HTML, headers);
415 client.setWebConnection(conn);
416 assertTrue(attachments.isEmpty());
417 assertTrue(attachmentFilenames.isEmpty());
418
419 final HtmlPage result = client.getPage(URL_FIRST);
420 final HtmlAnchor anchor = result.getAnchors().get(0);
421 final Page clickResult = anchor.click();
422 assertEquals(result, clickResult);
423 assertEquals(1, attachments.size());
424 assertEquals(1, attachmentFilenames.size());
425 assertEquals(1, client.getWebWindows().size());
426
427 final WebResponse attachmentResponse = attachments.get(0);
428 final InputStream attachmentStream = attachmentResponse.getContentAsStream();
429 HttpWebConnectionTest.assertEquals(new ByteArrayInputStream(content2.getBytes()), attachmentStream);
430 assertEquals(MimeType.TEXT_HTML, attachmentResponse.getContentType());
431 assertEquals(200, attachmentResponse.getStatusCode());
432 assertEquals(URL_SECOND, attachmentResponse.getWebRequest().getUrl());
433
434 assertEquals("htmlunit.zip", attachmentFilenames.get(0));
435 }
436
437
438
439
440
441 @Test
442 public void handleResponseOnlyApplicationOctetstream() throws Exception {
443 final String content1 = DOCTYPE_HTML
444 + "<html><body>\n"
445 + "<form method='POST' name='form' action='" + URL_SECOND + "'>\n"
446 + "<input type='submit' value='ok'>\n"
447 + "</form>\n"
448 + "<a href='#' onclick='document.form.submit()'>click me</a>\n"
449 + "</body></html>";
450 final String content2 = "download file contents";
451
452 final WebClient client = getWebClient();
453 final List<WebResponse> attachments = new ArrayList<>();
454 final List<String> attachmentFilenames = new ArrayList<>();
455
456 client.setAttachmentHandler(new AttachmentHandler() {
457 @Override
458 public boolean handleAttachment(final WebResponse response, final String attachmentFilename) {
459 attachments.add(response);
460 attachmentFilenames.add(attachmentFilename);
461 return true;
462 }
463
464 @Override
465 public void handleAttachment(final Page page, final String attachmentFilename) {
466 throw new IllegalAccessError("handleAttachment(Page, String) called");
467 }
468 });
469
470 final List<NameValuePair> headers = new ArrayList<>();
471 headers.add(new NameValuePair("Content-Type", MimeType.APPLICATION_OCTET_STREAM));
472
473 final MockWebConnection conn = new MockWebConnection();
474 conn.setResponse(URL_FIRST, content1);
475 conn.setResponse(URL_SECOND, content2, 200, "OK", MimeType.TEXT_HTML, headers);
476 client.setWebConnection(conn);
477 assertTrue(attachments.isEmpty());
478 assertTrue(attachmentFilenames.isEmpty());
479
480 final HtmlPage result = client.getPage(URL_FIRST);
481 final HtmlAnchor anchor = result.getAnchors().get(0);
482 final Page clickResult = anchor.click();
483 assertEquals(result, clickResult);
484 assertEquals(1, attachments.size());
485 assertEquals(1, attachmentFilenames.size());
486 assertEquals(1, client.getWebWindows().size());
487
488 final WebResponse attachmentResponse = attachments.get(0);
489 final InputStream attachmentStream = attachmentResponse.getContentAsStream();
490 HttpWebConnectionTest.assertEquals(new ByteArrayInputStream(content2.getBytes()), attachmentStream);
491 assertEquals(MimeType.APPLICATION_OCTET_STREAM, attachmentResponse.getContentType());
492 assertEquals(200, attachmentResponse.getStatusCode());
493 assertEquals(URL_SECOND, attachmentResponse.getWebRequest().getUrl());
494
495 assertNull(attachmentFilenames.get(0));
496 }
497 }