| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/child/web_url_loader_impl.h" |
| |
| #include <stdint.h> |
| #include <string.h> |
| |
| #include <utility> |
| #include <vector> |
| |
| #include "base/command_line.h" |
| #include "base/macros.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/run_loop.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/time/default_tick_clock.h" |
| #include "base/time/time.h" |
| #include "content/child/request_extra_data.h" |
| #include "content/child/resource_dispatcher.h" |
| #include "content/child/sync_load_response.h" |
| #include "content/public/child/fixed_received_data.h" |
| #include "content/public/child/request_peer.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/common/resource_response_info.h" |
| #include "net/base/host_port_pair.h" |
| #include "net/base/net_errors.h" |
| #include "net/http/http_response_headers.h" |
| #include "net/http/http_util.h" |
| #include "net/url_request/redirect_info.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/WebKit/public/platform/WebString.h" |
| #include "third_party/WebKit/public/platform/WebURLError.h" |
| #include "third_party/WebKit/public/platform/WebURLLoaderClient.h" |
| #include "third_party/WebKit/public/platform/WebURLRequest.h" |
| #include "third_party/WebKit/public/platform/WebURLResponse.h" |
| #include "url/gurl.h" |
| |
| namespace content { |
| namespace { |
| |
| const char kTestURL[] = "http://foo"; |
| const char kTestHTTPSURL[] = "https://foo"; |
| const char kTestData[] = "blah!"; |
| |
| const char kFtpDirMimeType[] = "text/vnd.chromium.ftp-dir"; |
| // Simple FTP directory listing. Tests are not concerned with correct parsing, |
| // but rather correct cleanup when deleted while parsing. Important details of |
| // this list are that it contains more than one entry that are not "." or "..". |
| const char kFtpDirListing[] = |
| "drwxr-xr-x 3 ftp ftp 4096 May 15 18:11 goat\n" |
| "drwxr-xr-x 3 ftp ftp 4096 May 15 18:11 hat"; |
| |
| class TestResourceDispatcher : public ResourceDispatcher { |
| public: |
| TestResourceDispatcher() : |
| ResourceDispatcher(nullptr, nullptr), |
| canceled_(false), |
| defers_loading_(false) { |
| } |
| |
| ~TestResourceDispatcher() override {} |
| |
| // TestDispatcher implementation: |
| |
| void StartSync(std::unique_ptr<ResourceRequest> request, |
| int routing_id, |
| SyncLoadResponse* response, |
| blink::WebURLRequest::LoadingIPCType ipc_type, |
| mojom::URLLoaderFactory* url_loader_factory) override { |
| *response = sync_load_response_; |
| } |
| |
| int StartAsync( |
| std::unique_ptr<ResourceRequest> request, |
| int routing_id, |
| scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner, |
| const GURL& frame_origin, |
| std::unique_ptr<RequestPeer> peer, |
| blink::WebURLRequest::LoadingIPCType ipc_type, |
| mojom::URLLoaderFactory* url_loader_factory, |
| mojo::AssociatedGroup* associated_group) override { |
| EXPECT_FALSE(peer_); |
| EXPECT_EQ(blink::WebURLRequest::LoadingIPCType::ChromeIPC, ipc_type); |
| peer_ = std::move(peer); |
| url_ = request->url; |
| stream_url_ = request->resource_body_stream_url; |
| return 1; |
| } |
| |
| void Cancel(int request_id) override { |
| EXPECT_FALSE(canceled_); |
| canceled_ = true; |
| } |
| |
| RequestPeer* peer() { return peer_.get(); } |
| |
| bool canceled() { return canceled_; } |
| |
| const GURL& url() { return url_; } |
| const GURL& stream_url() { return stream_url_; } |
| |
| void SetDefersLoading(int request_id, bool value) override { |
| defers_loading_ = value; |
| } |
| bool defers_loading() const { return defers_loading_; } |
| |
| void set_sync_load_response(const SyncLoadResponse& sync_load_response) { |
| sync_load_response_ = sync_load_response; |
| } |
| |
| private: |
| std::unique_ptr<RequestPeer> peer_; |
| bool canceled_; |
| bool defers_loading_; |
| GURL url_; |
| GURL stream_url_; |
| SyncLoadResponse sync_load_response_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TestResourceDispatcher); |
| }; |
| |
| class TestWebURLLoaderClient : public blink::WebURLLoaderClient { |
| public: |
| TestWebURLLoaderClient(ResourceDispatcher* dispatcher) |
| : loader_(new WebURLLoaderImpl(dispatcher, nullptr, nullptr)), |
| delete_on_receive_redirect_(false), |
| delete_on_receive_response_(false), |
| delete_on_receive_data_(false), |
| delete_on_finish_(false), |
| delete_on_fail_(false), |
| did_receive_redirect_(false), |
| did_receive_response_(false), |
| check_redirect_request_priority_(false), |
| did_finish_(false) {} |
| |
| ~TestWebURLLoaderClient() override {} |
| |
| // blink::WebURLLoaderClient implementation: |
| bool willFollowRedirect( |
| blink::WebURLRequest& newRequest, |
| const blink::WebURLResponse& redirectResponse) override { |
| EXPECT_TRUE(loader_); |
| |
| if (check_redirect_request_priority_) |
| EXPECT_EQ(redirect_request_priority, newRequest.getPriority()); |
| |
| // No test currently simulates mutiple redirects. |
| EXPECT_FALSE(did_receive_redirect_); |
| did_receive_redirect_ = true; |
| |
| if (delete_on_receive_redirect_) |
| loader_.reset(); |
| |
| return true; |
| } |
| |
| void didSendData(unsigned long long bytesSent, |
| unsigned long long totalBytesToBeSent) override { |
| EXPECT_TRUE(loader_); |
| } |
| |
| void didReceiveResponse( |
| const blink::WebURLResponse& response) override { |
| EXPECT_TRUE(loader_); |
| EXPECT_FALSE(did_receive_response_); |
| |
| did_receive_response_ = true; |
| response_ = response; |
| if (delete_on_receive_response_) |
| loader_.reset(); |
| } |
| |
| void didDownloadData(int dataLength, int encodedDataLength) override { |
| EXPECT_TRUE(loader_); |
| } |
| |
| void didReceiveData(const char* data, |
| int dataLength, |
| int encodedDataLength) override { |
| EXPECT_TRUE(loader_); |
| // The response should have started, but must not have finished, or failed. |
| EXPECT_TRUE(did_receive_response_); |
| EXPECT_FALSE(did_finish_); |
| EXPECT_EQ(net::OK, error_.reason); |
| EXPECT_EQ("", error_.domain.utf8()); |
| |
| received_data_.append(data, dataLength); |
| |
| if (delete_on_receive_data_) |
| loader_.reset(); |
| } |
| |
| void didFinishLoading(double finishTime, |
| int64_t totalEncodedDataLength, |
| int64_t totalEncodedBodyLength) override { |
| EXPECT_TRUE(loader_); |
| EXPECT_TRUE(did_receive_response_); |
| EXPECT_FALSE(did_finish_); |
| did_finish_ = true; |
| |
| if (delete_on_finish_) |
| loader_.reset(); |
| } |
| |
| void didFail(const blink::WebURLError& error, |
| int64_t totalEncodedDataLength, |
| int64_t totalEncodedBodyLength) override { |
| EXPECT_TRUE(loader_); |
| EXPECT_FALSE(did_finish_); |
| error_ = error; |
| |
| if (delete_on_fail_) |
| loader_.reset(); |
| } |
| |
| WebURLLoaderImpl* loader() { return loader_.get(); } |
| void DeleteLoader() { |
| loader_.reset(); |
| } |
| |
| void set_delete_on_receive_redirect() { delete_on_receive_redirect_ = true; } |
| void set_delete_on_receive_response() { delete_on_receive_response_ = true; } |
| void set_delete_on_receive_data() { delete_on_receive_data_ = true; } |
| void set_delete_on_finish() { delete_on_finish_ = true; } |
| void set_delete_on_fail() { delete_on_fail_ = true; } |
| void set_redirect_request_priority(blink::WebURLRequest::Priority priority) { |
| check_redirect_request_priority_ = true; |
| redirect_request_priority = priority; |
| } |
| |
| bool did_receive_redirect() const { return did_receive_redirect_; } |
| bool did_receive_response() const { return did_receive_response_; } |
| const std::string& received_data() const { return received_data_; } |
| bool did_finish() const { return did_finish_; } |
| const blink::WebURLError& error() const { return error_; } |
| const blink::WebURLResponse& response() const { return response_; } |
| |
| private: |
| std::unique_ptr<WebURLLoaderImpl> loader_; |
| |
| bool delete_on_receive_redirect_; |
| bool delete_on_receive_response_; |
| bool delete_on_receive_data_; |
| bool delete_on_finish_; |
| bool delete_on_fail_; |
| |
| bool did_receive_redirect_; |
| bool did_receive_response_; |
| bool check_redirect_request_priority_; |
| blink::WebURLRequest::Priority redirect_request_priority; |
| std::string received_data_; |
| bool did_finish_; |
| blink::WebURLError error_; |
| blink::WebURLResponse response_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TestWebURLLoaderClient); |
| }; |
| |
| class WebURLLoaderImplTest : public testing::Test { |
| public: |
| WebURLLoaderImplTest() { |
| client_.reset(new TestWebURLLoaderClient(&dispatcher_)); |
| } |
| |
| ~WebURLLoaderImplTest() override {} |
| |
| void DoStartAsyncRequest() { |
| blink::WebURLRequest request{GURL(kTestURL)}; |
| client()->loader()->loadAsynchronously(request, client()); |
| ASSERT_TRUE(peer()); |
| } |
| |
| void DoStartAsyncRequestWithPriority( |
| blink::WebURLRequest::Priority priority) { |
| blink::WebURLRequest request{GURL(kTestURL)}; |
| request.setPriority(priority); |
| client()->loader()->loadAsynchronously(request, client()); |
| ASSERT_TRUE(peer()); |
| } |
| |
| void DoReceiveRedirect() { |
| EXPECT_FALSE(client()->did_receive_redirect()); |
| net::RedirectInfo redirect_info; |
| redirect_info.status_code = 302; |
| redirect_info.new_method = "GET"; |
| redirect_info.new_url = GURL(kTestURL); |
| redirect_info.new_first_party_for_cookies = GURL(kTestURL); |
| peer()->OnReceivedRedirect(redirect_info, |
| content::ResourceResponseInfo()); |
| EXPECT_TRUE(client()->did_receive_redirect()); |
| } |
| |
| void DoReceiveHTTPSRedirect() { |
| EXPECT_FALSE(client()->did_receive_redirect()); |
| net::RedirectInfo redirect_info; |
| redirect_info.status_code = 302; |
| redirect_info.new_method = "GET"; |
| redirect_info.new_url = GURL(kTestHTTPSURL); |
| redirect_info.new_first_party_for_cookies = GURL(kTestHTTPSURL); |
| peer()->OnReceivedRedirect(redirect_info, |
| content::ResourceResponseInfo()); |
| EXPECT_TRUE(client()->did_receive_redirect()); |
| } |
| |
| void DoReceiveResponse() { |
| EXPECT_FALSE(client()->did_receive_response()); |
| peer()->OnReceivedResponse(content::ResourceResponseInfo()); |
| EXPECT_TRUE(client()->did_receive_response()); |
| } |
| |
| // Assumes it is called only once for a request. |
| void DoReceiveData() { |
| EXPECT_EQ("", client()->received_data()); |
| auto size = strlen(kTestData); |
| peer()->OnReceivedData( |
| base::MakeUnique<FixedReceivedData>(kTestData, size, size)); |
| EXPECT_EQ(kTestData, client()->received_data()); |
| } |
| |
| void DoCompleteRequest() { |
| EXPECT_FALSE(client()->did_finish()); |
| peer()->OnCompletedRequest(net::OK, false, false, base::TimeTicks(), |
| strlen(kTestData), strlen(kTestData)); |
| EXPECT_TRUE(client()->did_finish()); |
| // There should be no error. |
| EXPECT_EQ(net::OK, client()->error().reason); |
| EXPECT_EQ("", client()->error().domain.utf8()); |
| } |
| |
| void DoFailRequest() { |
| EXPECT_FALSE(client()->did_finish()); |
| peer()->OnCompletedRequest(net::ERR_FAILED, false, false, base::TimeTicks(), |
| strlen(kTestData), strlen(kTestData)); |
| EXPECT_FALSE(client()->did_finish()); |
| EXPECT_EQ(net::ERR_FAILED, client()->error().reason); |
| EXPECT_EQ(net::kErrorDomain, client()->error().domain.utf8()); |
| } |
| |
| void DoReceiveResponseFtp() { |
| EXPECT_FALSE(client()->did_receive_response()); |
| content::ResourceResponseInfo response_info; |
| response_info.mime_type = kFtpDirMimeType; |
| peer()->OnReceivedResponse(response_info); |
| EXPECT_TRUE(client()->did_receive_response()); |
| } |
| |
| void DoReceiveDataFtp() { |
| auto size = strlen(kFtpDirListing); |
| peer()->OnReceivedData( |
| base::MakeUnique<FixedReceivedData>(kFtpDirListing, size, size)); |
| // The FTP delegate should modify the data the client sees. |
| EXPECT_NE(kFtpDirListing, client()->received_data()); |
| } |
| |
| TestWebURLLoaderClient* client() { return client_.get(); } |
| TestResourceDispatcher* dispatcher() { return &dispatcher_; } |
| RequestPeer* peer() { return dispatcher()->peer(); } |
| base::MessageLoop* message_loop() { return &message_loop_; } |
| |
| private: |
| base::MessageLoop message_loop_; |
| TestResourceDispatcher dispatcher_; |
| std::unique_ptr<TestWebURLLoaderClient> client_; |
| }; |
| |
| TEST_F(WebURLLoaderImplTest, Success) { |
| DoStartAsyncRequest(); |
| DoReceiveResponse(); |
| DoReceiveData(); |
| DoCompleteRequest(); |
| EXPECT_FALSE(dispatcher()->canceled()); |
| EXPECT_EQ(kTestData, client()->received_data()); |
| } |
| |
| TEST_F(WebURLLoaderImplTest, Redirect) { |
| DoStartAsyncRequest(); |
| DoReceiveRedirect(); |
| DoReceiveResponse(); |
| DoReceiveData(); |
| DoCompleteRequest(); |
| EXPECT_FALSE(dispatcher()->canceled()); |
| EXPECT_EQ(kTestData, client()->received_data()); |
| } |
| |
| TEST_F(WebURLLoaderImplTest, RedirectCorrectPriority) { |
| DoStartAsyncRequestWithPriority( |
| blink::WebURLRequest::Priority::PriorityVeryHigh); |
| client()->set_redirect_request_priority( |
| blink::WebURLRequest::Priority::PriorityVeryHigh); |
| DoReceiveRedirect(); |
| DoReceiveResponse(); |
| DoReceiveData(); |
| DoCompleteRequest(); |
| EXPECT_FALSE(dispatcher()->canceled()); |
| EXPECT_EQ(kTestData, client()->received_data()); |
| } |
| |
| TEST_F(WebURLLoaderImplTest, Failure) { |
| DoStartAsyncRequest(); |
| DoReceiveResponse(); |
| DoReceiveData(); |
| DoFailRequest(); |
| EXPECT_FALSE(dispatcher()->canceled()); |
| } |
| |
| // The client may delete the WebURLLoader during any callback from the loader. |
| // These tests make sure that doesn't result in a crash. |
| TEST_F(WebURLLoaderImplTest, DeleteOnReceiveRedirect) { |
| client()->set_delete_on_receive_redirect(); |
| DoStartAsyncRequest(); |
| DoReceiveRedirect(); |
| } |
| |
| TEST_F(WebURLLoaderImplTest, DeleteOnReceiveResponse) { |
| client()->set_delete_on_receive_response(); |
| DoStartAsyncRequest(); |
| DoReceiveResponse(); |
| } |
| |
| TEST_F(WebURLLoaderImplTest, DeleteOnReceiveData) { |
| client()->set_delete_on_receive_data(); |
| DoStartAsyncRequest(); |
| DoReceiveResponse(); |
| DoReceiveData(); |
| } |
| |
| TEST_F(WebURLLoaderImplTest, DeleteOnFinish) { |
| client()->set_delete_on_finish(); |
| DoStartAsyncRequest(); |
| DoReceiveResponse(); |
| DoReceiveData(); |
| DoCompleteRequest(); |
| } |
| |
| TEST_F(WebURLLoaderImplTest, DeleteOnFail) { |
| client()->set_delete_on_fail(); |
| DoStartAsyncRequest(); |
| DoReceiveResponse(); |
| DoReceiveData(); |
| DoFailRequest(); |
| } |
| |
| TEST_F(WebURLLoaderImplTest, DeleteBeforeResponseDataURL) { |
| blink::WebURLRequest request(GURL("data:text/html;charset=utf-8,blah!")); |
| client()->loader()->loadAsynchronously(request, client()); |
| client()->DeleteLoader(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_FALSE(client()->did_receive_response()); |
| } |
| |
| // Data URL tests. |
| |
| TEST_F(WebURLLoaderImplTest, DataURL) { |
| blink::WebURLRequest request(GURL("data:text/html;charset=utf-8,blah!")); |
| client()->loader()->loadAsynchronously(request, client()); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ("blah!", client()->received_data()); |
| EXPECT_TRUE(client()->did_finish()); |
| EXPECT_EQ(net::OK, client()->error().reason); |
| EXPECT_EQ("", client()->error().domain.utf8()); |
| } |
| |
| TEST_F(WebURLLoaderImplTest, DataURLDeleteOnReceiveResponse) { |
| blink::WebURLRequest request(GURL("data:text/html;charset=utf-8,blah!")); |
| client()->set_delete_on_receive_response(); |
| client()->loader()->loadAsynchronously(request, client()); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_TRUE(client()->did_receive_response()); |
| EXPECT_EQ("", client()->received_data()); |
| EXPECT_FALSE(client()->did_finish()); |
| } |
| |
| TEST_F(WebURLLoaderImplTest, DataURLDeleteOnReceiveData) { |
| blink::WebURLRequest request(GURL("data:text/html;charset=utf-8,blah!")); |
| client()->set_delete_on_receive_data(); |
| client()->loader()->loadAsynchronously(request, client()); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_TRUE(client()->did_receive_response()); |
| EXPECT_EQ("blah!", client()->received_data()); |
| EXPECT_FALSE(client()->did_finish()); |
| } |
| |
| TEST_F(WebURLLoaderImplTest, DataURLDeleteOnFinish) { |
| blink::WebURLRequest request(GURL("data:text/html;charset=utf-8,blah!")); |
| client()->set_delete_on_finish(); |
| client()->loader()->loadAsynchronously(request, client()); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_TRUE(client()->did_receive_response()); |
| EXPECT_EQ("blah!", client()->received_data()); |
| EXPECT_TRUE(client()->did_finish()); |
| } |
| |
| TEST_F(WebURLLoaderImplTest, DataURLDefersLoading) { |
| blink::WebURLRequest request(GURL("data:text/html;charset=utf-8,blah!")); |
| client()->loader()->loadAsynchronously(request, client()); |
| |
| // setDefersLoading() might be called with either false or true in no |
| // specific order. The user of the API will not have sufficient information |
| // about the WebURLLoader's internal state, so the latter gracefully needs to |
| // handle calling setDefersLoading any number of times with any values from |
| // any point in time. |
| |
| client()->loader()->setDefersLoading(false); |
| client()->loader()->setDefersLoading(true); |
| client()->loader()->setDefersLoading(true); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_FALSE(client()->did_finish()); |
| |
| client()->loader()->setDefersLoading(false); |
| client()->loader()->setDefersLoading(true); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_FALSE(client()->did_finish()); |
| |
| client()->loader()->setDefersLoading(false); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_TRUE(client()->did_finish()); |
| |
| client()->loader()->setDefersLoading(true); |
| client()->loader()->setDefersLoading(false); |
| client()->loader()->setDefersLoading(false); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_TRUE(client()->did_finish()); |
| |
| EXPECT_EQ("blah!", client()->received_data()); |
| EXPECT_EQ(net::OK, client()->error().reason); |
| EXPECT_EQ("", client()->error().domain.utf8()); |
| } |
| |
| TEST_F(WebURLLoaderImplTest, DefersLoadingBeforeStart) { |
| client()->loader()->setDefersLoading(true); |
| EXPECT_FALSE(dispatcher()->defers_loading()); |
| DoStartAsyncRequest(); |
| EXPECT_TRUE(dispatcher()->defers_loading()); |
| } |
| |
| // FTP integration tests. These are focused more on safe deletion than correct |
| // parsing of FTP responses. |
| |
| TEST_F(WebURLLoaderImplTest, Ftp) { |
| DoStartAsyncRequest(); |
| DoReceiveResponseFtp(); |
| DoReceiveDataFtp(); |
| DoCompleteRequest(); |
| EXPECT_FALSE(dispatcher()->canceled()); |
| } |
| |
| TEST_F(WebURLLoaderImplTest, FtpDeleteOnReceiveResponse) { |
| client()->set_delete_on_receive_response(); |
| DoStartAsyncRequest(); |
| DoReceiveResponseFtp(); |
| |
| // No data should have been received. |
| EXPECT_EQ("", client()->received_data()); |
| } |
| |
| TEST_F(WebURLLoaderImplTest, FtpDeleteOnReceiveFirstData) { |
| client()->set_delete_on_receive_data(); |
| DoStartAsyncRequest(); |
| DoReceiveResponseFtp(); |
| |
| EXPECT_NE("", client()->received_data()); |
| } |
| |
| TEST_F(WebURLLoaderImplTest, FtpDeleteOnReceiveMoreData) { |
| DoStartAsyncRequest(); |
| DoReceiveResponseFtp(); |
| DoReceiveDataFtp(); |
| |
| // Directory listings are only parsed once the request completes, so this will |
| // cancel in DoReceiveDataFtp, before the request finishes. |
| client()->set_delete_on_receive_data(); |
| peer()->OnCompletedRequest(net::OK, false, false, base::TimeTicks(), |
| strlen(kTestData), strlen(kTestData)); |
| EXPECT_FALSE(client()->did_finish()); |
| } |
| |
| TEST_F(WebURLLoaderImplTest, FtpDeleteOnFinish) { |
| client()->set_delete_on_finish(); |
| DoStartAsyncRequest(); |
| DoReceiveResponseFtp(); |
| DoReceiveDataFtp(); |
| DoCompleteRequest(); |
| } |
| |
| TEST_F(WebURLLoaderImplTest, FtpDeleteOnFail) { |
| client()->set_delete_on_fail(); |
| DoStartAsyncRequest(); |
| DoReceiveResponseFtp(); |
| DoReceiveDataFtp(); |
| DoFailRequest(); |
| } |
| |
| // PlzNavigate: checks that the stream override parameters provided on |
| // navigation commit are properly applied. |
| TEST_F(WebURLLoaderImplTest, BrowserSideNavigationCommit) { |
| // Initialize the request and the stream override. |
| const GURL kNavigationURL = GURL(kTestURL); |
| const GURL kStreamURL = GURL("http://bar"); |
| const std::string kMimeType = "text/html"; |
| blink::WebURLRequest request(kNavigationURL); |
| request.setFrameType(blink::WebURLRequest::FrameTypeTopLevel); |
| request.setRequestContext(blink::WebURLRequest::RequestContextFrame); |
| std::unique_ptr<StreamOverrideParameters> stream_override( |
| new StreamOverrideParameters()); |
| stream_override->stream_url = kStreamURL; |
| stream_override->response.mime_type = kMimeType; |
| RequestExtraData* extra_data = new RequestExtraData(); |
| extra_data->set_stream_override(std::move(stream_override)); |
| request.setExtraData(extra_data); |
| base::CommandLine::ForCurrentProcess()->AppendSwitch( |
| switches::kEnableBrowserSideNavigation); |
| |
| client()->loader()->loadAsynchronously(request, client()); |
| |
| // The stream url should have been added to the ResourceRequest. |
| ASSERT_TRUE(peer()); |
| EXPECT_EQ(kNavigationURL, dispatcher()->url()); |
| EXPECT_EQ(kStreamURL, dispatcher()->stream_url()); |
| |
| EXPECT_FALSE(client()->did_receive_response()); |
| peer()->OnReceivedResponse(content::ResourceResponseInfo()); |
| EXPECT_TRUE(client()->did_receive_response()); |
| |
| // The response info should have been overriden. |
| ASSERT_FALSE(client()->response().isNull()); |
| EXPECT_EQ(kMimeType, client()->response().mimeType().latin1()); |
| |
| DoReceiveData(); |
| DoCompleteRequest(); |
| EXPECT_FALSE(dispatcher()->canceled()); |
| EXPECT_EQ(kTestData, client()->received_data()); |
| } |
| |
| TEST_F(WebURLLoaderImplTest, ResponseIPAddress) { |
| GURL url("http://example.test/"); |
| |
| struct TestCase { |
| const char* ip; |
| const char* expected; |
| } cases[] = { |
| {"127.0.0.1", "127.0.0.1"}, |
| {"123.123.123.123", "123.123.123.123"}, |
| {"::1", "[::1]"}, |
| {"2001:0db8:85a3:0000:0000:8a2e:0370:7334", |
| "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"}, |
| {"2001:db8:85a3:0:0:8a2e:370:7334", "[2001:db8:85a3:0:0:8a2e:370:7334]"}, |
| {"2001:db8:85a3::8a2e:370:7334", "[2001:db8:85a3::8a2e:370:7334]"}, |
| {"::ffff:192.0.2.128", "[::ffff:192.0.2.128]"}}; |
| |
| for (const auto& test : cases) { |
| SCOPED_TRACE(test.ip); |
| content::ResourceResponseInfo info; |
| info.socket_address = net::HostPortPair(test.ip, 443); |
| blink::WebURLResponse response; |
| WebURLLoaderImpl::PopulateURLResponse(url, info, &response, true); |
| EXPECT_EQ(test.expected, response.remoteIPAddress().utf8()); |
| }; |
| } |
| |
| // Verifies that the lengths used by the PerformanceResourceTiming API are |
| // correctly assigned for sync XHR. |
| TEST_F(WebURLLoaderImplTest, SyncLengths) { |
| static const char kBodyData[] = "Today is Thursday"; |
| const int kEncodedBodyLength = 30; |
| const int kEncodedDataLength = 130; |
| const GURL url(kTestURL); |
| blink::WebURLRequest request(url); |
| |
| // Prepare a mock response |
| SyncLoadResponse sync_load_response; |
| sync_load_response.error_code = net::OK; |
| sync_load_response.url = url; |
| sync_load_response.data = kBodyData; |
| ASSERT_EQ(17u, sync_load_response.data.size()); |
| sync_load_response.encoded_body_length = kEncodedBodyLength; |
| sync_load_response.encoded_data_length = kEncodedDataLength; |
| dispatcher()->set_sync_load_response(sync_load_response); |
| |
| blink::WebURLResponse response; |
| blink::WebURLError error; |
| blink::WebData data; |
| int64_t encoded_data_length = 0; |
| int64_t encoded_body_length = 0; |
| client()->loader()->loadSynchronously( |
| request, response, error, data, encoded_data_length, encoded_body_length); |
| |
| EXPECT_EQ(kEncodedBodyLength, encoded_body_length); |
| EXPECT_EQ(kEncodedDataLength, encoded_data_length); |
| } |
| |
| } // namespace |
| } // namespace content |