| // 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 |