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 "content/child/resource_dispatcher.h"
13 #include "content/public/child/request_peer.h"
14 #include "content/public/common/resource_response_info.h"
15 #include "net/base/net_errors.h"
16 #include "net/http/http_response_headers.h"
17 #include "net/http/http_util.h"
18 #include "net/url_request/redirect_info.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "third_party/WebKit/public/platform/WebString.h"
21 #include "third_party/WebKit/public/platform/WebURLError.h"
22 #include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
23 #include "third_party/WebKit/public/platform/WebURLRequest.h"
25 #include "webkit/child/resource_loader_bridge.h"
30 const char kTestURL[] = "http://foo";
31 const char kTestData[] = "blah!";
33 const char kFtpDirMimeType[] = "text/vnd.chromium.ftp-dir";
34 // Simple FTP directory listing. Tests are not concerned with correct parsing,
35 // but rather correct cleanup when deleted while parsing. Important details of
36 // this list are that it contains more than one entry that are not "." or "..".
37 const char kFtpDirListing[] =
38 "drwxr-xr-x 3 ftp ftp 4096 May 15 18:11 goat\n"
39 "drwxr-xr-x 3 ftp ftp 4096 May 15 18:11 hat";
41 const char kMultipartResponseMimeType[] = "multipart/x-mixed-replace";
42 const char kMultipartResponseHeaders[] =
43 "HTTP/1.0 200 Peachy\r\n"
44 "Content-Type: multipart/x-mixed-replace; boundary=boundary\r\n\r\n";
45 // Simple multipart response. Imporant details for the tests are that it
46 // contains multiple chunks, and that it doesn't end with a boundary, so will
47 // send data in OnResponseComplete. Also, it will resolve to kTestData.
48 const char kMultipartResponse[] =
50 "Content-type: text/html\n\n"
53 "Content-type: text/html\n\n"
56 class TestBridge : public webkit_glue::ResourceLoaderBridge,
57 public base::SupportsWeakPtr<TestBridge> {
59 TestBridge() : peer_(NULL), canceled_(false) {}
60 virtual ~TestBridge() {}
62 // ResourceLoaderBridge implementation:
63 virtual void SetRequestBody(ResourceRequestBody* request_body) OVERRIDE {}
65 virtual bool Start(RequestPeer* peer) OVERRIDE {
71 virtual void Cancel() OVERRIDE {
72 EXPECT_FALSE(canceled_);
76 virtual void SetDefersLoading(bool value) OVERRIDE {}
78 virtual void DidChangePriority(net::RequestPriority new_priority,
79 int intra_priority_value) OVERRIDE {}
81 virtual bool AttachThreadedDataReceiver(
82 blink::WebThreadedDataReceiver* threaded_data_receiver) OVERRIDE {
87 virtual void SyncLoad(SyncLoadResponse* response) OVERRIDE {}
89 RequestPeer* peer() { return peer_; }
91 bool canceled() { return canceled_; }
97 DISALLOW_COPY_AND_ASSIGN(TestBridge);
100 class TestResourceDispatcher : public ResourceDispatcher {
102 TestResourceDispatcher() : ResourceDispatcher(NULL) {}
103 virtual ~TestResourceDispatcher() {}
105 // ResourceDispatcher implementation:
106 virtual webkit_glue::ResourceLoaderBridge* CreateBridge(
107 const RequestInfo& request_info) OVERRIDE {
108 EXPECT_FALSE(bridge_.get());
109 TestBridge* bridge = new TestBridge();
110 bridge_ = bridge->AsWeakPtr();
114 TestBridge* bridge() { return bridge_.get(); }
117 base::WeakPtr<TestBridge> bridge_;
119 DISALLOW_COPY_AND_ASSIGN(TestResourceDispatcher);
122 class TestWebURLLoaderClient : public blink::WebURLLoaderClient {
124 TestWebURLLoaderClient(ResourceDispatcher* dispatcher)
125 : loader_(new WebURLLoaderImpl(dispatcher)),
126 expect_multipart_response_(false),
127 delete_on_receive_redirect_(false),
128 delete_on_receive_response_(false),
129 delete_on_receive_data_(false),
130 delete_on_finish_(false),
131 delete_on_fail_(false),
132 did_receive_redirect_(false),
133 did_receive_response_(false),
137 virtual ~TestWebURLLoaderClient() {}
139 // blink::WebURLLoaderClient implementation:
140 virtual void willSendRequest(
141 blink::WebURLLoader* loader,
142 blink::WebURLRequest& newRequest,
143 const blink::WebURLResponse& redirectResponse) OVERRIDE {
144 EXPECT_TRUE(loader_);
145 EXPECT_EQ(loader_.get(), loader);
146 // No test currently simulates mutiple redirects.
147 EXPECT_FALSE(did_receive_redirect_);
148 did_receive_redirect_ = true;
150 if (delete_on_receive_redirect_)
154 virtual void didSendData(blink::WebURLLoader* loader,
155 unsigned long long bytesSent,
156 unsigned long long totalBytesToBeSent) OVERRIDE {
157 EXPECT_TRUE(loader_);
158 EXPECT_EQ(loader_.get(), loader);
161 virtual void didReceiveResponse(
162 blink::WebURLLoader* loader,
163 const blink::WebURLResponse& response) OVERRIDE {
164 EXPECT_TRUE(loader_);
165 EXPECT_EQ(loader_.get(), loader);
167 // Only multipart requests may receive multiple response headers.
168 EXPECT_TRUE(expect_multipart_response_ || !did_receive_response_);
170 did_receive_response_ = true;
171 if (delete_on_receive_response_)
175 virtual void didDownloadData(blink::WebURLLoader* loader,
177 int encodedDataLength) OVERRIDE {
178 EXPECT_TRUE(loader_);
179 EXPECT_EQ(loader_.get(), loader);
182 virtual void didReceiveData(blink::WebURLLoader* loader,
185 int encodedDataLength) OVERRIDE {
186 EXPECT_TRUE(loader_);
187 EXPECT_EQ(loader_.get(), loader);
188 // The response should have started, but must not have finished, or failed.
189 EXPECT_TRUE(did_receive_response_);
190 EXPECT_FALSE(did_finish_);
191 EXPECT_EQ(net::OK, error_.reason);
192 EXPECT_EQ("", error_.domain.utf8());
194 received_data_.append(data, dataLength);
196 if (delete_on_receive_data_)
200 virtual void didReceiveCachedMetadata(blink::WebURLLoader* loader,
202 int dataLength) OVERRIDE {
203 EXPECT_EQ(loader_.get(), loader);
206 virtual void didFinishLoading(blink::WebURLLoader* loader,
208 int64_t totalEncodedDataLength) OVERRIDE {
209 EXPECT_TRUE(loader_);
210 EXPECT_EQ(loader_.get(), loader);
211 EXPECT_TRUE(did_receive_response_);
212 EXPECT_FALSE(did_finish_);
215 if (delete_on_finish_)
219 virtual void didFail(blink::WebURLLoader* loader,
220 const blink::WebURLError& error) OVERRIDE {
221 EXPECT_TRUE(loader_);
222 EXPECT_EQ(loader_.get(), loader);
223 EXPECT_FALSE(did_finish_);
230 WebURLLoaderImpl* loader() { return loader_.get(); }
231 void DeleteLoader() {
235 void set_expect_multipart_response() { expect_multipart_response_ = true; }
237 void set_delete_on_receive_redirect() { delete_on_receive_redirect_ = true; }
238 void set_delete_on_receive_response() { delete_on_receive_response_ = true; }
239 void set_delete_on_receive_data() { delete_on_receive_data_ = true; }
240 void set_delete_on_finish() { delete_on_finish_ = true; }
241 void set_delete_on_fail() { delete_on_fail_ = true; }
243 bool did_receive_redirect() const { return did_receive_redirect_; }
244 bool did_receive_response() const { return did_receive_response_; }
245 const std::string& received_data() const { return received_data_; }
246 bool did_finish() const { return did_finish_; }
247 const blink::WebURLError& error() const { return error_; }
250 scoped_ptr<WebURLLoaderImpl> loader_;
252 bool expect_multipart_response_;
254 bool delete_on_receive_redirect_;
255 bool delete_on_receive_response_;
256 bool delete_on_receive_data_;
257 bool delete_on_finish_;
258 bool delete_on_fail_;
260 bool did_receive_redirect_;
261 bool did_receive_response_;
262 std::string received_data_;
264 blink::WebURLError error_;
266 DISALLOW_COPY_AND_ASSIGN(TestWebURLLoaderClient);
269 class WebURLLoaderImplTest : public testing::Test {
271 explicit WebURLLoaderImplTest() : client_(&dispatcher_) {}
272 virtual ~WebURLLoaderImplTest() {}
274 void DoStartAsyncRequest() {
275 blink::WebURLRequest request;
276 request.initialize();
277 request.setURL(GURL(kTestURL));
278 client()->loader()->loadAsynchronously(request, client());
279 ASSERT_TRUE(bridge());
283 void DoReceiveRedirect() {
284 EXPECT_FALSE(client()->did_receive_redirect());
285 net::RedirectInfo redirect_info;
286 redirect_info.status_code = 302;
287 redirect_info.new_method = "GET";
288 redirect_info.new_url = GURL(kTestURL);
289 redirect_info.new_first_party_for_cookies = GURL(kTestURL);
290 peer()->OnReceivedRedirect(redirect_info,
291 content::ResourceResponseInfo());
292 EXPECT_TRUE(client()->did_receive_redirect());
295 void DoReceiveResponse() {
296 EXPECT_FALSE(client()->did_receive_response());
297 peer()->OnReceivedResponse(content::ResourceResponseInfo());
298 EXPECT_TRUE(client()->did_receive_response());
301 // Assumes it is called only once for a request.
302 void DoReceiveData() {
303 EXPECT_EQ("", client()->received_data());
304 peer()->OnReceivedData(kTestData, strlen(kTestData), strlen(kTestData));
305 EXPECT_EQ(kTestData, client()->received_data());
308 void DoCompleteRequest() {
309 EXPECT_FALSE(client()->did_finish());
310 peer()->OnCompletedRequest(net::OK, false, false, "", base::TimeTicks(),
312 EXPECT_TRUE(client()->did_finish());
313 // There should be no error.
314 EXPECT_EQ(net::OK, client()->error().reason);
315 EXPECT_EQ("", client()->error().domain.utf8());
318 void DoFailRequest() {
319 EXPECT_FALSE(client()->did_finish());
320 peer()->OnCompletedRequest(net::ERR_FAILED, false, false, "",
321 base::TimeTicks(), strlen(kTestData));
322 EXPECT_FALSE(client()->did_finish());
323 EXPECT_EQ(net::ERR_FAILED, client()->error().reason);
324 EXPECT_EQ(net::kErrorDomain, client()->error().domain.utf8());
327 void DoReceiveResponseFtp() {
328 EXPECT_FALSE(client()->did_receive_response());
329 content::ResourceResponseInfo response_info;
330 response_info.mime_type = kFtpDirMimeType;
331 peer()->OnReceivedResponse(response_info);
332 EXPECT_TRUE(client()->did_receive_response());
335 void DoReceiveDataFtp() {
336 peer()->OnReceivedData(kFtpDirListing, strlen(kFtpDirListing),
337 strlen(kFtpDirListing));
338 // The FTP delegate should modify the data the client sees.
339 EXPECT_NE(kFtpDirListing, client()->received_data());
342 void DoReceiveResponseMultipart() {
343 EXPECT_FALSE(client()->did_receive_response());
344 content::ResourceResponseInfo response_info;
345 response_info.headers = new net::HttpResponseHeaders(
346 net::HttpUtil::AssembleRawHeaders(kMultipartResponseHeaders,
347 strlen(kMultipartResponseHeaders)));
348 response_info.mime_type = kMultipartResponseMimeType;
349 peer()->OnReceivedResponse(response_info);
350 EXPECT_TRUE(client()->did_receive_response());
353 void DoReceiveDataMultipart() {
354 peer()->OnReceivedData(kMultipartResponse, strlen(kMultipartResponse),
355 strlen(kMultipartResponse));
356 // Multipart delegate should modify the data the client sees.
357 EXPECT_NE(kMultipartResponse, client()->received_data());
360 TestWebURLLoaderClient* client() { return &client_; }
361 TestBridge* bridge() { return dispatcher_.bridge(); }
362 RequestPeer* peer() { return bridge()->peer(); }
363 base::MessageLoop* message_loop() { return &message_loop_; }
366 TestResourceDispatcher dispatcher_;
367 TestWebURLLoaderClient client_;
369 base::MessageLoop message_loop_;
372 TEST_F(WebURLLoaderImplTest, Success) {
373 DoStartAsyncRequest();
377 EXPECT_FALSE(bridge()->canceled());
378 EXPECT_EQ(kTestData, client()->received_data());
381 TEST_F(WebURLLoaderImplTest, Redirect) {
382 DoStartAsyncRequest();
387 EXPECT_FALSE(bridge()->canceled());
388 EXPECT_EQ(kTestData, client()->received_data());
391 TEST_F(WebURLLoaderImplTest, Failure) {
392 DoStartAsyncRequest();
396 EXPECT_FALSE(bridge()->canceled());
399 // The client may delete the WebURLLoader during any callback from the loader.
400 // These tests make sure that doesn't result in a crash.
401 TEST_F(WebURLLoaderImplTest, DeleteOnReceiveRedirect) {
402 client()->set_delete_on_receive_redirect();
403 DoStartAsyncRequest();
405 EXPECT_FALSE(bridge());
408 TEST_F(WebURLLoaderImplTest, DeleteOnReceiveResponse) {
409 client()->set_delete_on_receive_response();
410 DoStartAsyncRequest();
412 EXPECT_FALSE(bridge());
415 TEST_F(WebURLLoaderImplTest, DeleteOnReceiveData) {
416 client()->set_delete_on_receive_data();
417 DoStartAsyncRequest();
420 EXPECT_FALSE(bridge());
423 TEST_F(WebURLLoaderImplTest, DeleteOnFinish) {
424 client()->set_delete_on_finish();
425 DoStartAsyncRequest();
429 EXPECT_FALSE(bridge());
432 TEST_F(WebURLLoaderImplTest, DeleteOnFail) {
433 client()->set_delete_on_fail();
434 DoStartAsyncRequest();
438 EXPECT_FALSE(bridge());
441 TEST_F(WebURLLoaderImplTest, DeleteBeforeResponseDataURL) {
442 blink::WebURLRequest request;
443 request.initialize();
444 request.setURL(GURL("data:text/html;charset=utf-8,blah!"));
445 client()->loader()->loadAsynchronously(request, client());
446 client()->DeleteLoader();
447 message_loop()->RunUntilIdle();
448 EXPECT_FALSE(client()->did_receive_response());
449 EXPECT_FALSE(bridge());
454 TEST_F(WebURLLoaderImplTest, DataURL) {
455 blink::WebURLRequest request;
456 request.initialize();
457 request.setURL(GURL("data:text/html;charset=utf-8,blah!"));
458 client()->loader()->loadAsynchronously(request, client());
459 message_loop()->RunUntilIdle();
460 EXPECT_EQ("blah!", client()->received_data());
461 EXPECT_TRUE(client()->did_finish());
462 EXPECT_EQ(net::OK, client()->error().reason);
463 EXPECT_EQ("", client()->error().domain.utf8());
466 TEST_F(WebURLLoaderImplTest, DataURLDeleteOnReceiveResponse) {
467 blink::WebURLRequest request;
468 request.initialize();
469 request.setURL(GURL("data:text/html;charset=utf-8,blah!"));
470 client()->set_delete_on_receive_response();
471 client()->loader()->loadAsynchronously(request, client());
472 message_loop()->RunUntilIdle();
473 EXPECT_TRUE(client()->did_receive_response());
474 EXPECT_EQ("", client()->received_data());
475 EXPECT_FALSE(client()->did_finish());
476 EXPECT_FALSE(bridge());
479 TEST_F(WebURLLoaderImplTest, DataURLDeleteOnReceiveData) {
480 blink::WebURLRequest request;
481 request.initialize();
482 request.setURL(GURL("data:text/html;charset=utf-8,blah!"));
483 client()->set_delete_on_receive_data();
484 client()->loader()->loadAsynchronously(request, client());
485 message_loop()->RunUntilIdle();
486 EXPECT_TRUE(client()->did_receive_response());
487 EXPECT_EQ("blah!", client()->received_data());
488 EXPECT_FALSE(client()->did_finish());
489 EXPECT_FALSE(bridge());
492 TEST_F(WebURLLoaderImplTest, DataURLDeleteOnFinisha) {
493 blink::WebURLRequest request;
494 request.initialize();
495 request.setURL(GURL("data:text/html;charset=utf-8,blah!"));
496 client()->set_delete_on_finish();
497 client()->loader()->loadAsynchronously(request, client());
498 message_loop()->RunUntilIdle();
499 EXPECT_TRUE(client()->did_receive_response());
500 EXPECT_EQ("blah!", client()->received_data());
501 EXPECT_TRUE(client()->did_finish());
502 EXPECT_FALSE(bridge());
505 // FTP integration tests. These are focused more on safe deletion than correct
506 // parsing of FTP responses.
508 TEST_F(WebURLLoaderImplTest, Ftp) {
509 DoStartAsyncRequest();
510 DoReceiveResponseFtp();
513 EXPECT_FALSE(bridge()->canceled());
516 TEST_F(WebURLLoaderImplTest, FtpDeleteOnReceiveResponse) {
517 client()->set_delete_on_receive_response();
518 DoStartAsyncRequest();
519 DoReceiveResponseFtp();
521 // No data should have been received.
522 EXPECT_EQ("", client()->received_data());
523 EXPECT_FALSE(bridge());
526 TEST_F(WebURLLoaderImplTest, FtpDeleteOnReceiveFirstData) {
527 client()->set_delete_on_receive_data();
528 DoStartAsyncRequest();
529 // Some data is sent in ReceiveResponse for FTP requests, so the bridge should
531 DoReceiveResponseFtp();
533 EXPECT_NE("", client()->received_data());
534 EXPECT_FALSE(bridge());
537 TEST_F(WebURLLoaderImplTest, FtpDeleteOnReceiveMoreData) {
538 DoStartAsyncRequest();
539 DoReceiveResponseFtp();
542 // Directory listings are only parsed once the request completes, so this will
543 // cancel in DoReceiveDataFtp, before the request finishes.
544 client()->set_delete_on_receive_data();
545 peer()->OnCompletedRequest(net::OK, false, false, "", base::TimeTicks(),
547 EXPECT_FALSE(client()->did_finish());
549 EXPECT_FALSE(bridge());
552 TEST_F(WebURLLoaderImplTest, FtpDeleteOnFinish) {
553 client()->set_delete_on_finish();
554 DoStartAsyncRequest();
555 DoReceiveResponseFtp();
558 EXPECT_FALSE(bridge());
561 TEST_F(WebURLLoaderImplTest, FtpDeleteOnFail) {
562 client()->set_delete_on_fail();
563 DoStartAsyncRequest();
564 DoReceiveResponseFtp();
567 EXPECT_FALSE(bridge());
570 // Multipart integration tests. These are focused more on safe deletion than
571 // correct parsing of Multipart responses.
573 TEST_F(WebURLLoaderImplTest, Multipart) {
574 client()->set_expect_multipart_response();
575 DoStartAsyncRequest();
576 DoReceiveResponseMultipart();
577 DoReceiveDataMultipart();
579 EXPECT_EQ(kTestData, client()->received_data());
580 EXPECT_FALSE(bridge()->canceled());
583 TEST_F(WebURLLoaderImplTest, MultipartDeleteOnReceiveFirstResponse) {
584 client()->set_expect_multipart_response();
585 client()->set_delete_on_receive_response();
586 DoStartAsyncRequest();
587 DoReceiveResponseMultipart();
588 EXPECT_EQ("", client()->received_data());
589 EXPECT_FALSE(bridge());
592 TEST_F(WebURLLoaderImplTest, MultipartDeleteOnReceiveSecondResponse) {
593 client()->set_expect_multipart_response();
594 DoStartAsyncRequest();
595 DoReceiveResponseMultipart();
596 client()->set_delete_on_receive_response();
597 DoReceiveDataMultipart();
598 EXPECT_EQ("", client()->received_data());
599 EXPECT_FALSE(bridge());
602 TEST_F(WebURLLoaderImplTest, MultipartDeleteOnReceiveFirstData) {
603 client()->set_expect_multipart_response();
604 client()->set_delete_on_receive_data();
605 DoStartAsyncRequest();
606 DoReceiveResponseMultipart();
607 DoReceiveDataMultipart();
608 EXPECT_EQ("bl", client()->received_data());
609 EXPECT_FALSE(bridge());
612 TEST_F(WebURLLoaderImplTest, MultipartDeleteOnReceiveMoreData) {
613 client()->set_expect_multipart_response();
614 DoStartAsyncRequest();
615 DoReceiveResponseMultipart();
616 DoReceiveDataMultipart();
617 // For multipart responses, the delegate may send some data when notified
618 // of a request completing.
619 client()->set_delete_on_receive_data();
620 peer()->OnCompletedRequest(net::OK, false, false, "", base::TimeTicks(),
622 EXPECT_FALSE(client()->did_finish());
623 EXPECT_EQ(kTestData, client()->received_data());
624 EXPECT_FALSE(bridge());
627 TEST_F(WebURLLoaderImplTest, MultipartDeleteFinish) {
628 client()->set_expect_multipart_response();
629 client()->set_delete_on_finish();
630 DoStartAsyncRequest();
631 DoReceiveResponseMultipart();
632 DoReceiveDataMultipart();
634 EXPECT_EQ(kTestData, client()->received_data());
635 EXPECT_FALSE(bridge());
638 TEST_F(WebURLLoaderImplTest, MultipartDeleteFail) {
639 client()->set_expect_multipart_response();
640 client()->set_delete_on_fail();
641 DoStartAsyncRequest();
642 DoReceiveResponseMultipart();
643 DoReceiveDataMultipart();
645 EXPECT_FALSE(bridge());
649 } // namespace content