Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 1 | // Copyright 2012 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
maxbogue | f0ab40f5 | 2016-10-11 16:12:40 | [diff] [blame] | 5 | #include "components/sync/engine/net/http_bridge.h" |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 6 | |
| 7 | #include <stddef.h> |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 8 | |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 9 | #include <utility> |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 10 | |
Sebastien Marchand | 53801a3 | 2019-01-25 16:26:11 | [diff] [blame] | 11 | #include "base/bind.h" |
Matt Menke | 991dd7e | 2021-07-22 17:31:51 | [diff] [blame] | 12 | #include "base/lazy_instance.h" |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 13 | #include "base/location.h" |
Ilya Sherman | 1edb6f18 | 2017-12-12 04:00:42 | [diff] [blame] | 14 | #include "base/metrics/histogram_functions.h" |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 15 | #include "base/metrics/histogram_macros.h" |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 16 | #include "base/task/post_task.h" |
Gabriel Charette | dd8d5985e | 2020-02-26 18:38:35 | [diff] [blame] | 17 | #include "base/task/thread_pool.h" |
Olivier Li | 4db886a | 2019-11-13 13:48:22 | [diff] [blame] | 18 | #include "base/threading/thread_restrictions.h" |
Mikel Astiz | f66cb726 | 2019-12-04 20:16:45 | [diff] [blame] | 19 | #include "components/variations/net/variations_http_headers.h" |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 20 | #include "net/base/load_flags.h" |
| 21 | #include "net/base/net_errors.h" |
| 22 | #include "net/http/http_cache.h" |
| 23 | #include "net/http/http_network_layer.h" |
| 24 | #include "net/http/http_request_headers.h" |
| 25 | #include "net/http/http_response_headers.h" |
rhalavati | 75a414c | 2017-03-09 13:56:37 | [diff] [blame] | 26 | #include "net/traffic_annotation/network_traffic_annotation.h" |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 27 | #include "net/url_request/static_http_user_agent_settings.h" |
Sigurd Schneider | e3d43c6b | 2021-07-27 13:35:01 | [diff] [blame] | 28 | #include "services/network/public/cpp/resource_request.h" |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 29 | #include "services/network/public/cpp/simple_url_loader.h" |
Matt Menke | 5096a86 | 2021-07-17 20:30:00 | [diff] [blame] | 30 | #include "services/network/public/mojom/url_response_head.mojom.h" |
gangwu | 56d4822 | 2016-10-20 00:00:46 | [diff] [blame] | 31 | #include "third_party/zlib/google/compression_utils.h" |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 32 | |
| 33 | namespace syncer { |
| 34 | |
| 35 | namespace { |
| 36 | |
| 37 | // It's possible for an http request to be silently stalled. We set a time |
| 38 | // limit for all http requests, beyond which the request is cancelled and |
| 39 | // treated as a transient failure. |
Peter Kasting | e5a38ed | 2021-10-02 03:06:35 | [diff] [blame^] | 40 | constexpr base::TimeDelta kMaxHttpRequestTime = base::Minutes(5); |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 41 | |
| 42 | // Helper method for logging timeouts via UMA. |
| 43 | void LogTimeout(bool timed_out) { |
| 44 | UMA_HISTOGRAM_BOOLEAN("Sync.URLFetchTimedOut", timed_out); |
| 45 | } |
| 46 | |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 47 | base::LazyInstance<scoped_refptr<base::SequencedTaskRunner>>::Leaky |
| 48 | g_io_capable_task_runner_for_tests = LAZY_INSTANCE_INITIALIZER; |
| 49 | |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 50 | } // namespace |
| 51 | |
| 52 | HttpBridgeFactory::HttpBridgeFactory( |
Marc Treib | 0df8aa4 | 2019-11-14 13:51:32 | [diff] [blame] | 53 | const std::string& user_agent, |
Dominic Farolino | bc280d2 | 2019-12-05 05:49:24 | [diff] [blame] | 54 | std::unique_ptr<network::PendingSharedURLLoaderFactory> |
Victor Hugo Vianna Silva | aa498417 | 2021-06-29 11:29:19 | [diff] [blame] | 55 | pending_url_loader_factory) |
| 56 | : user_agent_(user_agent) { |
Dominic Farolino | bc280d2 | 2019-12-05 05:49:24 | [diff] [blame] | 57 | // Some tests pass null'ed out pending_url_loader_factory instances. |
| 58 | if (pending_url_loader_factory) { |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 59 | url_loader_factory_ = network::SharedURLLoaderFactory::Create( |
Dominic Farolino | bc280d2 | 2019-12-05 05:49:24 | [diff] [blame] | 60 | std::move(pending_url_loader_factory)); |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 61 | } |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 62 | } |
| 63 | |
Marc Treib | e6ace16 | 2019-11-13 15:23:22 | [diff] [blame] | 64 | HttpBridgeFactory::~HttpBridgeFactory() = default; |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 65 | |
Marc Treib | b9454e0 | 2020-10-13 09:31:07 | [diff] [blame] | 66 | scoped_refptr<HttpPostProviderInterface> HttpBridgeFactory::Create() { |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 67 | DCHECK(url_loader_factory_); |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 68 | |
Victor Hugo Vianna Silva | aa498417 | 2021-06-29 11:29:19 | [diff] [blame] | 69 | scoped_refptr<HttpPostProviderInterface> http = |
| 70 | new HttpBridge(user_agent_, url_loader_factory_->Clone()); |
Marc Treib | b9454e0 | 2020-10-13 09:31:07 | [diff] [blame] | 71 | return http; |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 72 | } |
| 73 | |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 74 | HttpBridge::URLFetchState::URLFetchState() |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 75 | : aborted(false), |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 76 | request_completed(false), |
| 77 | request_succeeded(false), |
Mikel Astiz | 1de5fe9 | 2018-11-23 11:43:42 | [diff] [blame] | 78 | http_status_code(-1), |
Mikel Astiz | 3a64405f | 2018-11-22 15:50:31 | [diff] [blame] | 79 | net_error_code(-1) {} |
Victor Hugo Vianna Silva | 988fe732 | 2021-09-23 18:16:56 | [diff] [blame] | 80 | HttpBridge::URLFetchState::~URLFetchState() = default; |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 81 | |
Victor Hugo Vianna Silva | aa498417 | 2021-06-29 11:29:19 | [diff] [blame] | 82 | HttpBridge::HttpBridge(const std::string& user_agent, |
| 83 | std::unique_ptr<network::PendingSharedURLLoaderFactory> |
| 84 | pending_url_loader_factory) |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 85 | : user_agent_(user_agent), |
| 86 | http_post_completed_(base::WaitableEvent::ResetPolicy::AUTOMATIC, |
| 87 | base::WaitableEvent::InitialState::NOT_SIGNALED), |
Dominic Farolino | bc280d2 | 2019-12-05 05:49:24 | [diff] [blame] | 88 | pending_url_loader_factory_(std::move(pending_url_loader_factory)), |
Sami Kyostila | 14ca764 | 2019-08-01 17:52:25 | [diff] [blame] | 89 | network_task_runner_(g_io_capable_task_runner_for_tests.Get() |
| 90 | ? g_io_capable_task_runner_for_tests.Get() |
Gabriel Charette | dd8d5985e | 2020-02-26 18:38:35 | [diff] [blame] | 91 | : base::ThreadPool::CreateSequencedTaskRunner( |
Victor Hugo Vianna Silva | aa498417 | 2021-06-29 11:29:19 | [diff] [blame] | 92 | {base::MayBlock()})) {} |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 93 | |
Marc Treib | b9454e0 | 2020-10-13 09:31:07 | [diff] [blame] | 94 | HttpBridge::~HttpBridge() = default; |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 95 | |
| 96 | void HttpBridge::SetExtraRequestHeaders(const char* headers) { |
| 97 | DCHECK(extra_headers_.empty()) |
| 98 | << "HttpBridge::SetExtraRequestHeaders called twice."; |
| 99 | extra_headers_.assign(headers); |
| 100 | } |
| 101 | |
Marc Treib | bdbf7542 | 2020-10-15 09:42:39 | [diff] [blame] | 102 | void HttpBridge::SetURL(const GURL& url) { |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 103 | #if DCHECK_IS_ON() |
| 104 | DCHECK(thread_checker_.CalledOnValidThread()); |
| 105 | { |
| 106 | base::AutoLock lock(fetch_state_lock_); |
| 107 | DCHECK(!fetch_state_.request_completed); |
| 108 | } |
| 109 | DCHECK(url_for_request_.is_empty()) |
| 110 | << "HttpBridge::SetURL called more than once?!"; |
| 111 | #endif |
Marc Treib | bdbf7542 | 2020-10-15 09:42:39 | [diff] [blame] | 112 | url_for_request_ = url; |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 113 | } |
| 114 | |
| 115 | void HttpBridge::SetPostPayload(const char* content_type, |
| 116 | int content_length, |
| 117 | const char* content) { |
| 118 | #if DCHECK_IS_ON() |
| 119 | DCHECK(thread_checker_.CalledOnValidThread()); |
| 120 | { |
| 121 | base::AutoLock lock(fetch_state_lock_); |
| 122 | DCHECK(!fetch_state_.request_completed); |
| 123 | } |
| 124 | DCHECK(content_type_.empty()) << "Bridge payload already set."; |
| 125 | DCHECK_GE(content_length, 0) << "Content length < 0"; |
| 126 | #endif |
| 127 | content_type_ = content_type; |
| 128 | if (!content || (content_length == 0)) { |
| 129 | DCHECK_EQ(content_length, 0); |
| 130 | request_content_ = " "; // TODO(timsteele): URLFetcher requires non-empty |
| 131 | // content for POSTs whereas CURL does not, for now |
| 132 | // we hack this to support the sync backend. |
| 133 | } else { |
| 134 | request_content_.assign(content, content_length); |
| 135 | } |
| 136 | } |
| 137 | |
Mikel Astiz | 3a64405f | 2018-11-22 15:50:31 | [diff] [blame] | 138 | bool HttpBridge::MakeSynchronousPost(int* net_error_code, |
Mikel Astiz | 1de5fe9 | 2018-11-23 11:43:42 | [diff] [blame] | 139 | int* http_status_code) { |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 140 | #if DCHECK_IS_ON() |
| 141 | DCHECK(thread_checker_.CalledOnValidThread()); |
| 142 | { |
| 143 | base::AutoLock lock(fetch_state_lock_); |
| 144 | DCHECK(!fetch_state_.request_completed); |
| 145 | } |
| 146 | DCHECK(url_for_request_.is_valid()) << "Invalid URL for request"; |
| 147 | DCHECK(!content_type_.empty()) << "Payload not set"; |
| 148 | #endif |
| 149 | |
| 150 | if (!network_task_runner_->PostTask( |
tzik | 2bcf8e4 | 2018-07-31 11:22:15 | [diff] [blame] | 151 | FROM_HERE, |
| 152 | base::BindOnce(&HttpBridge::CallMakeAsynchronousPost, this))) { |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 153 | // This usually happens when we're in a unit test. |
| 154 | LOG(WARNING) << "Could not post CallMakeAsynchronousPost task"; |
| 155 | return false; |
| 156 | } |
| 157 | |
| 158 | // Block until network request completes or is aborted. See |
| 159 | // OnURLFetchComplete and Abort. |
Olivier Li | 4db886a | 2019-11-13 13:48:22 | [diff] [blame] | 160 | { |
| 161 | base::ScopedAllowBaseSyncPrimitives allow_wait; |
| 162 | http_post_completed_.Wait(); |
| 163 | } |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 164 | |
| 165 | base::AutoLock lock(fetch_state_lock_); |
| 166 | DCHECK(fetch_state_.request_completed || fetch_state_.aborted); |
Mikel Astiz | 3a64405f | 2018-11-22 15:50:31 | [diff] [blame] | 167 | *net_error_code = fetch_state_.net_error_code; |
Mikel Astiz | 1de5fe9 | 2018-11-23 11:43:42 | [diff] [blame] | 168 | *http_status_code = fetch_state_.http_status_code; |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 169 | return fetch_state_.request_succeeded; |
| 170 | } |
| 171 | |
| 172 | void HttpBridge::MakeAsynchronousPost() { |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 173 | DCHECK(network_task_runner_->RunsTasksInCurrentSequence()); |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 174 | |
| 175 | base::AutoLock lock(fetch_state_lock_); |
| 176 | DCHECK(!fetch_state_.request_completed); |
| 177 | if (fetch_state_.aborted) |
| 178 | return; |
| 179 | |
| 180 | // Start the timer on the network thread (the same thread progress is made |
| 181 | // on, and on which the url fetcher lives). |
Zinovy Nis | 701103b | 2018-05-10 22:59:38 | [diff] [blame] | 182 | DCHECK(!fetch_state_.http_request_timeout_timer); |
Patrick Monette | ad70b87 | 2021-04-16 18:49:26 | [diff] [blame] | 183 | fetch_state_.http_request_timeout_timer = std::make_unique<base::DelayTimer>( |
| 184 | FROM_HERE, kMaxHttpRequestTime, this, &HttpBridge::OnURLLoadTimedOut); |
| 185 | fetch_state_.http_request_timeout_timer->Reset(); |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 186 | |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 187 | // Some tests inject |url_loader_factory_| created to operated on the |
| 188 | // IO-capable thread currently running. |
Dominic Farolino | bc280d2 | 2019-12-05 05:49:24 | [diff] [blame] | 189 | DCHECK((!url_loader_factory_ && pending_url_loader_factory_) || |
| 190 | (url_loader_factory_ && !pending_url_loader_factory_)); |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 191 | if (!url_loader_factory_) { |
Dominic Farolino | bc280d2 | 2019-12-05 05:49:24 | [diff] [blame] | 192 | DCHECK(pending_url_loader_factory_); |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 193 | url_loader_factory_ = network::SharedURLLoaderFactory::Create( |
Dominic Farolino | bc280d2 | 2019-12-05 05:49:24 | [diff] [blame] | 194 | std::move(pending_url_loader_factory_)); |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 195 | } |
| 196 | |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 197 | fetch_state_.start_time = base::Time::Now(); |
rhalavati | 75a414c | 2017-03-09 13:56:37 | [diff] [blame] | 198 | net::NetworkTrafficAnnotationTag traffic_annotation = |
| 199 | net::DefineNetworkTrafficAnnotation("sync_http_bridge", R"( |
| 200 | semantics { |
| 201 | sender: "Chrome Sync" |
| 202 | description: |
| 203 | "Chrome Sync synchronizes profile data between Chromium clients " |
| 204 | "and Google for a given user account." |
| 205 | trigger: |
| 206 | "User makes a change to syncable profile data after enabling sync " |
| 207 | "on the device." |
| 208 | data: |
| 209 | "The device and user identifiers, along with any profile data that " |
| 210 | "is changing." |
| 211 | destination: GOOGLE_OWNED_SERVICE |
| 212 | } |
| 213 | policy { |
Ramin Halavati | 3b97978 | 2017-07-21 11:40:26 | [diff] [blame] | 214 | cookies_allowed: NO |
rhalavati | 75a414c | 2017-03-09 13:56:37 | [diff] [blame] | 215 | setting: |
| 216 | "Users can disable Chrome Sync by going into the profile settings " |
| 217 | "and choosing to Sign Out." |
| 218 | chrome_policy { |
| 219 | SyncDisabled { |
| 220 | policy_options {mode: MANDATORY} |
| 221 | SyncDisabled: true |
| 222 | } |
| 223 | } |
| 224 | })"); |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 225 | auto resource_request = std::make_unique<network::ResourceRequest>(); |
| 226 | resource_request->url = url_for_request_; |
| 227 | resource_request->method = "POST"; |
| 228 | resource_request->load_flags = |
David Benjamin | 29f864ef | 2019-08-13 20:51:01 | [diff] [blame] | 229 | net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE; |
| 230 | resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit; |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 231 | |
| 232 | if (!extra_headers_.empty()) |
| 233 | resource_request->headers.AddHeadersFromString(extra_headers_); |
| 234 | |
| 235 | resource_request->headers.SetHeader("Content-Encoding", "gzip"); |
| 236 | resource_request->headers.SetHeader(net::HttpRequestHeaders::kUserAgent, |
| 237 | user_agent_); |
| 238 | |
Mikel Astiz | f66cb726 | 2019-12-04 20:16:45 | [diff] [blame] | 239 | variations::AppendVariationsHeader( |
| 240 | url_for_request_, variations::InIncognito::kNo, |
| 241 | variations::SignedIn::kYes, resource_request.get()); |
| 242 | |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 243 | fetch_state_.url_loader = network::SimpleURLLoader::Create( |
| 244 | std::move(resource_request), traffic_annotation); |
| 245 | network::SimpleURLLoader* url_loader = fetch_state_.url_loader.get(); |
| 246 | |
gangwu | 56d4822 | 2016-10-20 00:00:46 | [diff] [blame] | 247 | std::string request_to_send; |
gangwu | a314137 | 2017-02-22 07:13:14 | [diff] [blame] | 248 | compression::GzipCompress(request_content_, &request_to_send); |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 249 | url_loader->AttachStringForUpload(request_to_send, content_type_); |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 250 | |
Antonio Gomes | 05b9b976 | 2018-09-11 17:10:45 | [diff] [blame] | 251 | // Sync relies on HTTP errors being detectable (and distinct from |
| 252 | // net/connection errors). |
| 253 | url_loader->SetAllowHttpErrorResults(true); |
| 254 | |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 255 | url_loader->SetOnUploadProgressCallback(base::BindRepeating( |
| 256 | &HttpBridge::OnURLLoadUploadProgress, base::Unretained(this))); |
| 257 | url_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( |
| 258 | url_loader_factory_.get(), |
| 259 | base::BindOnce(&HttpBridge::OnURLLoadComplete, base::Unretained(this))); |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 260 | } |
| 261 | |
| 262 | int HttpBridge::GetResponseContentLength() const { |
| 263 | DCHECK(thread_checker_.CalledOnValidThread()); |
| 264 | base::AutoLock lock(fetch_state_lock_); |
| 265 | DCHECK(fetch_state_.request_completed); |
| 266 | return fetch_state_.response_content.size(); |
| 267 | } |
| 268 | |
| 269 | const char* HttpBridge::GetResponseContent() const { |
| 270 | DCHECK(thread_checker_.CalledOnValidThread()); |
| 271 | base::AutoLock lock(fetch_state_lock_); |
| 272 | DCHECK(fetch_state_.request_completed); |
| 273 | return fetch_state_.response_content.data(); |
| 274 | } |
| 275 | |
| 276 | const std::string HttpBridge::GetResponseHeaderValue( |
| 277 | const std::string& name) const { |
| 278 | DCHECK(thread_checker_.CalledOnValidThread()); |
| 279 | base::AutoLock lock(fetch_state_lock_); |
| 280 | DCHECK(fetch_state_.request_completed); |
| 281 | |
| 282 | std::string value; |
skym | 8d8162f | 2016-10-17 22:12:44 | [diff] [blame] | 283 | fetch_state_.response_headers->EnumerateHeader(nullptr, name, &value); |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 284 | return value; |
| 285 | } |
| 286 | |
| 287 | void HttpBridge::Abort() { |
| 288 | base::AutoLock lock(fetch_state_lock_); |
| 289 | |
Dominic Farolino | bc280d2 | 2019-12-05 05:49:24 | [diff] [blame] | 290 | // Release |pending_url_loader_factory_| as soon as possible so that |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 291 | // no URLLoaderFactory instances proceed on the network task runner. |
Dominic Farolino | bc280d2 | 2019-12-05 05:49:24 | [diff] [blame] | 292 | pending_url_loader_factory_.reset(); |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 293 | |
| 294 | DCHECK(!fetch_state_.aborted); |
| 295 | if (fetch_state_.aborted || fetch_state_.request_completed) |
| 296 | return; |
| 297 | |
| 298 | fetch_state_.aborted = true; |
| 299 | if (!network_task_runner_->PostTask( |
| 300 | FROM_HERE, |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 301 | base::BindOnce(&HttpBridge::DestroyURLLoaderOnIOThread, this, |
| 302 | std::move(fetch_state_.url_loader), |
| 303 | std::move(fetch_state_.http_request_timeout_timer)))) { |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 304 | // Madness ensues. |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 305 | NOTREACHED() << "Could not post task to delete URLLoader"; |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 306 | } |
| 307 | |
Mikel Astiz | 3a64405f | 2018-11-22 15:50:31 | [diff] [blame] | 308 | fetch_state_.net_error_code = net::ERR_ABORTED; |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 309 | http_post_completed_.Signal(); |
| 310 | } |
| 311 | |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 312 | void HttpBridge::DestroyURLLoaderOnIOThread( |
| 313 | std::unique_ptr<network::SimpleURLLoader> loader, |
Patrick Monette | ad70b87 | 2021-04-16 18:49:26 | [diff] [blame] | 314 | std::unique_ptr<base::DelayTimer> loader_timer) { |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 315 | DCHECK(network_task_runner_->RunsTasksInCurrentSequence()); |
Zinovy Nis | 701103b | 2018-05-10 22:59:38 | [diff] [blame] | 316 | |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 317 | // Both |loader_timer| and |loader| go out of scope. |
| 318 | url_loader_factory_ = nullptr; |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 319 | } |
| 320 | |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 321 | void HttpBridge::OnURLLoadComplete(std::unique_ptr<std::string> response_body) { |
| 322 | DCHECK(network_task_runner_->RunsTasksInCurrentSequence()); |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 323 | |
| 324 | base::AutoLock lock(fetch_state_lock_); |
| 325 | |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 326 | network::SimpleURLLoader* url_loader = fetch_state_.url_loader.get(); |
Maks Orlovich | e95c2566 | 2018-08-30 17:56:04 | [diff] [blame] | 327 | // If the fetch completes in the window between Abort() and |
| 328 | // DestroyURLLoaderOnIOThread() this will still run. Abort() has already |
| 329 | // reported the result, so no extra work is needed. |
| 330 | if (fetch_state_.aborted) |
| 331 | return; |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 332 | |
Mikel Astiz | 1de5fe9 | 2018-11-23 11:43:42 | [diff] [blame] | 333 | int http_status_code = -1; |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 334 | if (url_loader->ResponseInfo() && url_loader->ResponseInfo()->headers) { |
Mikel Astiz | 1de5fe9 | 2018-11-23 11:43:42 | [diff] [blame] | 335 | http_status_code = url_loader->ResponseInfo()->headers->response_code(); |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 336 | fetch_state_.response_headers = url_loader->ResponseInfo()->headers; |
| 337 | } |
| 338 | |
Angelika Kurtz | d266ea6 | 2019-04-10 09:22:18 | [diff] [blame] | 339 | OnURLLoadCompleteInternal(http_status_code, url_loader->NetError(), |
| 340 | url_loader->GetFinalURL(), |
| 341 | std::move(response_body)); |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 342 | } |
| 343 | |
| 344 | void HttpBridge::OnURLLoadCompleteInternal( |
Mikel Astiz | 1de5fe9 | 2018-11-23 11:43:42 | [diff] [blame] | 345 | int http_status_code, |
Mikel Astiz | 3a64405f | 2018-11-22 15:50:31 | [diff] [blame] | 346 | int net_error_code, |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 347 | const GURL& final_url, |
| 348 | std::unique_ptr<std::string> response_body) { |
| 349 | DCHECK(network_task_runner_->RunsTasksInCurrentSequence()); |
| 350 | |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 351 | // Stop the request timer now that the request completed. |
Patrick Monette | ad70b87 | 2021-04-16 18:49:26 | [diff] [blame] | 352 | fetch_state_.http_request_timeout_timer = nullptr; |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 353 | |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 354 | // TODO(crbug.com/844968): Relax this if-check to become a DCHECK? |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 355 | if (fetch_state_.aborted) |
| 356 | return; |
| 357 | |
| 358 | fetch_state_.end_time = base::Time::Now(); |
| 359 | fetch_state_.request_completed = true; |
Mikel Astiz | 3a64405f | 2018-11-22 15:50:31 | [diff] [blame] | 360 | fetch_state_.request_succeeded = |
Mikel Astiz | 1de5fe9 | 2018-11-23 11:43:42 | [diff] [blame] | 361 | net_error_code == net::OK && http_status_code != -1; |
| 362 | fetch_state_.http_status_code = http_status_code; |
Mikel Astiz | 3a64405f | 2018-11-22 15:50:31 | [diff] [blame] | 363 | fetch_state_.net_error_code = net_error_code; |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 364 | |
| 365 | if (fetch_state_.request_succeeded) |
| 366 | LogTimeout(false); |
Matt Menke | 62723469 | 2019-12-18 13:36:10 | [diff] [blame] | 367 | base::UmaHistogramSparse("Sync.URLFetchResponse", |
| 368 | fetch_state_.request_succeeded |
| 369 | ? fetch_state_.http_status_code |
| 370 | : fetch_state_.net_error_code); |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 371 | |
| 372 | // Use a real (non-debug) log to facilitate troubleshooting in the wild. |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 373 | VLOG(2) << "HttpBridge::OnURLFetchComplete for: " << final_url.spec(); |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 374 | VLOG(1) << "HttpBridge received response code: " |
Mikel Astiz | 1de5fe9 | 2018-11-23 11:43:42 | [diff] [blame] | 375 | << fetch_state_.http_status_code; |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 376 | |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 377 | if (response_body) |
| 378 | fetch_state_.response_content = std::move(*response_body); |
| 379 | |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 380 | fetch_state_.url_loader.reset(); |
| 381 | url_loader_factory_ = nullptr; |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 382 | |
| 383 | // Wake the blocked syncer thread in MakeSynchronousPost. |
| 384 | // WARNING: DONT DO ANYTHING AFTER THIS CALL! |this| may be deleted! |
| 385 | http_post_completed_.Signal(); |
| 386 | } |
| 387 | |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 388 | void HttpBridge::OnURLLoadUploadProgress(uint64_t position, uint64_t total) { |
| 389 | DCHECK(network_task_runner_->RunsTasksInCurrentSequence()); |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 390 | // Reset the delay when forward progress is made. |
| 391 | base::AutoLock lock(fetch_state_lock_); |
Zinovy Nis | 701103b | 2018-05-10 22:59:38 | [diff] [blame] | 392 | if (fetch_state_.http_request_timeout_timer) |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 393 | fetch_state_.http_request_timeout_timer->Reset(); |
| 394 | } |
| 395 | |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 396 | void HttpBridge::OnURLLoadTimedOut() { |
| 397 | DCHECK(network_task_runner_->RunsTasksInCurrentSequence()); |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 398 | |
| 399 | base::AutoLock lock(fetch_state_lock_); |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 400 | if (!fetch_state_.url_loader) |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 401 | return; |
| 402 | |
| 403 | LogTimeout(true); |
| 404 | DVLOG(1) << "Sync url fetch timed out. Canceling."; |
| 405 | |
| 406 | fetch_state_.end_time = base::Time::Now(); |
| 407 | fetch_state_.request_completed = true; |
| 408 | fetch_state_.request_succeeded = false; |
Mikel Astiz | 1de5fe9 | 2018-11-23 11:43:42 | [diff] [blame] | 409 | fetch_state_.http_status_code = -1; |
Mikel Astiz | 3a64405f | 2018-11-22 15:50:31 | [diff] [blame] | 410 | fetch_state_.net_error_code = net::ERR_TIMED_OUT; |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 411 | |
| 412 | // This method is called by the timer, not the url fetcher implementation, |
| 413 | // so it's safe to delete the fetcher here. |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 414 | fetch_state_.url_loader.reset(); |
| 415 | url_loader_factory_ = nullptr; |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 416 | |
| 417 | // Timer is smart enough to handle being deleted as part of the invoked task. |
Patrick Monette | ad70b87 | 2021-04-16 18:49:26 | [diff] [blame] | 418 | fetch_state_.http_request_timeout_timer = nullptr; |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 419 | |
| 420 | // Wake the blocked syncer thread in MakeSynchronousPost. |
| 421 | // WARNING: DONT DO ANYTHING AFTER THIS CALL! |this| may be deleted! |
| 422 | http_post_completed_.Signal(); |
| 423 | } |
| 424 | |
Antonio Gomes | bf4f299 | 2018-08-25 03:35:07 | [diff] [blame] | 425 | void HttpBridge::SetIOCapableTaskRunnerForTest( |
| 426 | scoped_refptr<base::SequencedTaskRunner> task_runner) { |
| 427 | g_io_capable_task_runner_for_tests.Get() = task_runner; |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 428 | } |
| 429 | |
Max Bogue | fef332d | 2016-07-28 22:09:09 | [diff] [blame] | 430 | } // namespace syncer |