1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/child/web_url_loader_impl.h"
9 #include "base/macros.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/time/time.h"
13 #include "content/child/resource_dispatcher.h"
14 #include "content/public/child/request_peer.h"
15 #include "content/public/common/resource_response_info.h"
16 #include "net/base/net_errors.h"
17 #include "net/http/http_response_headers.h"
18 #include "net/http/http_util.h"
19 #include "net/url_request/redirect_info.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "third_party/WebKit/public/platform/WebString.h"
22 #include "third_party/WebKit/public/platform/WebURLError.h"
23 #include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
24 #include "third_party/WebKit/public/platform/WebURLRequest.h"
26 #include "webkit/child/resource_loader_bridge.h"
31 const char kTestURL
[] = "http://foo";
32 const char kTestData
[] = "blah!";
34 const char kFtpDirMimeType
[] = "text/vnd.chromium.ftp-dir";
35 // Simple FTP directory listing. Tests are not concerned with correct parsing,
36 // but rather correct cleanup when deleted while parsing. Important details of
37 // this list are that it contains more than one entry that are not "." or "..".
38 const char kFtpDirListing
[] =
39 "drwxr-xr-x 3 ftp ftp 4096 May 15 18:11 goat\n"
40 "drwxr-xr-x 3 ftp ftp 4096 May 15 18:11 hat";
42 const char kMultipartResponseMimeType
[] = "multipart/x-mixed-replace";
43 const char kMultipartResponseHeaders
[] =
44 "HTTP/1.0 200 Peachy\r\n"
45 "Content-Type: multipart/x-mixed-replace; boundary=boundary\r\n\r\n";
46 // Simple multipart response. Imporant details for the tests are that it
47 // contains multiple chunks, and that it doesn't end with a boundary, so will
48 // send data in OnResponseComplete. Also, it will resolve to kTestData.
49 const char kMultipartResponse
[] =
51 "Content-type: text/html\n\n"
54 "Content-type: text/html\n\n"
57 class TestBridge
: public webkit_glue::ResourceLoaderBridge
,
58 public base::SupportsWeakPtr
<TestBridge
> {
60 TestBridge() : peer_(NULL
), canceled_(false) {}
61 virtual ~TestBridge() {}
63 // ResourceLoaderBridge implementation:
64 virtual void SetRequestBody(ResourceRequestBody
* request_body
) OVERRIDE
{}
66 virtual bool Start(RequestPeer
* peer
) OVERRIDE
{
72 virtual void Cancel() OVERRIDE
{
73 EXPECT_FALSE(canceled_
);
77 virtual void SetDefersLoading(bool value
) OVERRIDE
{}
79 virtual void DidChangePriority(net::RequestPriority new_priority
,
80 int intra_priority_value
) OVERRIDE
{}
82 virtual bool AttachThreadedDataReceiver(
83 blink::WebThreadedDataReceiver
* threaded_data_receiver
) OVERRIDE
{
88 virtual void SyncLoad(SyncLoadResponse
* response
) OVERRIDE
{}
90 RequestPeer
* peer() { return peer_
; }
92 bool canceled() { return canceled_
; }
98 DISALLOW_COPY_AND_ASSIGN(TestBridge
);
101 class TestResourceDispatcher
: public ResourceDispatcher
{
103 TestResourceDispatcher() : ResourceDispatcher(NULL
) {}
104 virtual ~TestResourceDispatcher() {}
106 // ResourceDispatcher implementation:
107 virtual webkit_glue::ResourceLoaderBridge
* CreateBridge(
108 const RequestInfo
& request_info
) OVERRIDE
{
109 EXPECT_FALSE(bridge_
.get());
110 TestBridge
* bridge
= new TestBridge();
111 bridge_
= bridge
->AsWeakPtr();
115 TestBridge
* bridge() { return bridge_
.get(); }
118 base::WeakPtr
<TestBridge
> bridge_
;
120 DISALLOW_COPY_AND_ASSIGN(TestResourceDispatcher
);
123 class TestWebURLLoaderClient
: public blink::WebURLLoaderClient
{
125 TestWebURLLoaderClient(ResourceDispatcher
* dispatcher
)
126 : loader_(new WebURLLoaderImpl(dispatcher
)),
127 expect_multipart_response_(false),
128 delete_on_receive_redirect_(false),
129 delete_on_receive_response_(false),
130 delete_on_receive_data_(false),
131 delete_on_finish_(false),
132 delete_on_fail_(false),
133 did_receive_redirect_(false),
134 did_receive_response_(false),
138 virtual ~TestWebURLLoaderClient() {}
140 // blink::WebURLLoaderClient implementation:
141 virtual void willSendRequest(
142 blink::WebURLLoader
* loader
,
143 blink::WebURLRequest
& newRequest
,
144 const blink::WebURLResponse
& redirectResponse
) OVERRIDE
{
145 EXPECT_TRUE(loader_
);
146 EXPECT_EQ(loader_
.get(), loader
);
147 // No test currently simulates mutiple redirects.
148 EXPECT_FALSE(did_receive_redirect_
);
149 did_receive_redirect_
= true;
151 if (delete_on_receive_redirect_
)
155 virtual void didSendData(blink::WebURLLoader
* loader
,
156 unsigned long long bytesSent
,
157 unsigned long long totalBytesToBeSent
) OVERRIDE
{
158 EXPECT_TRUE(loader_
);
159 EXPECT_EQ(loader_
.get(), loader
);
162 virtual void didReceiveResponse(
163 blink::WebURLLoader
* loader
,
164 const blink::WebURLResponse
& response
) OVERRIDE
{
165 EXPECT_TRUE(loader_
);
166 EXPECT_EQ(loader_
.get(), loader
);
168 // Only multipart requests may receive multiple response headers.
169 EXPECT_TRUE(expect_multipart_response_
|| !did_receive_response_
);
171 did_receive_response_
= true;
172 if (delete_on_receive_response_
)
176 virtual void didDownloadData(blink::WebURLLoader
* loader
,
178 int encodedDataLength
) OVERRIDE
{
179 EXPECT_TRUE(loader_
);
180 EXPECT_EQ(loader_
.get(), loader
);
183 virtual void didReceiveData(blink::WebURLLoader
* loader
,
186 int encodedDataLength
) OVERRIDE
{
187 EXPECT_TRUE(loader_
);
188 EXPECT_EQ(loader_
.get(), loader
);
189 // The response should have started, but must not have finished, or failed.
190 EXPECT_TRUE(did_receive_response_
);
191 EXPECT_FALSE(did_finish_
);
192 EXPECT_EQ(net::OK
, error_
.reason
);
193 EXPECT_EQ("", error_
.domain
.utf8());
195 received_data_
.append(data
, dataLength
);
197 if (delete_on_receive_data_
)
201 virtual void didReceiveCachedMetadata(blink::WebURLLoader
* loader
,
203 int dataLength
) OVERRIDE
{
204 EXPECT_EQ(loader_
.get(), loader
);
207 virtual void didFinishLoading(blink::WebURLLoader
* loader
,
209 int64_t totalEncodedDataLength
) OVERRIDE
{
210 EXPECT_TRUE(loader_
);
211 EXPECT_EQ(loader_
.get(), loader
);
212 EXPECT_TRUE(did_receive_response_
);
213 EXPECT_FALSE(did_finish_
);
216 if (delete_on_finish_
)
220 virtual void didFail(blink::WebURLLoader
* loader
,
221 const blink::WebURLError
& error
) OVERRIDE
{
222 EXPECT_TRUE(loader_
);
223 EXPECT_EQ(loader_
.get(), loader
);
224 EXPECT_FALSE(did_finish_
);
231 WebURLLoaderImpl
* loader() { return loader_
.get(); }
232 void DeleteLoader() {
236 void set_expect_multipart_response() { expect_multipart_response_
= true; }
238 void set_delete_on_receive_redirect() { delete_on_receive_redirect_
= true; }
239 void set_delete_on_receive_response() { delete_on_receive_response_
= true; }
240 void set_delete_on_receive_data() { delete_on_receive_data_
= true; }
241 void set_delete_on_finish() { delete_on_finish_
= true; }
242 void set_delete_on_fail() { delete_on_fail_
= true; }
244 bool did_receive_redirect() const { return did_receive_redirect_
; }
245 bool did_receive_response() const { return did_receive_response_
; }
246 const std::string
& received_data() const { return received_data_
; }
247 bool did_finish() const { return did_finish_
; }
248 const blink::WebURLError
& error() const { return error_
; }
251 scoped_ptr
<WebURLLoaderImpl
> loader_
;
253 bool expect_multipart_response_
;
255 bool delete_on_receive_redirect_
;
256 bool delete_on_receive_response_
;
257 bool delete_on_receive_data_
;
258 bool delete_on_finish_
;
259 bool delete_on_fail_
;
261 bool did_receive_redirect_
;
262 bool did_receive_response_
;
263 std::string received_data_
;
265 blink::WebURLError error_
;
267 DISALLOW_COPY_AND_ASSIGN(TestWebURLLoaderClient
);
270 class WebURLLoaderImplTest
: public testing::Test
{
272 explicit WebURLLoaderImplTest() : client_(&dispatcher_
) {}
273 virtual ~WebURLLoaderImplTest() {}
275 void DoStartAsyncRequest() {
276 blink::WebURLRequest request
;
277 request
.initialize();
278 request
.setURL(GURL(kTestURL
));
279 client()->loader()->loadAsynchronously(request
, client());
280 ASSERT_TRUE(bridge());
284 void DoReceiveRedirect() {
285 EXPECT_FALSE(client()->did_receive_redirect());
286 net::RedirectInfo redirect_info
;
287 redirect_info
.status_code
= 302;
288 redirect_info
.new_method
= "GET";
289 redirect_info
.new_url
= GURL(kTestURL
);
290 redirect_info
.new_first_party_for_cookies
= GURL(kTestURL
);
291 peer()->OnReceivedRedirect(redirect_info
,
292 content::ResourceResponseInfo());
293 EXPECT_TRUE(client()->did_receive_redirect());
296 void DoReceiveResponse() {
297 EXPECT_FALSE(client()->did_receive_response());
298 peer()->OnReceivedResponse(content::ResourceResponseInfo());
299 EXPECT_TRUE(client()->did_receive_response());
302 // Assumes it is called only once for a request.
303 void DoReceiveData() {
304 EXPECT_EQ("", client()->received_data());
305 peer()->OnReceivedData(kTestData
, strlen(kTestData
), strlen(kTestData
));
306 EXPECT_EQ(kTestData
, client()->received_data());
309 void DoCompleteRequest() {
310 EXPECT_FALSE(client()->did_finish());
311 peer()->OnCompletedRequest(net::OK
, false, false, "", base::TimeTicks(),
313 EXPECT_TRUE(client()->did_finish());
314 // There should be no error.
315 EXPECT_EQ(net::OK
, client()->error().reason
);
316 EXPECT_EQ("", client()->error().domain
.utf8());
319 void DoFailRequest() {
320 EXPECT_FALSE(client()->did_finish());
321 peer()->OnCompletedRequest(net::ERR_FAILED
, false, false, "",
322 base::TimeTicks(), strlen(kTestData
));
323 EXPECT_FALSE(client()->did_finish());
324 EXPECT_EQ(net::ERR_FAILED
, client()->error().reason
);
325 EXPECT_EQ(net::kErrorDomain
, client()->error().domain
.utf8());
328 void DoReceiveResponseFtp() {
329 EXPECT_FALSE(client()->did_receive_response());
330 content::ResourceResponseInfo response_info
;
331 response_info
.mime_type
= kFtpDirMimeType
;
332 peer()->OnReceivedResponse(response_info
);
333 EXPECT_TRUE(client()->did_receive_response());
336 void DoReceiveDataFtp() {
337 peer()->OnReceivedData(kFtpDirListing
, strlen(kFtpDirListing
),
338 strlen(kFtpDirListing
));
339 // The FTP delegate should modify the data the client sees.
340 EXPECT_NE(kFtpDirListing
, client()->received_data());
343 void DoReceiveResponseMultipart() {
344 EXPECT_FALSE(client()->did_receive_response());
345 content::ResourceResponseInfo response_info
;
346 response_info
.headers
= new net::HttpResponseHeaders(
347 net::HttpUtil::AssembleRawHeaders(kMultipartResponseHeaders
,
348 strlen(kMultipartResponseHeaders
)));
349 response_info
.mime_type
= kMultipartResponseMimeType
;
350 peer()->OnReceivedResponse(response_info
);
351 EXPECT_TRUE(client()->did_receive_response());
354 void DoReceiveDataMultipart() {
355 peer()->OnReceivedData(kMultipartResponse
, strlen(kMultipartResponse
),
356 strlen(kMultipartResponse
));
357 // Multipart delegate should modify the data the client sees.
358 EXPECT_NE(kMultipartResponse
, client()->received_data());
361 TestWebURLLoaderClient
* client() { return &client_
; }
362 TestBridge
* bridge() { return dispatcher_
.bridge(); }
363 RequestPeer
* peer() { return bridge()->peer(); }
364 base::MessageLoop
* message_loop() { return &message_loop_
; }
367 TestResourceDispatcher dispatcher_
;
368 TestWebURLLoaderClient client_
;
370 base::MessageLoop message_loop_
;
373 TEST_F(WebURLLoaderImplTest
, Success
) {
374 DoStartAsyncRequest();
378 EXPECT_FALSE(bridge()->canceled());
379 EXPECT_EQ(kTestData
, client()->received_data());
382 TEST_F(WebURLLoaderImplTest
, Redirect
) {
383 DoStartAsyncRequest();
388 EXPECT_FALSE(bridge()->canceled());
389 EXPECT_EQ(kTestData
, client()->received_data());
392 TEST_F(WebURLLoaderImplTest
, Failure
) {
393 DoStartAsyncRequest();
397 EXPECT_FALSE(bridge()->canceled());
400 // The client may delete the WebURLLoader during any callback from the loader.
401 // These tests make sure that doesn't result in a crash.
402 TEST_F(WebURLLoaderImplTest
, DeleteOnReceiveRedirect
) {
403 client()->set_delete_on_receive_redirect();
404 DoStartAsyncRequest();
406 EXPECT_FALSE(bridge());
409 TEST_F(WebURLLoaderImplTest
, DeleteOnReceiveResponse
) {
410 client()->set_delete_on_receive_response();
411 DoStartAsyncRequest();
413 EXPECT_FALSE(bridge());
416 TEST_F(WebURLLoaderImplTest
, DeleteOnReceiveData
) {
417 client()->set_delete_on_receive_data();
418 DoStartAsyncRequest();
421 EXPECT_FALSE(bridge());
424 TEST_F(WebURLLoaderImplTest
, DeleteOnFinish
) {
425 client()->set_delete_on_finish();
426 DoStartAsyncRequest();
430 EXPECT_FALSE(bridge());
433 TEST_F(WebURLLoaderImplTest
, DeleteOnFail
) {
434 client()->set_delete_on_fail();
435 DoStartAsyncRequest();
439 EXPECT_FALSE(bridge());
442 TEST_F(WebURLLoaderImplTest
, DeleteBeforeResponseDataURL
) {
443 blink::WebURLRequest request
;
444 request
.initialize();
445 request
.setURL(GURL("data:text/html;charset=utf-8,blah!"));
446 client()->loader()->loadAsynchronously(request
, client());
447 client()->DeleteLoader();
448 message_loop()->RunUntilIdle();
449 EXPECT_FALSE(client()->did_receive_response());
450 EXPECT_FALSE(bridge());
455 TEST_F(WebURLLoaderImplTest
, DataURL
) {
456 blink::WebURLRequest request
;
457 request
.initialize();
458 request
.setURL(GURL("data:text/html;charset=utf-8,blah!"));
459 client()->loader()->loadAsynchronously(request
, client());
460 message_loop()->RunUntilIdle();
461 EXPECT_EQ("blah!", client()->received_data());
462 EXPECT_TRUE(client()->did_finish());
463 EXPECT_EQ(net::OK
, client()->error().reason
);
464 EXPECT_EQ("", client()->error().domain
.utf8());
467 TEST_F(WebURLLoaderImplTest
, DataURLDeleteOnReceiveResponse
) {
468 blink::WebURLRequest request
;
469 request
.initialize();
470 request
.setURL(GURL("data:text/html;charset=utf-8,blah!"));
471 client()->set_delete_on_receive_response();
472 client()->loader()->loadAsynchronously(request
, client());
473 message_loop()->RunUntilIdle();
474 EXPECT_TRUE(client()->did_receive_response());
475 EXPECT_EQ("", client()->received_data());
476 EXPECT_FALSE(client()->did_finish());
477 EXPECT_FALSE(bridge());
480 TEST_F(WebURLLoaderImplTest
, DataURLDeleteOnReceiveData
) {
481 blink::WebURLRequest request
;
482 request
.initialize();
483 request
.setURL(GURL("data:text/html;charset=utf-8,blah!"));
484 client()->set_delete_on_receive_data();
485 client()->loader()->loadAsynchronously(request
, client());
486 message_loop()->RunUntilIdle();
487 EXPECT_TRUE(client()->did_receive_response());
488 EXPECT_EQ("blah!", client()->received_data());
489 EXPECT_FALSE(client()->did_finish());
490 EXPECT_FALSE(bridge());
493 TEST_F(WebURLLoaderImplTest
, DataURLDeleteOnFinisha
) {
494 blink::WebURLRequest request
;
495 request
.initialize();
496 request
.setURL(GURL("data:text/html;charset=utf-8,blah!"));
497 client()->set_delete_on_finish();
498 client()->loader()->loadAsynchronously(request
, client());
499 message_loop()->RunUntilIdle();
500 EXPECT_TRUE(client()->did_receive_response());
501 EXPECT_EQ("blah!", client()->received_data());
502 EXPECT_TRUE(client()->did_finish());
503 EXPECT_FALSE(bridge());
506 // FTP integration tests. These are focused more on safe deletion than correct
507 // parsing of FTP responses.
509 TEST_F(WebURLLoaderImplTest
, Ftp
) {
510 DoStartAsyncRequest();
511 DoReceiveResponseFtp();
514 EXPECT_FALSE(bridge()->canceled());
517 TEST_F(WebURLLoaderImplTest
, FtpDeleteOnReceiveResponse
) {
518 client()->set_delete_on_receive_response();
519 DoStartAsyncRequest();
520 DoReceiveResponseFtp();
522 // No data should have been received.
523 EXPECT_EQ("", client()->received_data());
524 EXPECT_FALSE(bridge());
527 TEST_F(WebURLLoaderImplTest
, FtpDeleteOnReceiveFirstData
) {
528 client()->set_delete_on_receive_data();
529 DoStartAsyncRequest();
530 // Some data is sent in ReceiveResponse for FTP requests, so the bridge should
532 DoReceiveResponseFtp();
534 EXPECT_NE("", client()->received_data());
535 EXPECT_FALSE(bridge());
538 TEST_F(WebURLLoaderImplTest
, FtpDeleteOnReceiveMoreData
) {
539 DoStartAsyncRequest();
540 DoReceiveResponseFtp();
543 // Directory listings are only parsed once the request completes, so this will
544 // cancel in DoReceiveDataFtp, before the request finishes.
545 client()->set_delete_on_receive_data();
546 peer()->OnCompletedRequest(net::OK
, false, false, "", base::TimeTicks(),
548 EXPECT_FALSE(client()->did_finish());
550 EXPECT_FALSE(bridge());
553 TEST_F(WebURLLoaderImplTest
, FtpDeleteOnFinish
) {
554 client()->set_delete_on_finish();
555 DoStartAsyncRequest();
556 DoReceiveResponseFtp();
559 EXPECT_FALSE(bridge());
562 TEST_F(WebURLLoaderImplTest
, FtpDeleteOnFail
) {
563 client()->set_delete_on_fail();
564 DoStartAsyncRequest();
565 DoReceiveResponseFtp();
568 EXPECT_FALSE(bridge());
571 // Multipart integration tests. These are focused more on safe deletion than
572 // correct parsing of Multipart responses.
574 TEST_F(WebURLLoaderImplTest
, Multipart
) {
575 client()->set_expect_multipart_response();
576 DoStartAsyncRequest();
577 DoReceiveResponseMultipart();
578 DoReceiveDataMultipart();
580 EXPECT_EQ(kTestData
, client()->received_data());
581 EXPECT_FALSE(bridge()->canceled());
584 TEST_F(WebURLLoaderImplTest
, MultipartDeleteOnReceiveFirstResponse
) {
585 client()->set_expect_multipart_response();
586 client()->set_delete_on_receive_response();
587 DoStartAsyncRequest();
588 DoReceiveResponseMultipart();
589 EXPECT_EQ("", client()->received_data());
590 EXPECT_FALSE(bridge());
593 TEST_F(WebURLLoaderImplTest
, MultipartDeleteOnReceiveSecondResponse
) {
594 client()->set_expect_multipart_response();
595 DoStartAsyncRequest();
596 DoReceiveResponseMultipart();
597 client()->set_delete_on_receive_response();
598 DoReceiveDataMultipart();
599 EXPECT_EQ("", client()->received_data());
600 EXPECT_FALSE(bridge());
603 TEST_F(WebURLLoaderImplTest
, MultipartDeleteOnReceiveFirstData
) {
604 client()->set_expect_multipart_response();
605 client()->set_delete_on_receive_data();
606 DoStartAsyncRequest();
607 DoReceiveResponseMultipart();
608 DoReceiveDataMultipart();
609 EXPECT_EQ("bl", client()->received_data());
610 EXPECT_FALSE(bridge());
613 TEST_F(WebURLLoaderImplTest
, MultipartDeleteOnReceiveMoreData
) {
614 client()->set_expect_multipart_response();
615 DoStartAsyncRequest();
616 DoReceiveResponseMultipart();
617 DoReceiveDataMultipart();
618 // For multipart responses, the delegate may send some data when notified
619 // of a request completing.
620 client()->set_delete_on_receive_data();
621 peer()->OnCompletedRequest(net::OK
, false, false, "", base::TimeTicks(),
623 EXPECT_FALSE(client()->did_finish());
624 EXPECT_EQ(kTestData
, client()->received_data());
625 EXPECT_FALSE(bridge());
628 TEST_F(WebURLLoaderImplTest
, MultipartDeleteFinish
) {
629 client()->set_expect_multipart_response();
630 client()->set_delete_on_finish();
631 DoStartAsyncRequest();
632 DoReceiveResponseMultipart();
633 DoReceiveDataMultipart();
635 EXPECT_EQ(kTestData
, client()->received_data());
636 EXPECT_FALSE(bridge());
639 TEST_F(WebURLLoaderImplTest
, MultipartDeleteFail
) {
640 client()->set_expect_multipart_response();
641 client()->set_delete_on_fail();
642 DoStartAsyncRequest();
643 DoReceiveResponseMultipart();
644 DoReceiveDataMultipart();
646 EXPECT_FALSE(bridge());
650 } // namespace content