| // 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 <algorithm> |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/auto_reset.h" |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/check_op.h" |
| #include "base/command_line.h" |
| #include "base/feature_list.h" |
| #include "base/files/file_path.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/notreached.h" |
| #include "base/optional.h" |
| #include "base/sequence_checker.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "base/time/time.h" |
| #include "build/build_config.h" |
| #include "mojo/public/cpp/bindings/pending_remote.h" |
| #include "net/base/filename_util.h" |
| #include "net/base/host_port_pair.h" |
| #include "net/base/ip_endpoint.h" |
| #include "net/base/load_flags.h" |
| #include "net/base/net_errors.h" |
| #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
| #include "net/cert/cert_status_flags.h" |
| #include "net/cert/ct_sct_to_string.h" |
| #include "net/cert/x509_certificate.h" |
| #include "net/cert/x509_util.h" |
| #include "net/http/http_request_headers.h" |
| #include "net/http/http_response_headers.h" |
| #include "net/ssl/ssl_cipher_suite_names.h" |
| #include "net/ssl/ssl_connection_status_flags.h" |
| #include "net/ssl/ssl_info.h" |
| #include "services/network/public/cpp/http_raw_request_response_info.h" |
| #include "services/network/public/cpp/is_potentially_trustworthy.h" |
| #include "services/network/public/cpp/resource_request.h" |
| #include "services/network/public/mojom/fetch_api.mojom-shared.h" |
| #include "services/network/public/mojom/ip_address_space.mojom-shared.h" |
| #include "services/network/public/mojom/trust_tokens.mojom-shared.h" |
| #include "services/network/public/mojom/url_loader.mojom.h" |
| #include "services/network/public/mojom/url_response_head.mojom.h" |
| #include "third_party/blink/public/common/features.h" |
| #include "third_party/blink/public/common/loader/mime_sniffing_throttle.h" |
| #include "third_party/blink/public/common/loader/previews_state.h" |
| #include "third_party/blink/public/common/loader/referrer_utils.h" |
| #include "third_party/blink/public/common/loader/resource_type_util.h" |
| #include "third_party/blink/public/common/mime_util/mime_util.h" |
| #include "third_party/blink/public/common/net/ip_address_space_util.h" |
| #include "third_party/blink/public/common/security/security_style.h" |
| #include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h" |
| #include "third_party/blink/public/mojom/blob/blob_registry.mojom.h" |
| #include "third_party/blink/public/mojom/frame/frame.mojom.h" |
| #include "third_party/blink/public/platform/file_path_conversion.h" |
| #include "third_party/blink/public/platform/platform.h" |
| #include "third_party/blink/public/platform/resource_load_info_notifier_wrapper.h" |
| #include "third_party/blink/public/platform/resource_request_blocked_reason.h" |
| #include "third_party/blink/public/platform/url_conversion.h" |
| #include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h" |
| #include "third_party/blink/public/platform/web_http_load_info.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_security_origin.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_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/web/web_local_frame.h" |
| #include "third_party/blink/public/web/web_security_policy.h" |
| #include "third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_response.h" |
| #include "third_party/boringssl/src/include/openssl/ssl.h" |
| #include "url/origin.h" |
| |
| using base::Time; |
| using base::TimeTicks; |
| using blink::scheduler::WebResourceLoadingTaskRunnerHandle; |
| |
| namespace blink { |
| |
| // Utilities ------------------------------------------------------------------- |
| |
| namespace { |
| |
| // Converts timing data from |load_timing| to the mojo type. |
| network::mojom::LoadTimingInfo ToMojoLoadTiming( |
| const net::LoadTimingInfo& load_timing) { |
| DCHECK(!load_timing.request_start.is_null()); |
| |
| return network::mojom::LoadTimingInfo( |
| load_timing.socket_reused, load_timing.socket_log_id, |
| load_timing.request_start_time, load_timing.request_start, |
| load_timing.proxy_resolve_start, load_timing.proxy_resolve_end, |
| load_timing.connect_timing, load_timing.send_start, load_timing.send_end, |
| load_timing.receive_headers_start, load_timing.receive_headers_end, |
| load_timing.receive_non_informational_headers_start, |
| load_timing.first_early_hints_time, load_timing.push_start, |
| load_timing.push_end, load_timing.service_worker_start_time, |
| load_timing.service_worker_ready_time, |
| load_timing.service_worker_fetch_start, |
| load_timing.service_worker_respond_with_settled); |
| } |
| |
| // This is complementary to ConvertNetPriorityToWebKitPriority, defined in |
| // service_worker_context_client.cc. |
| // TODO(yhirano): Move this to blink/platform/loader. |
| net::RequestPriority ConvertWebKitPriorityToNetPriority( |
| const WebURLRequest::Priority& priority) { |
| switch (priority) { |
| case WebURLRequest::Priority::kVeryHigh: |
| return net::HIGHEST; |
| |
| case WebURLRequest::Priority::kHigh: |
| return net::MEDIUM; |
| |
| case WebURLRequest::Priority::kMedium: |
| return net::LOW; |
| |
| case WebURLRequest::Priority::kLow: |
| return net::LOWEST; |
| |
| case WebURLRequest::Priority::kVeryLow: |
| return net::IDLE; |
| |
| case WebURLRequest::Priority::kUnresolved: |
| default: |
| NOTREACHED(); |
| return net::LOW; |
| } |
| } |
| |
| // Convert a net::SignedCertificateTimestampAndStatus object to a |
| // WebURLResponse::SignedCertificateTimestamp object. |
| WebURLResponse::SignedCertificateTimestamp NetSCTToBlinkSCT( |
| const net::SignedCertificateTimestampAndStatus& sct_and_status) { |
| return WebURLResponse::SignedCertificateTimestamp( |
| WebString::FromASCII(net::ct::StatusToString(sct_and_status.status)), |
| WebString::FromASCII(net::ct::OriginToString(sct_and_status.sct->origin)), |
| WebString::FromUTF8(sct_and_status.sct->log_description), |
| WebString::FromASCII( |
| base::HexEncode(sct_and_status.sct->log_id.c_str(), |
| sct_and_status.sct->log_id.length())), |
| sct_and_status.sct->timestamp.ToJavaTime(), |
| WebString::FromASCII(net::ct::HashAlgorithmToString( |
| sct_and_status.sct->signature.hash_algorithm)), |
| WebString::FromASCII(net::ct::SignatureAlgorithmToString( |
| sct_and_status.sct->signature.signature_algorithm)), |
| WebString::FromASCII(base::HexEncode( |
| sct_and_status.sct->signature.signature_data.c_str(), |
| sct_and_status.sct->signature.signature_data.length()))); |
| } |
| |
| WebString CryptoBufferAsWebString(const CRYPTO_BUFFER* buffer) { |
| base::StringPiece sp = net::x509_util::CryptoBufferAsStringPiece(buffer); |
| return WebString::FromLatin1(reinterpret_cast<const WebLChar*>(sp.begin()), |
| sp.size()); |
| } |
| |
| void SetSecurityStyleAndDetails(const GURL& url, |
| const network::mojom::URLResponseHead& head, |
| WebURLResponse* response, |
| bool report_security_info) { |
| if (!report_security_info) { |
| response->SetSecurityStyle(SecurityStyle::kUnknown); |
| return; |
| } |
| if (!url.SchemeIsCryptographic()) { |
| // Some origins are considered secure even though they're not cryptographic, |
| // so treat them as secure in the UI. |
| if (network::IsUrlPotentiallyTrustworthy(url)) |
| response->SetSecurityStyle(SecurityStyle::kSecure); |
| else |
| response->SetSecurityStyle(SecurityStyle::kInsecure); |
| return; |
| } |
| |
| // The resource loader does not provide a guarantee that requests always have |
| // security info (such as a certificate) attached. Use SecurityStyleUnknown |
| // in this case where there isn't enough information to be useful. |
| if (!head.ssl_info.has_value()) { |
| response->SetSecurityStyle(SecurityStyle::kUnknown); |
| return; |
| } |
| |
| const net::SSLInfo& ssl_info = *head.ssl_info; |
| |
| const char* protocol = ""; |
| const char* key_exchange = ""; |
| const char* cipher = ""; |
| const char* mac = ""; |
| const char* key_exchange_group = ""; |
| |
| if (ssl_info.connection_status) { |
| int ssl_version = |
| net::SSLConnectionStatusToVersion(ssl_info.connection_status); |
| net::SSLVersionToString(&protocol, ssl_version); |
| |
| bool is_aead; |
| bool is_tls13; |
| uint16_t cipher_suite = |
| net::SSLConnectionStatusToCipherSuite(ssl_info.connection_status); |
| net::SSLCipherSuiteToStrings(&key_exchange, &cipher, &mac, &is_aead, |
| &is_tls13, cipher_suite); |
| if (!key_exchange) { |
| DCHECK(is_tls13); |
| key_exchange = ""; |
| } |
| |
| if (!mac) { |
| DCHECK(is_aead); |
| mac = ""; |
| } |
| |
| if (ssl_info.key_exchange_group != 0) { |
| // Historically the field was named 'curve' rather than 'group'. |
| key_exchange_group = SSL_get_curve_name(ssl_info.key_exchange_group); |
| if (!key_exchange_group) { |
| NOTREACHED(); |
| key_exchange_group = ""; |
| } |
| } |
| } |
| |
| if (net::IsCertStatusError(head.cert_status)) { |
| response->SetSecurityStyle(SecurityStyle::kInsecure); |
| } else { |
| response->SetSecurityStyle(SecurityStyle::kSecure); |
| } |
| |
| WebURLResponse::SignedCertificateTimestampList sct_list( |
| ssl_info.signed_certificate_timestamps.size()); |
| |
| for (size_t i = 0; i < sct_list.size(); ++i) |
| sct_list[i] = NetSCTToBlinkSCT(ssl_info.signed_certificate_timestamps[i]); |
| |
| if (!ssl_info.cert) { |
| NOTREACHED(); |
| response->SetSecurityStyle(SecurityStyle::kUnknown); |
| return; |
| } |
| |
| std::vector<std::string> san_dns; |
| std::vector<std::string> san_ip; |
| ssl_info.cert->GetSubjectAltName(&san_dns, &san_ip); |
| WebVector<WebString> web_san(san_dns.size() + san_ip.size()); |
| std::transform(san_dns.begin(), san_dns.end(), web_san.begin(), |
| [](const std::string& h) { return WebString::FromLatin1(h); }); |
| std::transform(san_ip.begin(), san_ip.end(), web_san.begin() + san_dns.size(), |
| [](const std::string& h) { |
| net::IPAddress ip(reinterpret_cast<const uint8_t*>(h.data()), |
| h.size()); |
| return WebString::FromLatin1(ip.ToString()); |
| }); |
| |
| WebVector<WebString> web_cert; |
| web_cert.reserve(ssl_info.cert->intermediate_buffers().size() + 1); |
| web_cert.emplace_back(CryptoBufferAsWebString(ssl_info.cert->cert_buffer())); |
| for (const auto& cert : ssl_info.cert->intermediate_buffers()) |
| web_cert.emplace_back(CryptoBufferAsWebString(cert.get())); |
| |
| WebURLResponse::WebSecurityDetails webSecurityDetails( |
| WebString::FromASCII(protocol), WebString::FromASCII(key_exchange), |
| WebString::FromASCII(key_exchange_group), WebString::FromASCII(cipher), |
| WebString::FromASCII(mac), |
| WebString::FromUTF8(ssl_info.cert->subject().common_name), web_san, |
| WebString::FromUTF8(ssl_info.cert->issuer().common_name), |
| ssl_info.cert->valid_start().ToDoubleT(), |
| ssl_info.cert->valid_expiry().ToDoubleT(), web_cert, sct_list); |
| |
| response->SetSecurityDetails(webSecurityDetails); |
| } |
| |
| bool IsBannedCrossSiteAuth( |
| network::ResourceRequest* resource_request, |
| WebURLRequestExtraData* passed_url_request_extra_data) { |
| auto& request_url = resource_request->url; |
| auto& first_party = resource_request->site_for_cookies; |
| |
| bool allow_cross_origin_auth_prompt = false; |
| if (passed_url_request_extra_data) { |
| WebURLRequestExtraData* url_request_extra_data = |
| static_cast<WebURLRequestExtraData*>(passed_url_request_extra_data); |
| allow_cross_origin_auth_prompt = |
| url_request_extra_data->allow_cross_origin_auth_prompt(); |
| } |
| |
| if (first_party.IsFirstPartyWithSchemefulMode( |
| request_url, /*compute_schemefully=*/false)) { |
| // If the first party is secure but the subresource is not, this is |
| // mixed-content. Do not allow the image. |
| if (!allow_cross_origin_auth_prompt && |
| network::IsUrlPotentiallyTrustworthy(first_party.RepresentativeUrl()) && |
| !network::IsUrlPotentiallyTrustworthy(request_url)) { |
| return true; |
| } |
| return false; |
| } |
| |
| return !allow_cross_origin_auth_prompt; |
| } |
| |
| } // namespace |
| |
| // This inner class exists since the WebURLLoader may be deleted while inside a |
| // call to WebURLLoaderClient. Refcounting is to keep the context from |
| // being deleted if it may have work to do after calling into the client. |
| class WebURLLoader::Context : public WebRequestPeer { |
| public: |
| Context(WebURLLoader* loader, |
| const WebVector<WebString>& cors_exempt_header_list, |
| base::WaitableEvent* terminate_sync_load_event, |
| std::unique_ptr<WebResourceLoadingTaskRunnerHandle> |
| freezable_task_runner_handle, |
| std::unique_ptr<WebResourceLoadingTaskRunnerHandle> |
| unfreezable_task_runner_handle, |
| scoped_refptr<network::SharedURLLoaderFactory> factory, |
| mojo::PendingRemote<mojom::KeepAliveHandle> keep_alive_handle, |
| WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper); |
| |
| int request_id() const { return request_id_; } |
| WebURLLoaderClient* client() const { return client_; } |
| void set_client(WebURLLoaderClient* client) { client_ = client; } |
| scoped_refptr<base::SingleThreadTaskRunner> freezable_task_runner() { |
| return freezable_task_runner_; |
| } |
| scoped_refptr<base::SingleThreadTaskRunner> unfreezable_task_runner() { |
| return unfreezable_task_runner_; |
| } |
| |
| void Cancel(); |
| void SetDefersLoading(WebURLLoader::DeferType value); |
| void DidChangePriority(WebURLRequest::Priority new_priority, |
| int intra_priority_value); |
| void Start(std::unique_ptr<network::ResourceRequest> request, |
| scoped_refptr<WebURLRequestExtraData> url_request_extra_data, |
| int requestor_id, |
| bool pass_response_pipe_to_client, |
| bool no_mime_sniffing, |
| base::TimeDelta timeout_interval, |
| SyncLoadResponse* sync_load_response, |
| std::unique_ptr<ResourceLoadInfoNotifierWrapper> |
| resource_load_info_notifier_wrapper); |
| |
| // WebRequestPeer overrides: |
| void OnUploadProgress(uint64_t position, uint64_t size) override; |
| bool OnReceivedRedirect(const net::RedirectInfo& redirect_info, |
| network::mojom::URLResponseHeadPtr head, |
| std::vector<std::string>* removed_headers) override; |
| void OnReceivedResponse(network::mojom::URLResponseHeadPtr head) override; |
| void OnStartLoadingResponseBody( |
| mojo::ScopedDataPipeConsumerHandle body) override; |
| void OnTransferSizeUpdated(int transfer_size_diff) override; |
| void OnReceivedCachedMetadata(mojo_base::BigBuffer data) override; |
| void OnCompletedRequest( |
| const network::URLLoaderCompletionStatus& status) override; |
| |
| void SetResourceRequestSenderForTesting( // IN-TEST |
| std::unique_ptr<WebResourceRequestSender> resource_request_sender); |
| |
| private: |
| // The maximal number of bytes consumed in a task. When there are more bytes |
| // in the data pipe, they will be consumed in following tasks. Setting a too |
| // small number will generate ton of tasks but setting a too large number will |
| // lead to thread janks. Also, some clients cannot handle too large chunks |
| // (512k for example). |
| static constexpr uint32_t kMaxNumConsumedBytesInTask = 64 * 1024; |
| |
| ~Context() override; |
| |
| // Called when the body data stream is detached from the reader side. |
| void CancelBodyStreaming(); |
| |
| void OnBodyAvailable(MojoResult, const mojo::HandleSignalsState&); |
| void OnBodyHasBeenRead(uint32_t read_bytes); |
| |
| static net::NetworkTrafficAnnotationTag GetTrafficAnnotationTag( |
| network::ResourceRequest* request); |
| |
| WebURLLoader* loader_; |
| |
| KURL url_; |
| // Controls SetSecurityStyleAndDetails() in PopulateURLResponse(). Initially |
| // set to WebURLRequest::ReportRawHeaders() in Start() and gets updated in |
| // WillFollowRedirect() (by the InspectorNetworkAgent) while the new |
| // ReportRawHeaders() value won't be propagated to the browser process. |
| // |
| // TODO(tyoshino): Investigate whether it's worth propagating the new value. |
| bool report_raw_headers_; |
| |
| WebURLLoaderClient* client_; |
| std::unique_ptr<WebResourceLoadingTaskRunnerHandle> |
| freezable_task_runner_handle_; |
| std::unique_ptr<WebResourceLoadingTaskRunnerHandle> |
| unfreezable_task_runner_handle_; |
| scoped_refptr<base::SingleThreadTaskRunner> freezable_task_runner_; |
| scoped_refptr<base::SingleThreadTaskRunner> unfreezable_task_runner_; |
| mojo::PendingRemote<mojom::KeepAliveHandle> keep_alive_handle_; |
| WebURLLoader::DeferType defers_loading_; |
| const WebVector<WebString> cors_exempt_header_list_; |
| base::WaitableEvent* terminate_sync_load_event_; |
| |
| int request_id_; |
| bool in_two_phase_read_ = false; |
| bool is_in_on_body_available_ = false; |
| |
| base::Optional<network::URLLoaderCompletionStatus> completion_status_; |
| |
| std::unique_ptr<WebResourceRequestSender> resource_request_sender_; |
| |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; |
| |
| WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper_; |
| }; |
| |
| // WebURLLoader::Context ------------------------------------------------------- |
| |
| // static |
| constexpr uint32_t WebURLLoader::Context::kMaxNumConsumedBytesInTask; |
| |
| WebURLLoader::Context::Context( |
| WebURLLoader* loader, |
| const WebVector<WebString>& cors_exempt_header_list, |
| base::WaitableEvent* terminate_sync_load_event, |
| std::unique_ptr<WebResourceLoadingTaskRunnerHandle> |
| freezable_task_runner_handle, |
| std::unique_ptr<WebResourceLoadingTaskRunnerHandle> |
| unfreezable_task_runner_handle, |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, |
| mojo::PendingRemote<mojom::KeepAliveHandle> keep_alive_handle, |
| WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper) |
| : loader_(loader), |
| report_raw_headers_(false), |
| client_(nullptr), |
| freezable_task_runner_handle_(std::move(freezable_task_runner_handle)), |
| unfreezable_task_runner_handle_( |
| std::move(unfreezable_task_runner_handle)), |
| freezable_task_runner_(freezable_task_runner_handle_->GetTaskRunner()), |
| unfreezable_task_runner_( |
| unfreezable_task_runner_handle_->GetTaskRunner()), |
| keep_alive_handle_(std::move(keep_alive_handle)), |
| defers_loading_(WebURLLoader::DeferType::kNotDeferred), |
| cors_exempt_header_list_(cors_exempt_header_list), |
| terminate_sync_load_event_(terminate_sync_load_event), |
| request_id_(-1), |
| resource_request_sender_(std::make_unique<WebResourceRequestSender>()), |
| url_loader_factory_(std::move(url_loader_factory)), |
| back_forward_cache_loader_helper_(back_forward_cache_loader_helper) { |
| DCHECK(url_loader_factory_); |
| } |
| |
| void WebURLLoader::Context::Cancel() { |
| TRACE_EVENT_WITH_FLOW0("loading", "WebURLLoader::Context::Cancel", this, |
| TRACE_EVENT_FLAG_FLOW_IN); |
| if (request_id_ != -1) { |
| resource_request_sender_->Cancel(freezable_task_runner_); |
| request_id_ = -1; |
| } |
| |
| // Do not make any further calls to the client. |
| client_ = nullptr; |
| loader_ = nullptr; |
| } |
| |
| void WebURLLoader::Context::SetDefersLoading(WebURLLoader::DeferType value) { |
| if (request_id_ != -1) |
| resource_request_sender_->SetDefersLoading(value); |
| defers_loading_ = value; |
| } |
| |
| void WebURLLoader::Context::DidChangePriority( |
| WebURLRequest::Priority new_priority, |
| int intra_priority_value) { |
| if (request_id_ != -1) { |
| net::RequestPriority net_priority = |
| ConvertWebKitPriorityToNetPriority(new_priority); |
| resource_request_sender_->DidChangePriority(net_priority, |
| intra_priority_value); |
| freezable_task_runner_handle_->DidChangeRequestPriority(net_priority); |
| } |
| } |
| |
| void WebURLLoader::Context::Start( |
| std::unique_ptr<network::ResourceRequest> request, |
| scoped_refptr<WebURLRequestExtraData> passed_url_request_extra_data, |
| int requestor_id, |
| bool pass_response_pipe_to_client, |
| bool no_mime_sniffing, |
| base::TimeDelta timeout_interval, |
| SyncLoadResponse* sync_load_response, |
| std::unique_ptr<ResourceLoadInfoNotifierWrapper> |
| resource_load_info_notifier_wrapper) { |
| DCHECK_EQ(request_id_, -1); |
| |
| // Notify Blink's scheduler with the initial resource fetch priority. |
| freezable_task_runner_handle_->DidChangeRequestPriority(request->priority); |
| |
| url_ = KURL(request->url); |
| report_raw_headers_ = request->report_raw_headers; |
| |
| // TODO(horo): Check credentials flag is unset when credentials mode is omit. |
| // Check credentials flag is set when credentials mode is include. |
| |
| const network::mojom::RequestDestination request_destination = |
| request->destination; |
| |
| // TODO(yhirano): Move the logic below to blink/platform/loader. |
| if (!request->is_favicon && |
| request_destination == network::mojom::RequestDestination::kImage && |
| IsBannedCrossSiteAuth(request.get(), |
| passed_url_request_extra_data.get())) { |
| // Prevent third-party image content from prompting for login, as this |
| // is often a scam to extract credentials for another domain from the |
| // user. Only block image loads, as the attack applies largely to the |
| // "src" property of the <img> tag. It is common for web properties to |
| // allow untrusted values for <img src>; this is considered a fair thing |
| // for an HTML sanitizer to do. Conversely, any HTML sanitizer that didn't |
| // filter sources for <script>, <link>, <embed>, <object>, <iframe> tags |
| // would be considered vulnerable in and of itself. |
| request->do_not_prompt_for_login = true; |
| request->load_flags |= net::LOAD_DO_NOT_USE_EMBEDDED_IDENTITY; |
| } |
| |
| scoped_refptr<WebURLRequestExtraData> empty_url_request_extra_data; |
| WebURLRequestExtraData* url_request_extra_data; |
| if (passed_url_request_extra_data) { |
| url_request_extra_data = static_cast<WebURLRequestExtraData*>( |
| passed_url_request_extra_data.get()); |
| } else { |
| empty_url_request_extra_data = |
| base::MakeRefCounted<WebURLRequestExtraData>(); |
| url_request_extra_data = empty_url_request_extra_data.get(); |
| } |
| url_request_extra_data->CopyToResourceRequest(request.get()); |
| |
| if (request->load_flags & net::LOAD_PREFETCH) |
| request->corb_detachable = true; |
| |
| auto throttles = |
| url_request_extra_data->TakeURLLoaderThrottles().ReleaseVector(); |
| // The frame request blocker is only for a frame's subresources. |
| if (url_request_extra_data->frame_request_blocker() && |
| !IsRequestDestinationFrame(request_destination)) { |
| auto throttle = url_request_extra_data->frame_request_blocker() |
| ->GetThrottleIfRequestsBlocked(); |
| if (throttle) |
| throttles.push_back(std::move(throttle)); |
| } |
| |
| // TODO(minggang): Remove the useage of render frame id. |
| Platform::Current()->AppendVariationsThrottles(request->render_frame_id, |
| &throttles); |
| |
| uint32_t loader_options = network::mojom::kURLLoadOptionNone; |
| if (!no_mime_sniffing) { |
| loader_options |= network::mojom::kURLLoadOptionSniffMimeType; |
| throttles.push_back( |
| std::make_unique<MimeSniffingThrottle>(unfreezable_task_runner_)); |
| } |
| |
| if (sync_load_response) { |
| DCHECK(defers_loading_ == WebURLLoader::DeferType::kNotDeferred); |
| |
| loader_options |= network::mojom::kURLLoadOptionSynchronous; |
| request->load_flags |= net::LOAD_IGNORE_LIMITS; |
| |
| mojo::PendingRemote<mojom::BlobRegistry> download_to_blob_registry; |
| if (pass_response_pipe_to_client) { |
| Platform::Current()->GetBrowserInterfaceBroker()->GetInterface( |
| download_to_blob_registry.InitWithNewPipeAndPassReceiver()); |
| } |
| net::NetworkTrafficAnnotationTag tag = |
| GetTrafficAnnotationTag(request.get()); |
| resource_request_sender_->SendSync( |
| std::move(request), requestor_id, tag, loader_options, |
| sync_load_response, url_loader_factory_, std::move(throttles), |
| timeout_interval, cors_exempt_header_list_, terminate_sync_load_event_, |
| std::move(download_to_blob_registry), base::WrapRefCounted(this), |
| std::move(resource_load_info_notifier_wrapper), |
| back_forward_cache_loader_helper_); |
| return; |
| } |
| |
| TRACE_EVENT_WITH_FLOW0("loading", "WebURLLoader::Context::Start", this, |
| TRACE_EVENT_FLAG_FLOW_OUT); |
| net::NetworkTrafficAnnotationTag tag = GetTrafficAnnotationTag(request.get()); |
| request_id_ = resource_request_sender_->SendAsync( |
| std::move(request), requestor_id, unfreezable_task_runner_, tag, |
| loader_options, cors_exempt_header_list_, base::WrapRefCounted(this), |
| url_loader_factory_, std::move(throttles), |
| std::move(resource_load_info_notifier_wrapper), |
| back_forward_cache_loader_helper_); |
| |
| if (defers_loading_ != WebURLLoader::DeferType::kNotDeferred) { |
| resource_request_sender_->SetDefersLoading( |
| WebURLLoader::DeferType::kDeferred); |
| } |
| } |
| |
| void WebURLLoader::Context::OnUploadProgress(uint64_t position, uint64_t size) { |
| if (client_) |
| client_->DidSendData(position, size); |
| } |
| |
| bool WebURLLoader::Context::OnReceivedRedirect( |
| const net::RedirectInfo& redirect_info, |
| network::mojom::URLResponseHeadPtr head, |
| std::vector<std::string>* removed_headers) { |
| if (!client_) |
| return false; |
| |
| TRACE_EVENT_WITH_FLOW0("loading", "WebURLLoader::Context::OnReceivedRedirect", |
| this, |
| TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); |
| |
| WebURLResponse response; |
| PopulateURLResponse(url_, *head, &response, report_raw_headers_, request_id_); |
| |
| url_ = KURL(redirect_info.new_url); |
| return client_->WillFollowRedirect( |
| url_, redirect_info.new_site_for_cookies, |
| WebString::FromUTF8(redirect_info.new_referrer), |
| ReferrerUtils::NetToMojoReferrerPolicy(redirect_info.new_referrer_policy), |
| WebString::FromUTF8(redirect_info.new_method), response, |
| report_raw_headers_, removed_headers); |
| } |
| |
| void WebURLLoader::Context::OnReceivedResponse( |
| network::mojom::URLResponseHeadPtr head) { |
| if (!client_) |
| return; |
| |
| TRACE_EVENT_WITH_FLOW0("loading", "WebURLLoader::Context::OnReceivedResponse", |
| this, |
| TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); |
| |
| // These headers must be stripped off before entering into the renderer |
| // (see also https://crbug.com/1019732). |
| DCHECK(!head->headers || !head->headers->HasHeader("set-cookie")); |
| DCHECK(!head->headers || !head->headers->HasHeader("set-cookie2")); |
| DCHECK(!head->headers || !head->headers->HasHeader("clear-site-data")); |
| |
| WebURLResponse response; |
| PopulateURLResponse(url_, *head, &response, report_raw_headers_, request_id_); |
| |
| client_->DidReceiveResponse(response); |
| |
| // DidReceiveResponse() may have triggered a cancel, causing the |client_| to |
| // go away. |
| if (!client_) |
| return; |
| } |
| |
| void WebURLLoader::Context::OnStartLoadingResponseBody( |
| mojo::ScopedDataPipeConsumerHandle body) { |
| if (client_) |
| client_->DidStartLoadingResponseBody(std::move(body)); |
| |
| TRACE_EVENT_WITH_FLOW0( |
| "loading", "WebURLLoader::Context::OnStartLoadingResponseBody", this, |
| TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); |
| } |
| |
| void WebURLLoader::Context::OnTransferSizeUpdated(int transfer_size_diff) { |
| client_->DidReceiveTransferSizeUpdate(transfer_size_diff); |
| } |
| |
| void WebURLLoader::Context::OnReceivedCachedMetadata( |
| mojo_base::BigBuffer data) { |
| if (!client_) |
| return; |
| TRACE_EVENT_WITH_FLOW1( |
| "loading", "WebURLLoader::Context::OnReceivedCachedMetadata", this, |
| TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "length", |
| data.size()); |
| client_->DidReceiveCachedMetadata(std::move(data)); |
| } |
| |
| void WebURLLoader::Context::OnCompletedRequest( |
| const network::URLLoaderCompletionStatus& status) { |
| int64_t total_transfer_size = status.encoded_data_length; |
| int64_t encoded_body_size = status.encoded_body_length; |
| |
| if (client_) { |
| TRACE_EVENT_WITH_FLOW0("loading", |
| "WebURLLoader::Context::OnCompletedRequest", this, |
| TRACE_EVENT_FLAG_FLOW_IN); |
| |
| if (status.error_code != net::OK) { |
| client_->DidFail(PopulateURLError(status, url_), status.completion_time, |
| total_transfer_size, encoded_body_size, |
| status.decoded_body_length); |
| } else { |
| client_->DidFinishLoading(status.completion_time, total_transfer_size, |
| encoded_body_size, status.decoded_body_length, |
| status.should_report_corb_blocking); |
| } |
| } |
| } |
| |
| WebURLLoader::Context::~Context() { |
| // We must be already cancelled at this point. |
| DCHECK_LT(request_id_, 0); |
| } |
| |
| void WebURLLoader::Context::CancelBodyStreaming() { |
| scoped_refptr<Context> protect(this); |
| |
| if (client_) { |
| // TODO(yhirano): Set |stale_copy_in_cache| appropriately if possible. |
| client_->DidFail(WebURLError(net::ERR_ABORTED, url_), |
| base::TimeTicks::Now(), |
| WebURLLoaderClient::kUnknownEncodedDataLength, 0, 0); |
| } |
| |
| // Notify the browser process that the request is canceled. |
| Cancel(); |
| } |
| |
| // WebURLLoader ---------------------------------------------------------------- |
| |
| WebURLLoader::WebURLLoader( |
| const WebVector<WebString>& cors_exempt_header_list, |
| base::WaitableEvent* terminate_sync_load_event, |
| std::unique_ptr<WebResourceLoadingTaskRunnerHandle> |
| freezable_task_runner_handle, |
| std::unique_ptr<WebResourceLoadingTaskRunnerHandle> |
| unfreezable_task_runner_handle, |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, |
| mojo::PendingRemote<mojom::KeepAliveHandle> keep_alive_handle, |
| WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper) |
| : context_(new Context(this, |
| cors_exempt_header_list, |
| terminate_sync_load_event, |
| std::move(freezable_task_runner_handle), |
| std::move(unfreezable_task_runner_handle), |
| std::move(url_loader_factory), |
| std::move(keep_alive_handle), |
| back_forward_cache_loader_helper)) {} |
| |
| WebURLLoader::WebURLLoader() = default; |
| |
| WebURLLoader::~WebURLLoader() { |
| Cancel(); |
| } |
| |
| void WebURLLoader::PopulateURLResponse( |
| const WebURL& url, |
| const network::mojom::URLResponseHead& head, |
| WebURLResponse* response, |
| bool report_security_info, |
| int request_id) { |
| response->SetCurrentRequestUrl(url); |
| response->SetResponseTime(head.response_time); |
| response->SetMimeType(WebString::FromUTF8(head.mime_type)); |
| response->SetTextEncodingName(WebString::FromUTF8(head.charset)); |
| response->SetExpectedContentLength(head.content_length); |
| response->SetHasMajorCertificateErrors( |
| net::IsCertStatusError(head.cert_status)); |
| response->SetCTPolicyCompliance(head.ct_policy_compliance); |
| response->SetIsLegacyTLSVersion(head.is_legacy_tls_version); |
| response->SetHasRangeRequested(head.has_range_requested); |
| response->SetTimingAllowPassed(head.timing_allow_passed); |
| response->SetAppCacheID(head.appcache_id); |
| response->SetAppCacheManifestURL(KURL(head.appcache_manifest_url)); |
| response->SetWasCached(!head.load_timing.request_start_time.is_null() && |
| head.response_time < |
| head.load_timing.request_start_time); |
| response->SetConnectionID(head.load_timing.socket_log_id); |
| response->SetConnectionReused(head.load_timing.socket_reused); |
| response->SetWasFetchedViaSPDY(head.was_fetched_via_spdy); |
| response->SetWasFetchedViaServiceWorker(head.was_fetched_via_service_worker); |
| response->SetServiceWorkerResponseSource(head.service_worker_response_source); |
| response->SetWasFallbackRequiredByServiceWorker( |
| head.was_fallback_required_by_service_worker); |
| response->SetType(head.response_type); |
| response->SetPadding(head.padding); |
| WebVector<KURL> url_list_via_service_worker( |
| head.url_list_via_service_worker.size()); |
| std::transform(head.url_list_via_service_worker.begin(), |
| head.url_list_via_service_worker.end(), |
| url_list_via_service_worker.begin(), |
| [](const GURL& h) { return KURL(h); }); |
| response->SetUrlListViaServiceWorker(url_list_via_service_worker); |
| response->SetCacheStorageCacheName( |
| head.service_worker_response_source == |
| network::mojom::FetchResponseSource::kCacheStorage |
| ? WebString::FromUTF8(head.cache_storage_cache_name) |
| : WebString()); |
| |
| WebVector<WebString> dns_aliases(head.dns_aliases.size()); |
| std::transform(head.dns_aliases.begin(), head.dns_aliases.end(), |
| dns_aliases.begin(), |
| [](const std::string& h) { return WebString::FromASCII(h); }); |
| response->SetDnsAliases(dns_aliases); |
| response->SetRemoteIPEndpoint(head.remote_endpoint); |
| // This computation can only be done once SetUrlListViaServiceWorker() has |
| // been called on |response|, so that ResponseUrl() returns the correct |
| // answer. |
| // |
| // Implements: https://wicg.github.io/cors-rfc1918/#integration-html |
| response->SetAddressSpace(CalculateResourceAddressSpace( |
| KURL(response->ResponseUrl()), head.remote_endpoint.address())); |
| |
| WebVector<WebString> cors_exposed_header_names( |
| head.cors_exposed_header_names.size()); |
| std::transform(head.cors_exposed_header_names.begin(), |
| head.cors_exposed_header_names.end(), |
| cors_exposed_header_names.begin(), |
| [](const std::string& h) { return WebString::FromLatin1(h); }); |
| response->SetCorsExposedHeaderNames(cors_exposed_header_names); |
| response->SetDidServiceWorkerNavigationPreload( |
| head.did_service_worker_navigation_preload); |
| response->SetEncodedDataLength(head.encoded_data_length); |
| response->SetEncodedBodyLength(head.encoded_body_length); |
| response->SetWasAlpnNegotiated(head.was_alpn_negotiated); |
| response->SetAlpnNegotiatedProtocol( |
| WebString::FromUTF8(head.alpn_negotiated_protocol)); |
| response->SetWasAlternateProtocolAvailable( |
| head.was_alternate_protocol_available); |
| response->SetConnectionInfo(head.connection_info); |
| response->SetAsyncRevalidationRequested(head.async_revalidation_requested); |
| response->SetNetworkAccessed(head.network_accessed); |
| response->SetRequestId(request_id); |
| response->SetIsSignedExchangeInnerResponse( |
| head.is_signed_exchange_inner_response); |
| response->SetWasInPrefetchCache(head.was_in_prefetch_cache); |
| response->SetWasCookieInRequest(head.was_cookie_in_request); |
| response->SetRecursivePrefetchToken(head.recursive_prefetch_token); |
| response->SetWebBundleURL(KURL(head.web_bundle_url)); |
| |
| SetSecurityStyleAndDetails(KURL(url), head, response, report_security_info); |
| |
| // If there's no received headers end time, don't set load timing. This is |
| // the case for non-HTTP requests, requests that don't go over the wire, and |
| // certain error cases. |
| if (!head.load_timing.receive_headers_end.is_null()) { |
| response->SetLoadTiming(ToMojoLoadTiming(head.load_timing)); |
| } |
| |
| if (head.raw_request_response_info.get()) { |
| WebHTTPLoadInfo load_info; |
| |
| load_info.SetHTTPStatusCode( |
| head.raw_request_response_info->http_status_code); |
| load_info.SetHTTPStatusText(WebString::FromLatin1( |
| head.raw_request_response_info->http_status_text)); |
| |
| load_info.SetRequestHeadersText(WebString::FromLatin1( |
| head.raw_request_response_info->request_headers_text)); |
| load_info.SetResponseHeadersText(WebString::FromLatin1( |
| head.raw_request_response_info->response_headers_text)); |
| for (auto& header : head.raw_request_response_info->request_headers) { |
| load_info.AddRequestHeader(WebString::FromLatin1(header->key), |
| WebString::FromLatin1(header->value)); |
| } |
| for (auto& header : head.raw_request_response_info->response_headers) { |
| load_info.AddResponseHeader(WebString::FromLatin1(header->key), |
| WebString::FromLatin1(header->value)); |
| } |
| response->SetHTTPLoadInfo(load_info); |
| } |
| |
| response->SetAuthChallengeInfo(head.auth_challenge_info); |
| |
| const net::HttpResponseHeaders* headers = head.headers.get(); |
| if (!headers) |
| return; |
| |
| WebURLResponse::HTTPVersion version = WebURLResponse::kHTTPVersionUnknown; |
| if (headers->GetHttpVersion() == net::HttpVersion(0, 9)) |
| version = WebURLResponse::kHTTPVersion_0_9; |
| else if (headers->GetHttpVersion() == net::HttpVersion(1, 0)) |
| version = WebURLResponse::kHTTPVersion_1_0; |
| else if (headers->GetHttpVersion() == net::HttpVersion(1, 1)) |
| version = WebURLResponse::kHTTPVersion_1_1; |
| else if (headers->GetHttpVersion() == net::HttpVersion(2, 0)) |
| version = WebURLResponse::kHTTPVersion_2_0; |
| response->SetHttpVersion(version); |
| response->SetHttpStatusCode(headers->response_code()); |
| response->SetHttpStatusText(WebString::FromLatin1(headers->GetStatusText())); |
| |
| // Build up the header map. |
| size_t iter = 0; |
| std::string name; |
| std::string value; |
| while (headers->EnumerateHeaderLines(&iter, &name, &value)) { |
| response->AddHttpHeaderField(WebString::FromLatin1(name), |
| WebString::FromLatin1(value)); |
| } |
| } |
| |
| // static |
| WebURLError WebURLLoader::PopulateURLError( |
| const network::URLLoaderCompletionStatus& status, |
| const WebURL& url) { |
| DCHECK_NE(net::OK, status.error_code); |
| const WebURLError::HasCopyInCache has_copy_in_cache = |
| status.exists_in_cache ? WebURLError::HasCopyInCache::kTrue |
| : WebURLError::HasCopyInCache::kFalse; |
| if (status.cors_error_status) |
| return WebURLError(*status.cors_error_status, has_copy_in_cache, url); |
| if (status.blocked_by_response_reason) { |
| DCHECK_EQ(net::ERR_BLOCKED_BY_RESPONSE, status.error_code); |
| return WebURLError(*status.blocked_by_response_reason, |
| status.resolve_error_info, has_copy_in_cache, url); |
| } |
| |
| if (status.trust_token_operation_status != |
| network::mojom::TrustTokenOperationStatus::kOk) { |
| DCHECK(status.error_code == |
| net::ERR_TRUST_TOKEN_OPERATION_SUCCESS_WITHOUT_SENDING_REQUEST || |
| status.error_code == net::ERR_TRUST_TOKEN_OPERATION_FAILED) |
| << "Unexpected error code on Trust Token operation failure (or cache " |
| "hit): " |
| << status.error_code; |
| |
| return WebURLError(status.error_code, status.trust_token_operation_status, |
| url); |
| } |
| |
| return WebURLError(status.error_code, status.extended_error_code, |
| status.resolve_error_info, has_copy_in_cache, |
| WebURLError::IsWebSecurityViolation::kFalse, url); |
| } |
| |
| void WebURLLoader::LoadSynchronously( |
| std::unique_ptr<network::ResourceRequest> request, |
| scoped_refptr<WebURLRequestExtraData> url_request_extra_data, |
| int requestor_id, |
| bool pass_response_pipe_to_client, |
| bool no_mime_sniffing, |
| base::TimeDelta timeout_interval, |
| WebURLLoaderClient* client, |
| WebURLResponse& response, |
| base::Optional<WebURLError>& error, |
| WebData& data, |
| int64_t& encoded_data_length, |
| int64_t& encoded_body_length, |
| WebBlobInfo& downloaded_blob, |
| std::unique_ptr<ResourceLoadInfoNotifierWrapper> |
| resource_load_info_notifier_wrapper) { |
| if (!context_) |
| return; |
| |
| TRACE_EVENT0("loading", "WebURLLoader::loadSynchronously"); |
| SyncLoadResponse sync_load_response; |
| |
| DCHECK(!context_->client()); |
| context_->set_client(client); |
| |
| const bool report_raw_headers = request->report_raw_headers; |
| context_->Start(std::move(request), std::move(url_request_extra_data), |
| requestor_id, pass_response_pipe_to_client, no_mime_sniffing, |
| timeout_interval, &sync_load_response, |
| std::move(resource_load_info_notifier_wrapper)); |
| |
| const KURL final_url(sync_load_response.url); |
| |
| // TODO(tc): For file loads, we may want to include a more descriptive |
| // status code or status text. |
| const int error_code = sync_load_response.error_code; |
| if (error_code != net::OK) { |
| if (sync_load_response.cors_error) { |
| error = WebURLError(*sync_load_response.cors_error, |
| WebURLError::HasCopyInCache::kFalse, final_url); |
| } else { |
| // SyncResourceHandler returns ERR_ABORTED for CORS redirect errors, |
| // so we treat the error as a web security violation. |
| const WebURLError::IsWebSecurityViolation is_web_security_violation = |
| error_code == net::ERR_ABORTED |
| ? WebURLError::IsWebSecurityViolation::kTrue |
| : WebURLError::IsWebSecurityViolation::kFalse; |
| error = WebURLError(error_code, sync_load_response.extended_error_code, |
| sync_load_response.resolve_error_info, |
| WebURLError::HasCopyInCache::kFalse, |
| is_web_security_violation, final_url); |
| } |
| return; |
| } |
| |
| PopulateURLResponse(final_url, *sync_load_response.head, &response, |
| report_raw_headers, context_->request_id()); |
| encoded_data_length = sync_load_response.head->encoded_data_length; |
| encoded_body_length = sync_load_response.head->encoded_body_length; |
| if (sync_load_response.downloaded_blob) { |
| downloaded_blob = WebBlobInfo( |
| WebString::FromLatin1(sync_load_response.downloaded_blob->uuid), |
| WebString::FromLatin1(sync_load_response.downloaded_blob->content_type), |
| sync_load_response.downloaded_blob->size, |
| std::move(sync_load_response.downloaded_blob->blob)); |
| } |
| |
| data.Assign(sync_load_response.data); |
| } |
| |
| void WebURLLoader::LoadAsynchronously( |
| std::unique_ptr<network::ResourceRequest> request, |
| scoped_refptr<WebURLRequestExtraData> url_request_extra_data, |
| int requestor_id, |
| bool no_mime_sniffing, |
| std::unique_ptr<ResourceLoadInfoNotifierWrapper> |
| resource_load_info_notifier_wrapper, |
| WebURLLoaderClient* client) { |
| if (!context_) |
| return; |
| |
| TRACE_EVENT_WITH_FLOW0("loading", "WebURLLoader::loadAsynchronously", this, |
| TRACE_EVENT_FLAG_FLOW_OUT); |
| DCHECK(!context_->client()); |
| |
| context_->set_client(client); |
| context_->Start(std::move(request), std::move(url_request_extra_data), |
| requestor_id, |
| /*pass_response_pipe_to_client=*/false, no_mime_sniffing, |
| base::TimeDelta(), nullptr, |
| std::move(resource_load_info_notifier_wrapper)); |
| } |
| |
| void WebURLLoader::Cancel() { |
| if (context_) |
| context_->Cancel(); |
| } |
| |
| void WebURLLoader::SetDefersLoading(DeferType value) { |
| if (context_) |
| context_->SetDefersLoading(value); |
| } |
| |
| void WebURLLoader::DidChangePriority(WebURLRequest::Priority new_priority, |
| int intra_priority_value) { |
| if (context_) |
| context_->DidChangePriority(new_priority, intra_priority_value); |
| } |
| |
| scoped_refptr<base::SingleThreadTaskRunner> |
| WebURLLoader::GetTaskRunnerForBodyLoader() { |
| if (!context_) |
| return nullptr; |
| return context_->unfreezable_task_runner(); |
| } |
| |
| void WebURLLoader::SetResourceRequestSenderForTesting( |
| std::unique_ptr<WebResourceRequestSender> resource_request_sender) { |
| context_->SetResourceRequestSenderForTesting( // IN-TEST |
| std::move(resource_request_sender)); |
| } |
| |
| // static |
| // We have this function at the bottom of this file because it confuses |
| // syntax highliting. |
| // TODO(kinuko): Deprecate this, we basically need to know the destination |
| // and if it's for favicon or not. |
| net::NetworkTrafficAnnotationTag WebURLLoader::Context::GetTrafficAnnotationTag( |
| network::ResourceRequest* request) { |
| if (request->is_favicon) { |
| return net::DefineNetworkTrafficAnnotation("favicon_loader", R"( |
| semantics { |
| sender: "Blink Resource Loader" |
| description: |
| "Chrome sends a request to download favicon for a URL." |
| trigger: |
| "Navigating to a URL." |
| data: "None." |
| destination: WEBSITE |
| } |
| policy { |
| cookies_allowed: YES |
| cookies_store: "user" |
| setting: "These requests cannot be disabled in settings." |
| policy_exception_justification: |
| "Not implemented." |
| })"); |
| } |
| switch (request->destination) { |
| case network::mojom::RequestDestination::kDocument: |
| case network::mojom::RequestDestination::kIframe: |
| case network::mojom::RequestDestination::kFrame: |
| NOTREACHED(); |
| FALLTHROUGH; |
| |
| case network::mojom::RequestDestination::kEmpty: |
| case network::mojom::RequestDestination::kAudio: |
| case network::mojom::RequestDestination::kAudioWorklet: |
| case network::mojom::RequestDestination::kFont: |
| case network::mojom::RequestDestination::kImage: |
| case network::mojom::RequestDestination::kManifest: |
| case network::mojom::RequestDestination::kPaintWorklet: |
| case network::mojom::RequestDestination::kReport: |
| case network::mojom::RequestDestination::kScript: |
| case network::mojom::RequestDestination::kServiceWorker: |
| case network::mojom::RequestDestination::kSharedWorker: |
| case network::mojom::RequestDestination::kStyle: |
| case network::mojom::RequestDestination::kTrack: |
| case network::mojom::RequestDestination::kVideo: |
| case network::mojom::RequestDestination::kWebBundle: |
| case network::mojom::RequestDestination::kWorker: |
| case network::mojom::RequestDestination::kXslt: |
| return net::DefineNetworkTrafficAnnotation("blink_resource_loader", R"( |
| semantics { |
| sender: "Blink Resource Loader" |
| description: |
| "Blink-initiated request, which includes all resources for " |
| "normal page loads, chrome URLs, and downloads." |
| trigger: |
| "The user navigates to a URL or downloads a file. Also when a " |
| "webpage, ServiceWorker, or chrome:// uses any network communication." |
| data: "Anything the initiator wants to send." |
| destination: OTHER |
| } |
| policy { |
| cookies_allowed: YES |
| cookies_store: "user" |
| setting: "These requests cannot be disabled in settings." |
| policy_exception_justification: |
| "Not implemented. Without these requests, Chrome will be unable " |
| "to load any webpage." |
| })"); |
| |
| case network::mojom::RequestDestination::kEmbed: |
| case network::mojom::RequestDestination::kObject: |
| return net::DefineNetworkTrafficAnnotation( |
| "blink_extension_resource_loader", R"( |
| semantics { |
| sender: "Blink Resource Loader" |
| description: |
| "Blink-initiated request for resources required for NaCl instances " |
| "tagged with <embed> or <object>, or installed extensions." |
| trigger: |
| "An extension or NaCl instance may initiate a request at any time, " |
| "even in the background." |
| data: "Anything the initiator wants to send." |
| destination: OTHER |
| } |
| policy { |
| cookies_allowed: YES |
| cookies_store: "user" |
| setting: |
| "These requests cannot be disabled in settings, but they are " |
| "sent only if user installs extensions." |
| chrome_policy { |
| ExtensionInstallBlocklist { |
| ExtensionInstallBlocklist: { |
| entries: '*' |
| } |
| } |
| } |
| })"); |
| } |
| |
| return net::NetworkTrafficAnnotationTag::NotReached(); |
| } |
| |
| void WebURLLoader::Context::SetResourceRequestSenderForTesting( |
| std::unique_ptr<blink::WebResourceRequestSender> resource_request_sender) { |
| resource_request_sender_ = std::move(resource_request_sender); |
| } |
| |
| } // namespace blink |