OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2011 Google Inc. All rights reserved. | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions are | |
6 * met: | |
7 * | |
8 * * Redistributions of source code must retain the above copyright | |
9 * notice, this list of conditions and the following disclaimer. | |
10 * * Redistributions in binary form must reproduce the above | |
11 * copyright notice, this list of conditions and the following disclaimer | |
12 * in the documentation and/or other materials provided with the | |
13 * distribution. | |
14 * * Neither the name of Google Inc. nor the names of its | |
15 * contributors may be used to endorse or promote products derived from | |
16 * this software without specific prior written permission. | |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 */ | |
30 | |
31 #include "platform/testing/URLTestHelpers.h" | |
32 #include "platform/testing/UnitTestHelpers.h" | |
33 #include "public/platform/Platform.h" | |
34 #include "public/platform/WebString.h" | |
35 #include "public/platform/WebThread.h" | |
36 #include "public/platform/WebURL.h" | |
37 #include "public/platform/WebURLLoader.h" | |
38 #include "public/platform/WebURLLoaderClient.h" | |
39 #include "public/platform/WebURLLoaderMockFactory.h" | |
40 #include "public/platform/WebURLRequest.h" | |
41 #include "public/platform/WebURLResponse.h" | |
42 #include "public/web/WebCache.h" | |
43 #include "public/web/WebFrame.h" | |
44 #include "public/web/WebURLLoaderOptions.h" | |
45 #include "public/web/WebView.h" | |
46 #include "testing/gtest/include/gtest/gtest.h" | |
47 #include "web/tests/FrameTestHelpers.h" | |
48 #include "wtf/PtrUtil.h" | |
49 #include "wtf/text/CString.h" | |
50 #include "wtf/text/WTFString.h" | |
51 #include <memory> | |
52 | |
53 using blink::URLTestHelpers::toKURL; | |
54 using blink::testing::runPendingTasks; | |
55 | |
56 namespace blink { | |
57 | |
58 class AssociatedURLLoaderTest : public ::testing::Test, | |
59 public WebURLLoaderClient { | |
60 public: | |
61 AssociatedURLLoaderTest() | |
62 : m_willFollowRedirect(false), | |
63 m_didSendData(false), | |
64 m_didReceiveResponse(false), | |
65 m_didReceiveData(false), | |
66 m_didReceiveCachedMetadata(false), | |
67 m_didFinishLoading(false), | |
68 m_didFail(false) { | |
69 // Reuse one of the test files from WebFrameTest. | |
70 m_baseFilePath = testing::blinkRootDir(); | |
71 m_baseFilePath.append("/Source/web/tests/data/"); | |
72 m_frameFilePath = m_baseFilePath; | |
73 m_frameFilePath.append("iframes_test.html"); | |
74 } | |
75 | |
76 KURL RegisterMockedUrl(const std::string& urlRoot, | |
77 const WTF::String& filename) { | |
78 WebURLResponse response; | |
79 response.setMIMEType("text/html"); | |
80 WTF::String localPath = m_baseFilePath; | |
81 localPath.append(filename); | |
82 KURL url = toKURL(urlRoot + filename.utf8().data()); | |
83 Platform::current()->getURLLoaderMockFactory()->registerURL(url, response, | |
84 localPath); | |
85 return url; | |
86 } | |
87 | |
88 void SetUp() override { | |
89 m_helper.initialize(); | |
90 | |
91 std::string urlRoot = "http://www.test.com/"; | |
92 KURL url = RegisterMockedUrl(urlRoot, "iframes_test.html"); | |
93 const char* iframeSupportFiles[] = { | |
94 "invisible_iframe.html", "visible_iframe.html", | |
95 "zero_sized_iframe.html", | |
96 }; | |
97 for (size_t i = 0; i < WTF_ARRAY_LENGTH(iframeSupportFiles); ++i) { | |
98 RegisterMockedUrl(urlRoot, iframeSupportFiles[i]); | |
99 } | |
100 | |
101 FrameTestHelpers::loadFrame(mainFrame(), url.getString().utf8().data()); | |
102 | |
103 Platform::current()->getURLLoaderMockFactory()->unregisterURL(url); | |
104 } | |
105 | |
106 void TearDown() override { | |
107 Platform::current()->getURLLoaderMockFactory()->unregisterAllURLs(); | |
108 WebCache::clear(); | |
109 } | |
110 | |
111 void serveRequests() { | |
112 Platform::current()->getURLLoaderMockFactory()->serveAsynchronousRequests(); | |
113 } | |
114 | |
115 std::unique_ptr<WebURLLoader> createAssociatedURLLoader( | |
116 const WebURLLoaderOptions options = WebURLLoaderOptions()) { | |
117 return wrapUnique(mainFrame()->createAssociatedURLLoader(options)); | |
118 } | |
119 | |
120 // WebURLLoaderClient implementation. | |
121 bool willFollowRedirect(WebURLLoader* loader, | |
122 WebURLRequest& newRequest, | |
123 const WebURLResponse& redirectResponse) override { | |
124 m_willFollowRedirect = true; | |
125 EXPECT_EQ(m_expectedLoader.get(), loader); | |
126 EXPECT_EQ(m_expectedNewRequest.url(), newRequest.url()); | |
127 // Check that CORS simple headers are transferred to the new request. | |
128 EXPECT_EQ(m_expectedNewRequest.httpHeaderField("accept"), | |
129 newRequest.httpHeaderField("accept")); | |
130 EXPECT_EQ(m_expectedRedirectResponse.url(), redirectResponse.url()); | |
131 EXPECT_EQ(m_expectedRedirectResponse.httpStatusCode(), | |
132 redirectResponse.httpStatusCode()); | |
133 EXPECT_EQ(m_expectedRedirectResponse.mimeType(), | |
134 redirectResponse.mimeType()); | |
135 return true; | |
136 } | |
137 | |
138 void didSendData(WebURLLoader* loader, | |
139 unsigned long long bytesSent, | |
140 unsigned long long totalBytesToBeSent) override { | |
141 m_didSendData = true; | |
142 EXPECT_EQ(m_expectedLoader.get(), loader); | |
143 } | |
144 | |
145 void didReceiveResponse(WebURLLoader* loader, | |
146 const WebURLResponse& response) override { | |
147 m_didReceiveResponse = true; | |
148 m_actualResponse = WebURLResponse(response); | |
149 EXPECT_EQ(m_expectedLoader.get(), loader); | |
150 EXPECT_EQ(m_expectedResponse.url(), response.url()); | |
151 EXPECT_EQ(m_expectedResponse.httpStatusCode(), response.httpStatusCode()); | |
152 } | |
153 | |
154 void didDownloadData(WebURLLoader* loader, | |
155 int dataLength, | |
156 int encodedDataLength) override { | |
157 m_didDownloadData = true; | |
158 EXPECT_EQ(m_expectedLoader.get(), loader); | |
159 } | |
160 | |
161 void didReceiveData(WebURLLoader* loader, | |
162 const char* data, | |
163 int dataLength, | |
164 int encodedDataLength, | |
165 int encodedBodyLength) override { | |
166 m_didReceiveData = true; | |
167 EXPECT_EQ(m_expectedLoader.get(), loader); | |
168 EXPECT_TRUE(data); | |
169 EXPECT_GT(dataLength, 0); | |
170 } | |
171 | |
172 void didReceiveCachedMetadata(WebURLLoader* loader, | |
173 const char* data, | |
174 int dataLength) override { | |
175 m_didReceiveCachedMetadata = true; | |
176 EXPECT_EQ(m_expectedLoader.get(), loader); | |
177 } | |
178 | |
179 void didFinishLoading(WebURLLoader* loader, | |
180 double finishTime, | |
181 int64_t encodedDataLength) override { | |
182 m_didFinishLoading = true; | |
183 EXPECT_EQ(m_expectedLoader.get(), loader); | |
184 } | |
185 | |
186 void didFail(WebURLLoader* loader, const WebURLError& error) override { | |
187 m_didFail = true; | |
188 EXPECT_EQ(m_expectedLoader.get(), loader); | |
189 } | |
190 | |
191 void CheckMethodFails(const char* unsafeMethod) { | |
192 WebURLRequest request; | |
193 request.setURL(toKURL("http://www.test.com/success.html")); | |
194 request.setHTTPMethod(WebString::fromUTF8(unsafeMethod)); | |
195 WebURLLoaderOptions options; | |
196 options.untrustedHTTP = true; | |
197 CheckFails(request, options); | |
198 } | |
199 | |
200 void CheckHeaderFails(const char* headerField) { | |
201 CheckHeaderFails(headerField, "foo"); | |
202 } | |
203 | |
204 void CheckHeaderFails(const char* headerField, const char* headerValue) { | |
205 WebURLRequest request; | |
206 request.setURL(toKURL("http://www.test.com/success.html")); | |
207 if (equalIgnoringASCIICase(WebString::fromUTF8(headerField), "referer")) | |
208 request.setHTTPReferrer(WebString::fromUTF8(headerValue), | |
209 WebReferrerPolicyDefault); | |
210 else | |
211 request.setHTTPHeaderField(WebString::fromUTF8(headerField), | |
212 WebString::fromUTF8(headerValue)); | |
213 WebURLLoaderOptions options; | |
214 options.untrustedHTTP = true; | |
215 CheckFails(request, options); | |
216 } | |
217 | |
218 void CheckFails(const WebURLRequest& request, | |
219 WebURLLoaderOptions options = WebURLLoaderOptions()) { | |
220 m_expectedLoader = createAssociatedURLLoader(options); | |
221 EXPECT_TRUE(m_expectedLoader); | |
222 m_didFail = false; | |
223 m_expectedLoader->loadAsynchronously(request, this); | |
224 // Failure should not be reported synchronously. | |
225 EXPECT_FALSE(m_didFail); | |
226 // Allow the loader to return the error. | |
227 runPendingTasks(); | |
228 EXPECT_TRUE(m_didFail); | |
229 EXPECT_FALSE(m_didReceiveResponse); | |
230 } | |
231 | |
232 bool CheckAccessControlHeaders(const char* headerName, bool exposed) { | |
233 std::string id("http://www.other.com/CheckAccessControlExposeHeaders_"); | |
234 id.append(headerName); | |
235 if (exposed) | |
236 id.append("-Exposed"); | |
237 id.append(".html"); | |
238 | |
239 KURL url = toKURL(id); | |
240 WebURLRequest request; | |
241 request.setURL(url); | |
242 | |
243 WebString headerNameString(WebString::fromUTF8(headerName)); | |
244 m_expectedResponse = WebURLResponse(); | |
245 m_expectedResponse.setMIMEType("text/html"); | |
246 m_expectedResponse.setHTTPStatusCode(200); | |
247 m_expectedResponse.addHTTPHeaderField("Access-Control-Allow-Origin", "*"); | |
248 if (exposed) | |
249 m_expectedResponse.addHTTPHeaderField("access-control-expose-headers", | |
250 headerNameString); | |
251 m_expectedResponse.addHTTPHeaderField(headerNameString, "foo"); | |
252 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
253 url, m_expectedResponse, m_frameFilePath); | |
254 | |
255 WebURLLoaderOptions options; | |
256 options.crossOriginRequestPolicy = | |
257 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; | |
258 m_expectedLoader = createAssociatedURLLoader(options); | |
259 EXPECT_TRUE(m_expectedLoader); | |
260 m_expectedLoader->loadAsynchronously(request, this); | |
261 serveRequests(); | |
262 EXPECT_TRUE(m_didReceiveResponse); | |
263 EXPECT_TRUE(m_didReceiveData); | |
264 EXPECT_TRUE(m_didFinishLoading); | |
265 | |
266 return !m_actualResponse.httpHeaderField(headerNameString).isEmpty(); | |
267 } | |
268 | |
269 WebFrame* mainFrame() const { return m_helper.webView()->mainFrame(); } | |
270 | |
271 protected: | |
272 String m_baseFilePath; | |
273 String m_frameFilePath; | |
274 FrameTestHelpers::WebViewHelper m_helper; | |
275 | |
276 std::unique_ptr<WebURLLoader> m_expectedLoader; | |
277 WebURLResponse m_actualResponse; | |
278 WebURLResponse m_expectedResponse; | |
279 WebURLRequest m_expectedNewRequest; | |
280 WebURLResponse m_expectedRedirectResponse; | |
281 bool m_willFollowRedirect; | |
282 bool m_didSendData; | |
283 bool m_didReceiveResponse; | |
284 bool m_didDownloadData; | |
285 bool m_didReceiveData; | |
286 bool m_didReceiveCachedMetadata; | |
287 bool m_didFinishLoading; | |
288 bool m_didFail; | |
289 }; | |
290 | |
291 // Test a successful same-origin URL load. | |
292 TEST_F(AssociatedURLLoaderTest, SameOriginSuccess) { | |
293 KURL url = toKURL("http://www.test.com/SameOriginSuccess.html"); | |
294 WebURLRequest request; | |
295 request.setURL(url); | |
296 | |
297 m_expectedResponse = WebURLResponse(); | |
298 m_expectedResponse.setMIMEType("text/html"); | |
299 m_expectedResponse.setHTTPStatusCode(200); | |
300 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
301 url, m_expectedResponse, m_frameFilePath); | |
302 | |
303 m_expectedLoader = createAssociatedURLLoader(); | |
304 EXPECT_TRUE(m_expectedLoader); | |
305 m_expectedLoader->loadAsynchronously(request, this); | |
306 serveRequests(); | |
307 EXPECT_TRUE(m_didReceiveResponse); | |
308 EXPECT_TRUE(m_didReceiveData); | |
309 EXPECT_TRUE(m_didFinishLoading); | |
310 } | |
311 | |
312 // Test that the same-origin restriction is the default. | |
313 TEST_F(AssociatedURLLoaderTest, SameOriginRestriction) { | |
314 // This is cross-origin since the frame was loaded from www.test.com. | |
315 KURL url = toKURL("http://www.other.com/SameOriginRestriction.html"); | |
316 WebURLRequest request; | |
317 request.setURL(url); | |
318 CheckFails(request); | |
319 } | |
320 | |
321 // Test a successful cross-origin load. | |
322 TEST_F(AssociatedURLLoaderTest, CrossOriginSuccess) { | |
323 // This is cross-origin since the frame was loaded from www.test.com. | |
324 KURL url = toKURL("http://www.other.com/CrossOriginSuccess"); | |
325 WebURLRequest request; | |
326 request.setURL(url); | |
327 // No-CORS requests (CrossOriginRequestPolicyAllow) aren't allowed for the | |
328 // default context. So we set the context as Script here. | |
329 request.setRequestContext(WebURLRequest::RequestContextScript); | |
330 | |
331 m_expectedResponse = WebURLResponse(); | |
332 m_expectedResponse.setMIMEType("text/html"); | |
333 m_expectedResponse.setHTTPStatusCode(200); | |
334 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
335 url, m_expectedResponse, m_frameFilePath); | |
336 | |
337 WebURLLoaderOptions options; | |
338 options.crossOriginRequestPolicy = | |
339 WebURLLoaderOptions::CrossOriginRequestPolicyAllow; | |
340 m_expectedLoader = createAssociatedURLLoader(options); | |
341 EXPECT_TRUE(m_expectedLoader); | |
342 m_expectedLoader->loadAsynchronously(request, this); | |
343 serveRequests(); | |
344 EXPECT_TRUE(m_didReceiveResponse); | |
345 EXPECT_TRUE(m_didReceiveData); | |
346 EXPECT_TRUE(m_didFinishLoading); | |
347 } | |
348 | |
349 // Test a successful cross-origin load using CORS. | |
350 TEST_F(AssociatedURLLoaderTest, CrossOriginWithAccessControlSuccess) { | |
351 // This is cross-origin since the frame was loaded from www.test.com. | |
352 KURL url = | |
353 toKURL("http://www.other.com/CrossOriginWithAccessControlSuccess.html"); | |
354 WebURLRequest request; | |
355 request.setURL(url); | |
356 | |
357 m_expectedResponse = WebURLResponse(); | |
358 m_expectedResponse.setMIMEType("text/html"); | |
359 m_expectedResponse.setHTTPStatusCode(200); | |
360 m_expectedResponse.addHTTPHeaderField("access-control-allow-origin", "*"); | |
361 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
362 url, m_expectedResponse, m_frameFilePath); | |
363 | |
364 WebURLLoaderOptions options; | |
365 options.crossOriginRequestPolicy = | |
366 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; | |
367 m_expectedLoader = createAssociatedURLLoader(options); | |
368 EXPECT_TRUE(m_expectedLoader); | |
369 m_expectedLoader->loadAsynchronously(request, this); | |
370 serveRequests(); | |
371 EXPECT_TRUE(m_didReceiveResponse); | |
372 EXPECT_TRUE(m_didReceiveData); | |
373 EXPECT_TRUE(m_didFinishLoading); | |
374 } | |
375 | |
376 // Test an unsuccessful cross-origin load using CORS. | |
377 TEST_F(AssociatedURLLoaderTest, CrossOriginWithAccessControlFailure) { | |
378 // This is cross-origin since the frame was loaded from www.test.com. | |
379 KURL url = | |
380 toKURL("http://www.other.com/CrossOriginWithAccessControlFailure.html"); | |
381 WebURLRequest request; | |
382 request.setURL(url); | |
383 | |
384 m_expectedResponse = WebURLResponse(); | |
385 m_expectedResponse.setMIMEType("text/html"); | |
386 m_expectedResponse.setHTTPStatusCode(200); | |
387 m_expectedResponse.addHTTPHeaderField("access-control-allow-origin", "*"); | |
388 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
389 url, m_expectedResponse, m_frameFilePath); | |
390 | |
391 WebURLLoaderOptions options; | |
392 // Send credentials. This will cause the CORS checks to fail, because | |
393 // credentials can't be sent to a server which returns the header | |
394 // "access-control-allow-origin" with "*" as its value. | |
395 options.allowCredentials = true; | |
396 options.crossOriginRequestPolicy = | |
397 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; | |
398 m_expectedLoader = createAssociatedURLLoader(options); | |
399 EXPECT_TRUE(m_expectedLoader); | |
400 m_expectedLoader->loadAsynchronously(request, this); | |
401 | |
402 // Failure should not be reported synchronously. | |
403 EXPECT_FALSE(m_didFail); | |
404 // The loader needs to receive the response, before doing the CORS check. | |
405 serveRequests(); | |
406 EXPECT_TRUE(m_didFail); | |
407 EXPECT_FALSE(m_didReceiveResponse); | |
408 } | |
409 | |
410 // Test an unsuccessful cross-origin load using CORS. | |
411 TEST_F(AssociatedURLLoaderTest, | |
412 CrossOriginWithAccessControlFailureBadStatusCode) { | |
413 // This is cross-origin since the frame was loaded from www.test.com. | |
414 KURL url = | |
415 toKURL("http://www.other.com/CrossOriginWithAccessControlFailure.html"); | |
416 WebURLRequest request; | |
417 request.setURL(url); | |
418 | |
419 m_expectedResponse = WebURLResponse(); | |
420 m_expectedResponse.setMIMEType("text/html"); | |
421 m_expectedResponse.setHTTPStatusCode(0); | |
422 m_expectedResponse.addHTTPHeaderField("access-control-allow-origin", "*"); | |
423 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
424 url, m_expectedResponse, m_frameFilePath); | |
425 | |
426 WebURLLoaderOptions options; | |
427 options.crossOriginRequestPolicy = | |
428 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; | |
429 m_expectedLoader = createAssociatedURLLoader(options); | |
430 EXPECT_TRUE(m_expectedLoader); | |
431 m_expectedLoader->loadAsynchronously(request, this); | |
432 | |
433 // Failure should not be reported synchronously. | |
434 EXPECT_FALSE(m_didFail); | |
435 // The loader needs to receive the response, before doing the CORS check. | |
436 serveRequests(); | |
437 EXPECT_TRUE(m_didFail); | |
438 EXPECT_FALSE(m_didReceiveResponse); | |
439 } | |
440 | |
441 // Test a same-origin URL redirect and load. | |
442 TEST_F(AssociatedURLLoaderTest, RedirectSuccess) { | |
443 KURL url = toKURL("http://www.test.com/RedirectSuccess.html"); | |
444 char redirect[] = "http://www.test.com/RedirectSuccess2.html"; // Same-origin | |
445 KURL redirectURL = toKURL(redirect); | |
446 | |
447 WebURLRequest request; | |
448 request.setURL(url); | |
449 | |
450 m_expectedRedirectResponse = WebURLResponse(); | |
451 m_expectedRedirectResponse.setMIMEType("text/html"); | |
452 m_expectedRedirectResponse.setHTTPStatusCode(301); | |
453 m_expectedRedirectResponse.setHTTPHeaderField("Location", redirect); | |
454 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
455 url, m_expectedRedirectResponse, m_frameFilePath); | |
456 | |
457 m_expectedNewRequest = WebURLRequest(); | |
458 m_expectedNewRequest.setURL(redirectURL); | |
459 | |
460 m_expectedResponse = WebURLResponse(); | |
461 m_expectedResponse.setMIMEType("text/html"); | |
462 m_expectedResponse.setHTTPStatusCode(200); | |
463 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
464 redirectURL, m_expectedResponse, m_frameFilePath); | |
465 | |
466 m_expectedLoader = createAssociatedURLLoader(); | |
467 EXPECT_TRUE(m_expectedLoader); | |
468 m_expectedLoader->loadAsynchronously(request, this); | |
469 serveRequests(); | |
470 EXPECT_TRUE(m_willFollowRedirect); | |
471 EXPECT_TRUE(m_didReceiveResponse); | |
472 EXPECT_TRUE(m_didReceiveData); | |
473 EXPECT_TRUE(m_didFinishLoading); | |
474 } | |
475 | |
476 // Test a cross-origin URL redirect without Access Control set. | |
477 TEST_F(AssociatedURLLoaderTest, RedirectCrossOriginFailure) { | |
478 KURL url = toKURL("http://www.test.com/RedirectCrossOriginFailure.html"); | |
479 char redirect[] = | |
480 "http://www.other.com/RedirectCrossOriginFailure.html"; // Cross-origin | |
481 KURL redirectURL = toKURL(redirect); | |
482 | |
483 WebURLRequest request; | |
484 request.setURL(url); | |
485 | |
486 m_expectedRedirectResponse = WebURLResponse(); | |
487 m_expectedRedirectResponse.setMIMEType("text/html"); | |
488 m_expectedRedirectResponse.setHTTPStatusCode(301); | |
489 m_expectedRedirectResponse.setHTTPHeaderField("Location", redirect); | |
490 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
491 url, m_expectedRedirectResponse, m_frameFilePath); | |
492 | |
493 m_expectedNewRequest = WebURLRequest(); | |
494 m_expectedNewRequest.setURL(redirectURL); | |
495 | |
496 m_expectedResponse = WebURLResponse(); | |
497 m_expectedResponse.setMIMEType("text/html"); | |
498 m_expectedResponse.setHTTPStatusCode(200); | |
499 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
500 redirectURL, m_expectedResponse, m_frameFilePath); | |
501 | |
502 m_expectedLoader = createAssociatedURLLoader(); | |
503 EXPECT_TRUE(m_expectedLoader); | |
504 m_expectedLoader->loadAsynchronously(request, this); | |
505 | |
506 serveRequests(); | |
507 EXPECT_FALSE(m_willFollowRedirect); | |
508 EXPECT_FALSE(m_didReceiveResponse); | |
509 EXPECT_FALSE(m_didReceiveData); | |
510 EXPECT_FALSE(m_didFinishLoading); | |
511 } | |
512 | |
513 // Test that a cross origin redirect response without CORS headers fails. | |
514 TEST_F(AssociatedURLLoaderTest, RedirectCrossOriginWithAccessControlFailure) { | |
515 KURL url = toKURL( | |
516 "http://www.test.com/RedirectCrossOriginWithAccessControlFailure.html"); | |
517 char redirect[] = | |
518 "http://www.other.com/" | |
519 "RedirectCrossOriginWithAccessControlFailure.html"; // Cross-origin | |
520 KURL redirectURL = toKURL(redirect); | |
521 | |
522 WebURLRequest request; | |
523 request.setURL(url); | |
524 | |
525 m_expectedRedirectResponse = WebURLResponse(); | |
526 m_expectedRedirectResponse.setMIMEType("text/html"); | |
527 m_expectedRedirectResponse.setHTTPStatusCode(301); | |
528 m_expectedRedirectResponse.setHTTPHeaderField("Location", redirect); | |
529 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
530 url, m_expectedRedirectResponse, m_frameFilePath); | |
531 | |
532 m_expectedNewRequest = WebURLRequest(); | |
533 m_expectedNewRequest.setURL(redirectURL); | |
534 | |
535 m_expectedResponse = WebURLResponse(); | |
536 m_expectedResponse.setMIMEType("text/html"); | |
537 m_expectedResponse.setHTTPStatusCode(200); | |
538 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
539 redirectURL, m_expectedResponse, m_frameFilePath); | |
540 | |
541 WebURLLoaderOptions options; | |
542 options.crossOriginRequestPolicy = | |
543 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; | |
544 m_expectedLoader = createAssociatedURLLoader(options); | |
545 EXPECT_TRUE(m_expectedLoader); | |
546 m_expectedLoader->loadAsynchronously(request, this); | |
547 | |
548 serveRequests(); | |
549 // We should get a notification about access control check failure. | |
550 EXPECT_FALSE(m_willFollowRedirect); | |
551 EXPECT_FALSE(m_didReceiveResponse); | |
552 EXPECT_FALSE(m_didReceiveData); | |
553 EXPECT_TRUE(m_didFail); | |
554 } | |
555 | |
556 // Test that a cross origin redirect response with CORS headers that allow the | |
557 // requesting origin succeeds. | |
558 TEST_F(AssociatedURLLoaderTest, RedirectCrossOriginWithAccessControlSuccess) { | |
559 KURL url = toKURL( | |
560 "http://www.test.com/RedirectCrossOriginWithAccessControlSuccess.html"); | |
561 char redirect[] = | |
562 "http://www.other.com/" | |
563 "RedirectCrossOriginWithAccessControlSuccess.html"; // Cross-origin | |
564 KURL redirectURL = toKURL(redirect); | |
565 | |
566 WebURLRequest request; | |
567 request.setURL(url); | |
568 // Add a CORS simple header. | |
569 request.setHTTPHeaderField("accept", "application/json"); | |
570 | |
571 // Create a redirect response that allows the redirect to pass the access | |
572 // control checks. | |
573 m_expectedRedirectResponse = WebURLResponse(); | |
574 m_expectedRedirectResponse.setMIMEType("text/html"); | |
575 m_expectedRedirectResponse.setHTTPStatusCode(301); | |
576 m_expectedRedirectResponse.setHTTPHeaderField("Location", redirect); | |
577 m_expectedRedirectResponse.addHTTPHeaderField("access-control-allow-origin", | |
578 "*"); | |
579 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
580 url, m_expectedRedirectResponse, m_frameFilePath); | |
581 | |
582 m_expectedNewRequest = WebURLRequest(); | |
583 m_expectedNewRequest.setURL(redirectURL); | |
584 m_expectedNewRequest.setHTTPHeaderField("accept", "application/json"); | |
585 | |
586 m_expectedResponse = WebURLResponse(); | |
587 m_expectedResponse.setMIMEType("text/html"); | |
588 m_expectedResponse.setHTTPStatusCode(200); | |
589 m_expectedResponse.addHTTPHeaderField("access-control-allow-origin", "*"); | |
590 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
591 redirectURL, m_expectedResponse, m_frameFilePath); | |
592 | |
593 WebURLLoaderOptions options; | |
594 options.crossOriginRequestPolicy = | |
595 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; | |
596 m_expectedLoader = createAssociatedURLLoader(options); | |
597 EXPECT_TRUE(m_expectedLoader); | |
598 m_expectedLoader->loadAsynchronously(request, this); | |
599 serveRequests(); | |
600 // We should not receive a notification for the redirect. | |
601 EXPECT_FALSE(m_willFollowRedirect); | |
602 EXPECT_TRUE(m_didReceiveResponse); | |
603 EXPECT_TRUE(m_didReceiveData); | |
604 EXPECT_TRUE(m_didFinishLoading); | |
605 } | |
606 | |
607 // Test that untrusted loads can't use a forbidden method. | |
608 TEST_F(AssociatedURLLoaderTest, UntrustedCheckMethods) { | |
609 // Check non-token method fails. | |
610 CheckMethodFails("GET()"); | |
611 CheckMethodFails("POST\x0d\x0ax-csrf-token:\x20test1234"); | |
612 | |
613 // Forbidden methods should fail regardless of casing. | |
614 CheckMethodFails("CoNneCt"); | |
615 CheckMethodFails("TrAcK"); | |
616 CheckMethodFails("TrAcE"); | |
617 } | |
618 | |
619 // This test is flaky on Windows and Android. See <http://crbug.com/471645>. | |
620 #if OS(WIN) || OS(ANDROID) | |
621 #define MAYBE_UntrustedCheckHeaders DISABLED_UntrustedCheckHeaders | |
622 #else | |
623 #define MAYBE_UntrustedCheckHeaders UntrustedCheckHeaders | |
624 #endif | |
625 | |
626 // Test that untrusted loads can't use a forbidden header field. | |
627 TEST_F(AssociatedURLLoaderTest, MAYBE_UntrustedCheckHeaders) { | |
628 // Check non-token header fails. | |
629 CheckHeaderFails("foo()"); | |
630 | |
631 // Check forbidden headers fail. | |
632 CheckHeaderFails("accept-charset"); | |
633 CheckHeaderFails("accept-encoding"); | |
634 CheckHeaderFails("connection"); | |
635 CheckHeaderFails("content-length"); | |
636 CheckHeaderFails("cookie"); | |
637 CheckHeaderFails("cookie2"); | |
638 CheckHeaderFails("date"); | |
639 CheckHeaderFails("dnt"); | |
640 CheckHeaderFails("expect"); | |
641 CheckHeaderFails("host"); | |
642 CheckHeaderFails("keep-alive"); | |
643 CheckHeaderFails("origin"); | |
644 CheckHeaderFails("referer", "http://example.com/"); | |
645 CheckHeaderFails("te"); | |
646 CheckHeaderFails("trailer"); | |
647 CheckHeaderFails("transfer-encoding"); | |
648 CheckHeaderFails("upgrade"); | |
649 CheckHeaderFails("user-agent"); | |
650 CheckHeaderFails("via"); | |
651 | |
652 CheckHeaderFails("proxy-"); | |
653 CheckHeaderFails("proxy-foo"); | |
654 CheckHeaderFails("sec-"); | |
655 CheckHeaderFails("sec-foo"); | |
656 | |
657 // Check that validation is case-insensitive. | |
658 CheckHeaderFails("AcCePt-ChArSeT"); | |
659 CheckHeaderFails("ProXy-FoO"); | |
660 | |
661 // Check invalid header values. | |
662 CheckHeaderFails("foo", "bar\x0d\x0ax-csrf-token:\x20test1234"); | |
663 } | |
664 | |
665 // Test that the loader filters response headers according to the CORS standard. | |
666 TEST_F(AssociatedURLLoaderTest, CrossOriginHeaderWhitelisting) { | |
667 // Test that whitelisted headers are returned without exposing them. | |
668 EXPECT_TRUE(CheckAccessControlHeaders("cache-control", false)); | |
669 EXPECT_TRUE(CheckAccessControlHeaders("content-language", false)); | |
670 EXPECT_TRUE(CheckAccessControlHeaders("content-type", false)); | |
671 EXPECT_TRUE(CheckAccessControlHeaders("expires", false)); | |
672 EXPECT_TRUE(CheckAccessControlHeaders("last-modified", false)); | |
673 EXPECT_TRUE(CheckAccessControlHeaders("pragma", false)); | |
674 | |
675 // Test that non-whitelisted headers aren't returned. | |
676 EXPECT_FALSE(CheckAccessControlHeaders("non-whitelisted", false)); | |
677 | |
678 // Test that Set-Cookie headers aren't returned. | |
679 EXPECT_FALSE(CheckAccessControlHeaders("Set-Cookie", false)); | |
680 EXPECT_FALSE(CheckAccessControlHeaders("Set-Cookie2", false)); | |
681 | |
682 // Test that exposed headers that aren't whitelisted are returned. | |
683 EXPECT_TRUE(CheckAccessControlHeaders("non-whitelisted", true)); | |
684 | |
685 // Test that Set-Cookie headers aren't returned, even if exposed. | |
686 EXPECT_FALSE(CheckAccessControlHeaders("Set-Cookie", true)); | |
687 } | |
688 | |
689 // Test that the loader can allow non-whitelisted response headers for trusted | |
690 // CORS loads. | |
691 TEST_F(AssociatedURLLoaderTest, CrossOriginHeaderAllowResponseHeaders) { | |
692 WebURLRequest request; | |
693 KURL url = | |
694 toKURL("http://www.other.com/CrossOriginHeaderAllowResponseHeaders.html"); | |
695 request.setURL(url); | |
696 | |
697 WebString headerNameString(WebString::fromUTF8("non-whitelisted")); | |
698 m_expectedResponse = WebURLResponse(); | |
699 m_expectedResponse.setMIMEType("text/html"); | |
700 m_expectedResponse.setHTTPStatusCode(200); | |
701 m_expectedResponse.addHTTPHeaderField("Access-Control-Allow-Origin", "*"); | |
702 m_expectedResponse.addHTTPHeaderField(headerNameString, "foo"); | |
703 Platform::current()->getURLLoaderMockFactory()->registerURL( | |
704 url, m_expectedResponse, m_frameFilePath); | |
705 | |
706 WebURLLoaderOptions options; | |
707 options.exposeAllResponseHeaders = | |
708 true; // This turns off response whitelisting. | |
709 options.crossOriginRequestPolicy = | |
710 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; | |
711 m_expectedLoader = createAssociatedURLLoader(options); | |
712 EXPECT_TRUE(m_expectedLoader); | |
713 m_expectedLoader->loadAsynchronously(request, this); | |
714 serveRequests(); | |
715 EXPECT_TRUE(m_didReceiveResponse); | |
716 EXPECT_TRUE(m_didReceiveData); | |
717 EXPECT_TRUE(m_didFinishLoading); | |
718 | |
719 EXPECT_FALSE(m_actualResponse.httpHeaderField(headerNameString).isEmpty()); | |
720 } | |
721 | |
722 } // namespace blink | |
OLD | NEW |