blob: 6f5e2e2e1d61d4a778a55dde5540288141d37da6 [file] [log] [blame]
// 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 "third_party/blink/public/platform/web_url_loader.h"
#include <stdint.h>
#include <string.h>
#include <utility>
#include <vector>
#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/test/task_environment.h"
#include "base/time/default_tick_clock.h"
#include "base/time/time.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "net/base/host_port_pair.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/cert/x509_util.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
#include "net/ssl/ssl_connection_status_flags.h"
#include "net/test/cert_test_util.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/redirect_info.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/public/mojom/fetch_api.mojom-shared.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/resource_load_info_notifier_wrapper.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
#include "third_party/blink/public/platform/web_data.h"
#include "third_party/blink/public/platform/web_request_peer.h"
#include "third_party/blink/public/platform/web_resource_request_sender.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/platform/web_url_error.h"
#include "third_party/blink/public/platform/web_url_loader.h"
#include "third_party/blink/public/platform/web_url_loader_client.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/public/platform/web_url_request_extra_data.h"
#include "third_party/blink/public/platform/web_url_response.h"
#include "third_party/blink/public/platform/web_vector.h"
#include "third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_response.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace blink {
namespace {
const char kTestURL[] = "http://foo";
const char kTestHTTPSURL[] = "https://foo";
const char kTestData[] = "blah!";
class MockResourceRequestSender : public WebResourceRequestSender {
public:
MockResourceRequestSender() = default;
~MockResourceRequestSender() override = default;
// WebResourceRequestSender implementation:
void SendSync(
std::unique_ptr<network::ResourceRequest> request,
int routing_id,
const net::NetworkTrafficAnnotationTag& traffic_annotation,
uint32_t loader_options,
SyncLoadResponse* response,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
WebVector<std::unique_ptr<URLLoaderThrottle>> throttles,
base::TimeDelta timeout,
const WebVector<WebString>& cors_exempt_header_list,
base::WaitableEvent* terminate_sync_load_event,
mojo::PendingRemote<mojom::BlobRegistry> download_to_blob_registry,
scoped_refptr<WebRequestPeer> peer,
std::unique_ptr<ResourceLoadInfoNotifierWrapper>
resource_load_info_notifier_wrapper,
WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper)
override {
*response = std::move(sync_load_response_);
}
int SendAsync(
std::unique_ptr<network::ResourceRequest> request,
int routing_id,
scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner,
const net::NetworkTrafficAnnotationTag& traffic_annotation,
uint32_t loader_options,
const WebVector<WebString>& cors_exempt_header_list,
scoped_refptr<WebRequestPeer> peer,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
WebVector<std::unique_ptr<URLLoaderThrottle>> throttles,
std::unique_ptr<ResourceLoadInfoNotifierWrapper>
resource_load_info_notifier_wrapper,
WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper)
override {
EXPECT_FALSE(peer_);
if (sync_load_response_.head->encoded_body_length != -1)
EXPECT_TRUE(loader_options & network::mojom::kURLLoadOptionSynchronous);
peer_ = std::move(peer);
return 1;
}
void Cancel(
scoped_refptr<base::SingleThreadTaskRunner> task_runner) override {
EXPECT_FALSE(canceled_);
canceled_ = true;
task_runner->ReleaseSoon(FROM_HERE, std::move(peer_));
}
WebRequestPeer* peer() { return peer_.get(); }
bool canceled() { return canceled_; }
void SetDefersLoading(WebURLLoader::DeferType value) override {
defers_loading_ = (value != WebURLLoader::DeferType::kNotDeferred);
}
bool defers_loading() const { return defers_loading_; }
void set_sync_load_response(SyncLoadResponse&& sync_load_response) {
sync_load_response_ = std::move(sync_load_response);
}
private:
scoped_refptr<WebRequestPeer> peer_;
bool canceled_ = false;
bool defers_loading_ = false;
SyncLoadResponse sync_load_response_;
DISALLOW_COPY_AND_ASSIGN(MockResourceRequestSender);
};
class FakeURLLoaderFactory final : public network::mojom::URLLoaderFactory {
public:
FakeURLLoaderFactory() = default;
~FakeURLLoaderFactory() override = default;
void CreateLoaderAndStart(
mojo::PendingReceiver<network::mojom::URLLoader> receiver,
int32_t routing_id,
int32_t request_id,
uint32_t options,
const network::ResourceRequest& url_request,
mojo::PendingRemote<network::mojom::URLLoaderClient> client,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
override {
NOTREACHED();
}
void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)
override {
NOTREACHED();
}
private:
DISALLOW_COPY_AND_ASSIGN(FakeURLLoaderFactory);
};
class TestWebURLLoaderClient : public WebURLLoaderClient {
public:
TestWebURLLoaderClient()
: loader_(new WebURLLoader(
/*cors_exempt_header_list=*/WebVector<WebString>(),
/*terminate_sync_load_event=*/nullptr,
scheduler::WebResourceLoadingTaskRunnerHandle::CreateUnprioritized(
scheduler::GetSingleThreadTaskRunnerForTesting()),
scheduler::WebResourceLoadingTaskRunnerHandle::CreateUnprioritized(
scheduler::GetSingleThreadTaskRunnerForTesting()),
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&fake_url_loader_factory_),
/*keep_alive_handle=*/mojo::NullRemote(),
WebBackForwardCacheLoaderHelper())),
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),
did_finish_(false) {}
~TestWebURLLoaderClient() override {
// During the deconstruction of the `loader_`, the request context will be
// released asynchronously and we must ensure that the request context has
// been deleted practically before the test quits, thus, memory leak will
// not be reported on the ASAN build. So, we call 'reset()' to trigger the
// deconstruction, and then execute `RunUntilIdle()` to empty the task queue
// to achieve that.
if (loader_)
loader_.reset();
base::RunLoop().RunUntilIdle();
}
// WebURLLoaderClient implementation:
bool WillFollowRedirect(const WebURL& new_url,
const net::SiteForCookies& new_site_for_cookies,
const WebString& new_referrer,
network::mojom::ReferrerPolicy new_referrer_policy,
const WebString& new_method,
const WebURLResponse& passed_redirect_response,
bool& report_raw_headers,
std::vector<std::string>*) override {
EXPECT_TRUE(loader_);
// 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(uint64_t bytesSent, uint64_t totalBytesToBeSent) override {
EXPECT_TRUE(loader_);
}
void DidReceiveResponse(const 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 DidStartLoadingResponseBody(
mojo::ScopedDataPipeConsumerHandle response_body) override {
DCHECK(!response_body_);
DCHECK(response_body);
response_body_ = std::move(response_body);
}
void DidReceiveData(const char* data, int dataLength) override {
NOTREACHED();
}
void DidFinishLoading(base::TimeTicks finishTime,
int64_t totalEncodedDataLength,
int64_t totalEncodedBodyLength,
int64_t totalDecodedBodyLength,
bool should_report_corb_blocking) 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 WebURLError& error,
base::TimeTicks finishTime,
int64_t totalEncodedDataLength,
int64_t totalEncodedBodyLength,
int64_t totalDecodedBodyLength) override {
EXPECT_TRUE(loader_);
EXPECT_FALSE(did_finish_);
error_ = error;
if (delete_on_fail_)
loader_.reset();
}
WebURLLoader* 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; }
bool did_receive_redirect() const { return did_receive_redirect_; }
bool did_receive_response() const { return did_receive_response_; }
bool did_receive_response_body() const { return !!response_body_; }
bool did_finish() const { return did_finish_; }
const base::Optional<WebURLError>& error() const { return error_; }
const WebURLResponse& response() const { return response_; }
private:
FakeURLLoaderFactory fake_url_loader_factory_;
std::unique_ptr<WebURLLoader> 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_;
mojo::ScopedDataPipeConsumerHandle response_body_;
bool did_finish_;
base::Optional<WebURLError> error_;
WebURLResponse response_;
DISALLOW_COPY_AND_ASSIGN(TestWebURLLoaderClient);
};
class WebURLLoaderTest : public testing::Test {
public:
WebURLLoaderTest() : client_(std::make_unique<TestWebURLLoaderClient>()) {
auto sender = std::make_unique<MockResourceRequestSender>();
sender_ = sender.get();
client_->loader()->SetResourceRequestSenderForTesting(std::move(sender));
}
~WebURLLoaderTest() override = default;
void DoStartAsyncRequest() {
auto request = std::make_unique<network::ResourceRequest>();
request->url = GURL(kTestURL);
request->destination = network::mojom::RequestDestination::kEmpty;
request->priority = net::IDLE;
client()->loader()->LoadAsynchronously(
std::move(request), /*url_request_extra_data=*/nullptr,
/*requestor_id=*/0,
/*no_mime_sniffing=*/false,
std::make_unique<ResourceLoadInfoNotifierWrapper>(
/*resource_load_info_notifier=*/nullptr),
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_site_for_cookies =
net::SiteForCookies::FromUrl(GURL(kTestURL));
std::vector<std::string> removed_headers;
peer()->OnReceivedRedirect(redirect_info,
network::mojom::URLResponseHead::New(),
&removed_headers);
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_site_for_cookies =
net::SiteForCookies::FromUrl(GURL(kTestHTTPSURL));
peer()->OnReceivedRedirect(redirect_info,
network::mojom::URLResponseHead::New(), nullptr);
EXPECT_TRUE(client()->did_receive_redirect());
}
void DoReceiveResponse() {
EXPECT_FALSE(client()->did_receive_response());
peer()->OnReceivedResponse(network::mojom::URLResponseHead::New());
EXPECT_TRUE(client()->did_receive_response());
}
void DoStartLoadingResponseBody() {
mojo::ScopedDataPipeConsumerHandle handle_to_pass;
MojoResult rv = mojo::CreateDataPipe(nullptr, body_handle_, handle_to_pass);
ASSERT_EQ(MOJO_RESULT_OK, rv);
peer()->OnStartLoadingResponseBody(std::move(handle_to_pass));
}
void DoCompleteRequest() {
EXPECT_FALSE(client()->did_finish());
DCHECK(body_handle_);
body_handle_.reset();
base::RunLoop().RunUntilIdle();
network::URLLoaderCompletionStatus status(net::OK);
status.encoded_data_length = base::size(kTestData);
status.encoded_body_length = base::size(kTestData);
status.decoded_body_length = base::size(kTestData);
peer()->OnCompletedRequest(status);
EXPECT_TRUE(client()->did_finish());
// There should be no error.
EXPECT_FALSE(client()->error());
}
void DoFailRequest() {
EXPECT_FALSE(client()->did_finish());
DCHECK(body_handle_);
body_handle_.reset();
base::RunLoop().RunUntilIdle();
network::URLLoaderCompletionStatus status(net::ERR_FAILED);
status.encoded_data_length = base::size(kTestData);
status.encoded_body_length = base::size(kTestData);
status.decoded_body_length = base::size(kTestData);
peer()->OnCompletedRequest(status);
EXPECT_FALSE(client()->did_finish());
ASSERT_TRUE(client()->error());
EXPECT_EQ(net::ERR_FAILED, client()->error()->reason());
}
TestWebURLLoaderClient* client() { return client_.get(); }
MockResourceRequestSender* sender() { return sender_; }
WebRequestPeer* peer() { return sender_->peer(); }
private:
base::test::SingleThreadTaskEnvironment task_environment_;
mojo::ScopedDataPipeProducerHandle body_handle_;
std::unique_ptr<TestWebURLLoaderClient> client_;
MockResourceRequestSender* sender_ = nullptr;
};
TEST_F(WebURLLoaderTest, Success) {
DoStartAsyncRequest();
DoReceiveResponse();
DoStartLoadingResponseBody();
DoCompleteRequest();
EXPECT_FALSE(sender()->canceled());
EXPECT_TRUE(client()->did_receive_response_body());
}
TEST_F(WebURLLoaderTest, Redirect) {
DoStartAsyncRequest();
DoReceiveRedirect();
DoReceiveResponse();
DoStartLoadingResponseBody();
DoCompleteRequest();
EXPECT_FALSE(sender()->canceled());
EXPECT_TRUE(client()->did_receive_response_body());
}
TEST_F(WebURLLoaderTest, Failure) {
DoStartAsyncRequest();
DoReceiveResponse();
DoStartLoadingResponseBody();
DoFailRequest();
EXPECT_FALSE(sender()->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(WebURLLoaderTest, DeleteOnReceiveRedirect) {
client()->set_delete_on_receive_redirect();
DoStartAsyncRequest();
DoReceiveRedirect();
}
TEST_F(WebURLLoaderTest, DeleteOnReceiveResponse) {
client()->set_delete_on_receive_response();
DoStartAsyncRequest();
DoReceiveResponse();
}
TEST_F(WebURLLoaderTest, DeleteOnFinish) {
client()->set_delete_on_finish();
DoStartAsyncRequest();
DoReceiveResponse();
DoStartLoadingResponseBody();
DoCompleteRequest();
}
TEST_F(WebURLLoaderTest, DeleteOnFail) {
client()->set_delete_on_fail();
DoStartAsyncRequest();
DoReceiveResponse();
DoStartLoadingResponseBody();
DoFailRequest();
}
TEST_F(WebURLLoaderTest, DefersLoadingBeforeStart) {
client()->loader()->SetDefersLoading(WebURLLoader::DeferType::kDeferred);
EXPECT_FALSE(sender()->defers_loading());
DoStartAsyncRequest();
EXPECT_TRUE(sender()->defers_loading());
}
TEST_F(WebURLLoaderTest, ResponseIPEndpoint) {
KURL url("http://example.test/");
struct TestCase {
const char* ip;
uint16_t port;
} cases[] = {
{"127.0.0.1", 443},
{"123.123.123.123", 80},
{"::1", 22},
{"2001:0db8:85a3:0000:0000:8a2e:0370:7334", 1337},
{"2001:db8:85a3:0:0:8a2e:370:7334", 12345},
{"2001:db8:85a3::8a2e:370:7334", 8080},
{"::ffff:192.0.2.128", 8443},
};
for (const auto& test : cases) {
SCOPED_TRACE(test.ip);
net::IPAddress address;
ASSERT_TRUE(address.AssignFromIPLiteral(test.ip));
network::mojom::URLResponseHead head;
head.remote_endpoint = net::IPEndPoint(address, test.port);
WebURLResponse response;
WebURLLoader::PopulateURLResponse(url, head, &response, true, -1);
EXPECT_EQ(head.remote_endpoint, response.RemoteIPEndpoint());
};
}
TEST_F(WebURLLoaderTest, ResponseAddressSpace) {
using AddressSpace = network::mojom::IPAddressSpace;
struct TestCase {
std::string url;
std::string ip;
AddressSpace expected;
} cases[] = {
{"http://localhost", "127.0.0.1", AddressSpace::kLocal},
{"http://localhost", "::1", AddressSpace::kLocal},
{"file:///a/path", "", AddressSpace::kLocal},
{"file:///a/path", "8.8.8.8", AddressSpace::kLocal},
{"http://router.local", "10.1.0.1", AddressSpace::kPrivate},
{"http://router.local", "::ffff:192.0.2.128", AddressSpace::kPrivate},
{"https://bleep.test", "8.8.8.8", AddressSpace::kPublic},
{"http://a.test", "2001:db8:85a3::8a2e:370:7334", AddressSpace::kPublic},
{"http://invalid", "", AddressSpace::kUnknown},
};
for (const auto& test : cases) {
SCOPED_TRACE(test.url + ", " + test.ip);
KURL url(test.url.c_str());
// We are forced to use the result of AssignFromIPLiteral(), and we cannot
// just assign it to an unused variable. Check that all non-empty literals
// are correctly parsed.
net::IPAddress address;
EXPECT_EQ(!test.ip.empty(), address.AssignFromIPLiteral(test.ip));
network::mojom::URLResponseHead head;
head.remote_endpoint = net::IPEndPoint(address, 443);
WebURLResponse response;
WebURLLoader::PopulateURLResponse(url, head, &response, true, -1);
EXPECT_EQ(test.expected, response.AddressSpace());
}
}
// This test verifies that the IPAddressSpace set on WebURLResponse takes into
// account WebURLResponse::ResponseUrl() instead of
// WebURLResponse::CurrentRequestUrl().
TEST_F(WebURLLoaderTest, ResponseAddressSpaceConsidersResponseUrl) {
KURL request_url("http://request.test");
// The remote endpoint contains a public IP address, but the response was
// ultimately fetched by a service worker from a file URL.
network::mojom::URLResponseHead head;
head.remote_endpoint = net::IPEndPoint(net::IPAddress(8, 8, 8, 8), 80);
head.was_fetched_via_service_worker = true;
head.url_list_via_service_worker = {
GURL("http://redirect.test"),
GURL("file:///a/path"),
};
WebURLResponse response;
WebURLLoader::PopulateURLResponse(request_url, head, &response, true, -1);
// The address space of the response reflects the fact the it was fetched
// from a file, even though the request was initially to a public website.
EXPECT_EQ(KURL("http://request.test"), KURL(response.CurrentRequestUrl()));
EXPECT_EQ(KURL("file:///a/path"), KURL(response.ResponseUrl()));
EXPECT_EQ(network::mojom::IPAddressSpace::kLocal, response.AddressSpace());
}
TEST_F(WebURLLoaderTest, ResponseCert) {
KURL url("https://test.example/");
net::CertificateList certs;
ASSERT_TRUE(net::LoadCertificateFiles(
{"subjectAltName_sanity_check.pem", "root_ca_cert.pem"}, &certs));
ASSERT_EQ(2U, certs.size());
base::StringPiece cert0_der =
net::x509_util::CryptoBufferAsStringPiece(certs[0]->cert_buffer());
base::StringPiece cert1_der =
net::x509_util::CryptoBufferAsStringPiece(certs[1]->cert_buffer());
net::SSLInfo ssl_info;
ssl_info.cert =
net::X509Certificate::CreateFromDERCertChain({cert0_der, cert1_der});
net::SSLConnectionStatusSetVersion(net::SSL_CONNECTION_VERSION_TLS1_2,
&ssl_info.connection_status);
network::mojom::URLResponseHead head;
head.ssl_info = ssl_info;
WebURLResponse web_url_response;
WebURLLoader::PopulateURLResponse(url, head, &web_url_response, true, -1);
base::Optional<WebURLResponse::WebSecurityDetails> security_details =
web_url_response.SecurityDetailsForTesting();
ASSERT_TRUE(security_details.has_value());
EXPECT_EQ("TLS 1.2", security_details->protocol);
EXPECT_EQ("127.0.0.1", security_details->subject_name);
EXPECT_EQ("127.0.0.1", security_details->issuer);
ASSERT_EQ(3U, security_details->san_list.size());
EXPECT_EQ("test.example", security_details->san_list[0]);
EXPECT_EQ("127.0.0.2", security_details->san_list[1]);
EXPECT_EQ("fe80::1", security_details->san_list[2]);
EXPECT_EQ(certs[0]->valid_start().ToTimeT(), security_details->valid_from);
EXPECT_EQ(certs[0]->valid_expiry().ToTimeT(), security_details->valid_to);
ASSERT_EQ(2U, security_details->certificate.size());
EXPECT_EQ(WebString::FromLatin1(std::string(cert0_der)),
security_details->certificate[0]);
EXPECT_EQ(WebString::FromLatin1(std::string(cert1_der)),
security_details->certificate[1]);
}
TEST_F(WebURLLoaderTest, ResponseCertWithNoSANs) {
KURL url("https://test.example/");
net::CertificateList certs;
ASSERT_TRUE(net::LoadCertificateFiles({"multi-root-B-by-C.pem"}, &certs));
ASSERT_EQ(1U, certs.size());
base::StringPiece cert0_der =
net::x509_util::CryptoBufferAsStringPiece(certs[0]->cert_buffer());
net::SSLInfo ssl_info;
net::SSLConnectionStatusSetVersion(net::SSL_CONNECTION_VERSION_TLS1_2,
&ssl_info.connection_status);
ssl_info.cert = certs[0];
network::mojom::URLResponseHead head;
head.ssl_info = ssl_info;
WebURLResponse web_url_response;
WebURLLoader::PopulateURLResponse(url, head, &web_url_response, true, -1);
base::Optional<WebURLResponse::WebSecurityDetails> security_details =
web_url_response.SecurityDetailsForTesting();
ASSERT_TRUE(security_details.has_value());
EXPECT_EQ("TLS 1.2", security_details->protocol);
EXPECT_EQ("B CA - Multi-root", security_details->subject_name);
EXPECT_EQ("C CA - Multi-root", security_details->issuer);
EXPECT_EQ(0U, security_details->san_list.size());
EXPECT_EQ(certs[0]->valid_start().ToTimeT(), security_details->valid_from);
EXPECT_EQ(certs[0]->valid_expiry().ToTimeT(), security_details->valid_to);
ASSERT_EQ(1U, security_details->certificate.size());
EXPECT_EQ(WebString::FromLatin1(std::string(cert0_der)),
security_details->certificate[0]);
}
// Verifies that the lengths used by the PerformanceResourceTiming API are
// correctly assigned for sync XHR.
TEST_F(WebURLLoaderTest, SyncLengths) {
static const char kBodyData[] = "Today is Thursday";
const int kEncodedBodyLength = 30;
const int kEncodedDataLength = 130;
const KURL url(kTestURL);
auto request = std::make_unique<network::ResourceRequest>();
request->url = url;
request->destination = network::mojom::RequestDestination::kEmpty;
request->priority = net::HIGHEST;
// Prepare a mock response
SyncLoadResponse sync_load_response;
sync_load_response.error_code = net::OK;
sync_load_response.url = url;
sync_load_response.data.Assign(WebData(kBodyData));
ASSERT_EQ(17u, sync_load_response.data.size());
sync_load_response.head->encoded_body_length = kEncodedBodyLength;
sync_load_response.head->encoded_data_length = kEncodedDataLength;
sender()->set_sync_load_response(std::move(sync_load_response));
WebURLResponse response;
base::Optional<WebURLError> error;
WebData data;
int64_t encoded_data_length = 0;
int64_t encoded_body_length = 0;
WebBlobInfo downloaded_blob;
client()->loader()->LoadSynchronously(
std::move(request), /*url_request_extra_data=*/nullptr,
/*requestor_id=*/0,
/*pass_response_pipe_to_client=*/false, /*no_mime_sniffing=*/false,
base::TimeDelta(), nullptr, response, error, data, encoded_data_length,
encoded_body_length, downloaded_blob,
std::make_unique<ResourceLoadInfoNotifierWrapper>(
/*resource_load_info_notifier=*/nullptr));
EXPECT_EQ(kEncodedBodyLength, encoded_body_length);
EXPECT_EQ(kEncodedDataLength, encoded_data_length);
EXPECT_TRUE(downloaded_blob.Uuid().IsNull());
}
// Verifies that PopulateURLResponse() copies AuthChallengeInfo to the response.
TEST_F(WebURLLoaderTest, AuthChallengeInfo) {
network::mojom::URLResponseHead head;
net::AuthChallengeInfo auth_challenge_info;
auth_challenge_info.is_proxy = true;
auth_challenge_info.challenge = "foobar";
head.auth_challenge_info = auth_challenge_info;
blink::WebURLResponse response;
WebURLLoader::PopulateURLResponse(KURL(), head, &response, true, -1);
ASSERT_TRUE(response.AuthChallengeInfo().has_value());
EXPECT_TRUE(response.AuthChallengeInfo()->is_proxy);
EXPECT_EQ("foobar", response.AuthChallengeInfo()->challenge);
}
} // namespace
} // namespace blink