| // Copyright 2019 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 "components/update_client/net/network_impl.h" |
| |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/numerics/safe_conversions.h" |
| #include "components/update_client/net/network_chromium.h" |
| #include "net/base/load_flags.h" |
| #include "net/http/http_response_headers.h" |
| #include "net/traffic_annotation/network_traffic_annotation.h" |
| #include "services/network/public/cpp/resource_response.h" |
| #include "services/network/public/cpp/shared_url_loader_factory.h" |
| #include "services/network/public/cpp/simple_url_loader.h" |
| #include "url/gurl.h" |
| |
| namespace { |
| |
| const net::NetworkTrafficAnnotationTag traffic_annotation = |
| net::DefineNetworkTrafficAnnotation("update_client", R"( |
| semantics { |
| sender: "Component Updater and Extension Updater" |
| description: |
| "This network module is used by both the component and the " |
| "extension updaters in Chrome. " |
| "The component updater is responsible for updating code and data " |
| "modules such as Flash, CrlSet, Origin Trials, etc. These modules " |
| "are updated on cycles independent of the Chrome release tracks. " |
| "It runs in the browser process and communicates with a set of " |
| "servers using the Omaha protocol to find the latest versions of " |
| "components, download them, and register them with the rest of " |
| "Chrome. " |
| "The extension updater works similarly, but it updates user " |
| "extensions instead of Chrome components. " |
| trigger: "Manual or automatic software updates." |
| data: |
| "Various OS and Chrome parameters such as version, bitness, " |
| "release tracks, etc. The component and the extension ids are also " |
| "present in both the request and the response from the servers. " |
| "The URL that refers to a component CRX payload is obfuscated for " |
| "most components." |
| destination: GOOGLE_OWNED_SERVICE |
| } |
| policy { |
| cookies_allowed: NO |
| setting: "This feature cannot be disabled." |
| chrome_policy { |
| ComponentUpdatesEnabled { |
| policy_options {mode: MANDATORY} |
| ComponentUpdatesEnabled: false |
| } |
| } |
| })"); |
| |
| // Returns the string value of a header of the server response or an empty |
| // string if the header is not available. Only the first header is returned |
| // if multiple instances of the same header are present. |
| std::string GetStringHeader(const network::SimpleURLLoader* simple_url_loader, |
| const char* header_name) { |
| DCHECK(simple_url_loader); |
| |
| const auto* response_info = simple_url_loader->ResponseInfo(); |
| if (!response_info || !response_info->headers) |
| return {}; |
| |
| std::string header_value; |
| return response_info->headers->EnumerateHeader(nullptr, header_name, |
| &header_value) |
| ? header_value |
| : std::string{}; |
| } |
| |
| // Returns the integral value of a header of the server response or -1 if |
| // if the header is not available or a conversion error has occured. |
| int64_t GetInt64Header(const network::SimpleURLLoader* simple_url_loader, |
| const char* header_name) { |
| DCHECK(simple_url_loader); |
| |
| const auto* response_info = simple_url_loader->ResponseInfo(); |
| if (!response_info || !response_info->headers) |
| return -1; |
| |
| return response_info->headers->GetInt64HeaderValue(header_name); |
| } |
| |
| } // namespace |
| |
| namespace update_client { |
| |
| NetworkFetcherImpl::NetworkFetcherImpl( |
| scoped_refptr<network::SharedURLLoaderFactory> shared_url_network_factory) |
| : shared_url_network_factory_(shared_url_network_factory) {} |
| NetworkFetcherImpl::~NetworkFetcherImpl() = default; |
| |
| void NetworkFetcherImpl::PostRequest( |
| const GURL& url, |
| const std::string& post_data, |
| const base::flat_map<std::string, std::string>& post_additional_headers, |
| ResponseStartedCallback response_started_callback, |
| ProgressCallback progress_callback, |
| PostRequestCompleteCallback post_request_complete_callback) { |
| DCHECK(!simple_url_loader_); |
| auto resource_request = std::make_unique<network::ResourceRequest>(); |
| resource_request->url = url; |
| resource_request->method = "POST"; |
| resource_request->load_flags = net::LOAD_DO_NOT_SEND_COOKIES | |
| net::LOAD_DO_NOT_SAVE_COOKIES | |
| net::LOAD_DISABLE_CACHE; |
| for (const auto& header : post_additional_headers) |
| resource_request->headers.SetHeader(header.first, header.second); |
| simple_url_loader_ = network::SimpleURLLoader::Create( |
| std::move(resource_request), traffic_annotation); |
| simple_url_loader_->SetRetryOptions( |
| kMaxRetriesOnNetworkChange, |
| network::SimpleURLLoader::RETRY_ON_NETWORK_CHANGE); |
| simple_url_loader_->AttachStringForUpload(post_data, "application/json"); |
| simple_url_loader_->SetOnResponseStartedCallback(base::BindOnce( |
| &NetworkFetcherImpl::OnResponseStartedCallback, base::Unretained(this), |
| std::move(response_started_callback))); |
| simple_url_loader_->SetOnDownloadProgressCallback(base::BindRepeating( |
| &NetworkFetcherImpl::OnProgressCallback, base::Unretained(this), |
| std::move(progress_callback))); |
| constexpr size_t kMaxResponseSize = 1024 * 1024; |
| simple_url_loader_->DownloadToString( |
| shared_url_network_factory_.get(), |
| base::BindOnce( |
| [](const network::SimpleURLLoader* simple_url_loader, |
| PostRequestCompleteCallback post_request_complete_callback, |
| std::unique_ptr<std::string> response_body) { |
| std::move(post_request_complete_callback) |
| .Run(std::move(response_body), simple_url_loader->NetError(), |
| GetStringHeader(simple_url_loader, kHeaderEtag), |
| GetInt64Header(simple_url_loader, kHeaderXRetryAfter)); |
| }, |
| simple_url_loader_.get(), std::move(post_request_complete_callback)), |
| kMaxResponseSize); |
| } |
| |
| void NetworkFetcherImpl::DownloadToFile( |
| const GURL& url, |
| const base::FilePath& file_path, |
| ResponseStartedCallback response_started_callback, |
| ProgressCallback progress_callback, |
| DownloadToFileCompleteCallback download_to_file_complete_callback) { |
| DCHECK(!simple_url_loader_); |
| auto resource_request = std::make_unique<network::ResourceRequest>(); |
| resource_request->url = url; |
| resource_request->method = "GET"; |
| resource_request->load_flags = net::LOAD_DO_NOT_SEND_COOKIES | |
| net::LOAD_DO_NOT_SAVE_COOKIES | |
| net::LOAD_DISABLE_CACHE; |
| simple_url_loader_ = network::SimpleURLLoader::Create( |
| std::move(resource_request), traffic_annotation); |
| simple_url_loader_->SetRetryOptions( |
| kMaxRetriesOnNetworkChange, |
| network::SimpleURLLoader::RetryMode::RETRY_ON_NETWORK_CHANGE); |
| simple_url_loader_->SetAllowPartialResults(true); |
| simple_url_loader_->SetOnResponseStartedCallback(base::BindOnce( |
| &NetworkFetcherImpl::OnResponseStartedCallback, base::Unretained(this), |
| std::move(response_started_callback))); |
| simple_url_loader_->SetOnDownloadProgressCallback(base::BindRepeating( |
| &NetworkFetcherImpl::OnProgressCallback, base::Unretained(this), |
| std::move(progress_callback))); |
| simple_url_loader_->DownloadToFile( |
| shared_url_network_factory_.get(), |
| base::BindOnce( |
| [](const network::SimpleURLLoader* simple_url_loader, |
| DownloadToFileCompleteCallback download_to_file_complete_callback, |
| base::FilePath file_path) { |
| std::move(download_to_file_complete_callback) |
| .Run(file_path, simple_url_loader->NetError(), |
| simple_url_loader->GetContentSize()); |
| }, |
| simple_url_loader_.get(), |
| std::move(download_to_file_complete_callback)), |
| file_path); |
| } |
| |
| void NetworkFetcherImpl::OnResponseStartedCallback( |
| ResponseStartedCallback response_started_callback, |
| const GURL& final_url, |
| const network::ResourceResponseHead& response_head) { |
| std::move(response_started_callback) |
| .Run(final_url, |
| response_head.headers ? response_head.headers->response_code() : -1, |
| response_head.content_length); |
| } |
| |
| void NetworkFetcherImpl::OnProgressCallback(ProgressCallback progress_callback, |
| uint64_t current) { |
| progress_callback.Run(base::saturated_cast<int64_t>(current)); |
| } |
| |
| NetworkFetcherChromiumFactory::NetworkFetcherChromiumFactory( |
| scoped_refptr<network::SharedURLLoaderFactory> shared_url_network_factory) |
| : shared_url_network_factory_(shared_url_network_factory) {} |
| |
| NetworkFetcherChromiumFactory::~NetworkFetcherChromiumFactory() = default; |
| |
| std::unique_ptr<NetworkFetcher> NetworkFetcherChromiumFactory::Create() const { |
| return std::make_unique<NetworkFetcherImpl>(shared_url_network_factory_); |
| } |
| |
| } // namespace update_client |