Provide GUID in ONC for all networks in ManagedNetworkConfigurationHandler
[chromium-blink-merge.git] / sync / internal_api / http_bridge.cc
blob5a601b3dc38f462c6884af250820bb67b73c04e8
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.
5 #include "sync/internal_api/public/http_bridge.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/metrics/histogram_macros.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "net/base/load_flags.h"
11 #include "net/base/net_errors.h"
12 #include "net/cookies/cookie_monster.h"
13 #include "net/http/http_cache.h"
14 #include "net/http/http_network_layer.h"
15 #include "net/http/http_response_headers.h"
16 #include "net/url_request/static_http_user_agent_settings.h"
17 #include "net/url_request/url_fetcher.h"
18 #include "net/url_request/url_request_context.h"
19 #include "net/url_request/url_request_job_factory_impl.h"
20 #include "net/url_request/url_request_status.h"
21 #include "sync/internal_api/public/base/cancelation_signal.h"
23 namespace syncer {
25 namespace {
27 // It's possible for an http request to be silently stalled. We set a time
28 // limit for all http requests, beyond which the request is cancelled and
29 // treated as a transient failure.
30 const int kMaxHttpRequestTimeSeconds = 60 * 5; // 5 minutes.
32 // Helper method for logging timeouts via UMA.
33 void LogTimeout(bool timed_out) {
34 UMA_HISTOGRAM_BOOLEAN("Sync.URLFetchTimedOut", timed_out);
37 } // namespace
39 HttpBridge::RequestContextGetter::RequestContextGetter(
40 net::URLRequestContextGetter* baseline_context_getter,
41 const std::string& user_agent)
42 : baseline_context_getter_(baseline_context_getter),
43 network_task_runner_(
44 baseline_context_getter_->GetNetworkTaskRunner()),
45 user_agent_(user_agent) {
46 DCHECK(baseline_context_getter_.get());
47 DCHECK(network_task_runner_.get());
48 DCHECK(!user_agent_.empty());
51 HttpBridge::RequestContextGetter::~RequestContextGetter() {}
53 net::URLRequestContext*
54 HttpBridge::RequestContextGetter::GetURLRequestContext() {
55 // Lazily create the context.
56 if (!context_) {
57 net::URLRequestContext* baseline_context =
58 baseline_context_getter_->GetURLRequestContext();
59 context_.reset(
60 new RequestContext(baseline_context, GetNetworkTaskRunner(),
61 user_agent_));
62 baseline_context_getter_ = NULL;
65 return context_.get();
68 scoped_refptr<base::SingleThreadTaskRunner>
69 HttpBridge::RequestContextGetter::GetNetworkTaskRunner() const {
70 return network_task_runner_;
73 HttpBridgeFactory::HttpBridgeFactory(
74 const scoped_refptr<net::URLRequestContextGetter>& baseline_context_getter,
75 const NetworkTimeUpdateCallback& network_time_update_callback,
76 CancelationSignal* cancelation_signal)
77 : baseline_request_context_getter_(baseline_context_getter),
78 network_time_update_callback_(network_time_update_callback),
79 cancelation_signal_(cancelation_signal) {
80 // Registration should never fail. This should happen on the UI thread during
81 // init. It would be impossible for a shutdown to have been requested at this
82 // point.
83 bool result = cancelation_signal_->TryRegisterHandler(this);
84 DCHECK(result);
87 HttpBridgeFactory::~HttpBridgeFactory() {
88 cancelation_signal_->UnregisterHandler(this);
91 void HttpBridgeFactory::Init(const std::string& user_agent) {
92 base::AutoLock lock(context_getter_lock_);
94 if (!baseline_request_context_getter_.get()) {
95 // Uh oh. We've been aborted before we finished initializing. There's no
96 // point in initializating further; let's just return right away.
97 return;
100 request_context_getter_ = new HttpBridge::RequestContextGetter(
101 baseline_request_context_getter_.get(), user_agent);
104 HttpPostProviderInterface* HttpBridgeFactory::Create() {
105 base::AutoLock lock(context_getter_lock_);
107 // If we've been asked to shut down (something which may happen asynchronously
108 // and at pretty much any time), then we won't have a request_context_getter_.
109 // Some external mechanism must ensure that this function is not called after
110 // we've been asked to shut down.
111 CHECK(request_context_getter_.get());
113 HttpBridge* http = new HttpBridge(request_context_getter_.get(),
114 network_time_update_callback_);
115 http->AddRef();
116 return http;
119 void HttpBridgeFactory::Destroy(HttpPostProviderInterface* http) {
120 static_cast<HttpBridge*>(http)->Release();
123 void HttpBridgeFactory::OnSignalReceived() {
124 base::AutoLock lock(context_getter_lock_);
125 // Release |baseline_request_context_getter_| as soon as possible so that it
126 // is destroyed in the right order on its network task runner. The
127 // |request_context_getter_| has a reference to the baseline, so we must
128 // drop our reference to it, too.
129 baseline_request_context_getter_ = NULL;
130 request_context_getter_ = NULL;
133 HttpBridge::RequestContext::RequestContext(
134 net::URLRequestContext* baseline_context,
135 const scoped_refptr<base::SingleThreadTaskRunner>&
136 network_task_runner,
137 const std::string& user_agent)
138 : network_task_runner_(network_task_runner),
139 job_factory_(new net::URLRequestJobFactoryImpl()) {
140 DCHECK(!user_agent.empty());
142 // Create empty, in-memory cookie store.
143 set_cookie_store(new net::CookieMonster(NULL, NULL));
145 // We don't use a cache for bridged loads, but we do want to share proxy info.
146 set_host_resolver(baseline_context->host_resolver());
147 set_proxy_service(baseline_context->proxy_service());
148 set_ssl_config_service(baseline_context->ssl_config_service());
150 // Use its own job factory, which only supports http and https.
151 set_job_factory(job_factory_.get());
153 // We want to share the HTTP session data with the network layer factory,
154 // which includes auth_cache for proxies.
155 // Session is not refcounted so we need to be careful to not lose the parent
156 // context.
157 net::HttpNetworkSession* session =
158 baseline_context->http_transaction_factory()->GetSession();
159 DCHECK(session);
160 set_http_transaction_factory(new net::HttpNetworkLayer(session));
162 // TODO(timsteele): We don't currently listen for pref changes of these
163 // fields or CookiePolicy; I'm not sure we want to strictly follow the
164 // default settings, since for example if the user chooses to block all
165 // cookies, sync will start failing. Also it seems like accept_lang/charset
166 // should be tied to whatever the sync servers expect (if anything). These
167 // fields should probably just be settable by sync backend; though we should
168 // figure out if we need to give the user explicit control over policies etc.
169 std::string accepted_language_list;
170 if (baseline_context->http_user_agent_settings()) {
171 accepted_language_list =
172 baseline_context->http_user_agent_settings()->GetAcceptLanguage();
174 http_user_agent_settings_.reset(new net::StaticHttpUserAgentSettings(
175 accepted_language_list,
176 user_agent));
177 set_http_user_agent_settings(http_user_agent_settings_.get());
179 set_net_log(baseline_context->net_log());
182 HttpBridge::RequestContext::~RequestContext() {
183 AssertNoURLRequests();
184 DCHECK(network_task_runner_->BelongsToCurrentThread());
185 delete http_transaction_factory();
188 HttpBridge::URLFetchState::URLFetchState()
189 : url_poster(NULL),
190 aborted(false),
191 request_completed(false),
192 request_succeeded(false),
193 http_response_code(-1),
194 error_code(-1) {
196 HttpBridge::URLFetchState::~URLFetchState() {}
198 HttpBridge::HttpBridge(
199 HttpBridge::RequestContextGetter* context_getter,
200 const NetworkTimeUpdateCallback& network_time_update_callback)
201 : created_on_loop_(base::MessageLoop::current()),
202 http_post_completed_(false, false),
203 context_getter_for_request_(context_getter),
204 network_task_runner_(
205 context_getter_for_request_->GetNetworkTaskRunner()),
206 network_time_update_callback_(network_time_update_callback) {
209 HttpBridge::~HttpBridge() {
212 void HttpBridge::SetExtraRequestHeaders(const char * headers) {
213 DCHECK(extra_headers_.empty())
214 << "HttpBridge::SetExtraRequestHeaders called twice.";
215 extra_headers_.assign(headers);
218 void HttpBridge::SetURL(const char* url, int port) {
219 #if DCHECK_IS_ON()
220 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_);
222 base::AutoLock lock(fetch_state_lock_);
223 DCHECK(!fetch_state_.request_completed);
225 DCHECK(url_for_request_.is_empty())
226 << "HttpBridge::SetURL called more than once?!";
227 #endif
228 GURL temp(url);
229 GURL::Replacements replacements;
230 std::string port_str = base::IntToString(port);
231 replacements.SetPort(port_str.c_str(), url::Component(0, port_str.length()));
232 url_for_request_ = temp.ReplaceComponents(replacements);
235 void HttpBridge::SetPostPayload(const char* content_type,
236 int content_length,
237 const char* content) {
238 #if DCHECK_IS_ON()
239 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_);
241 base::AutoLock lock(fetch_state_lock_);
242 DCHECK(!fetch_state_.request_completed);
244 DCHECK(content_type_.empty()) << "Bridge payload already set.";
245 DCHECK_GE(content_length, 0) << "Content length < 0";
246 #endif
247 content_type_ = content_type;
248 if (!content || (content_length == 0)) {
249 DCHECK_EQ(content_length, 0);
250 request_content_ = " "; // TODO(timsteele): URLFetcher requires non-empty
251 // content for POSTs whereas CURL does not, for now
252 // we hack this to support the sync backend.
253 } else {
254 request_content_.assign(content, content_length);
258 bool HttpBridge::MakeSynchronousPost(int* error_code, int* response_code) {
259 #if DCHECK_IS_ON()
260 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_);
262 base::AutoLock lock(fetch_state_lock_);
263 DCHECK(!fetch_state_.request_completed);
265 DCHECK(url_for_request_.is_valid()) << "Invalid URL for request";
266 DCHECK(!content_type_.empty()) << "Payload not set";
267 #endif
269 if (!network_task_runner_->PostTask(
270 FROM_HERE,
271 base::Bind(&HttpBridge::CallMakeAsynchronousPost, this))) {
272 // This usually happens when we're in a unit test.
273 LOG(WARNING) << "Could not post CallMakeAsynchronousPost task";
274 return false;
277 // Block until network request completes or is aborted. See
278 // OnURLFetchComplete and Abort.
279 http_post_completed_.Wait();
281 base::AutoLock lock(fetch_state_lock_);
282 DCHECK(fetch_state_.request_completed || fetch_state_.aborted);
283 *error_code = fetch_state_.error_code;
284 *response_code = fetch_state_.http_response_code;
285 return fetch_state_.request_succeeded;
288 void HttpBridge::MakeAsynchronousPost() {
289 DCHECK(network_task_runner_->BelongsToCurrentThread());
291 base::AutoLock lock(fetch_state_lock_);
292 DCHECK(!fetch_state_.request_completed);
293 if (fetch_state_.aborted)
294 return;
296 // Start the timer on the network thread (the same thread progress is made
297 // on, and on which the url fetcher lives).
298 DCHECK(!fetch_state_.http_request_timeout_timer.get());
299 fetch_state_.http_request_timeout_timer.reset(new base::Timer(false, false));
300 fetch_state_.http_request_timeout_timer->Start(
301 FROM_HERE, base::TimeDelta::FromSeconds(kMaxHttpRequestTimeSeconds),
302 base::Bind(&HttpBridge::OnURLFetchTimedOut, this));
304 DCHECK(context_getter_for_request_.get());
305 fetch_state_.url_poster = net::URLFetcher::Create(
306 url_for_request_, net::URLFetcher::POST, this);
307 fetch_state_.url_poster->SetRequestContext(context_getter_for_request_.get());
308 fetch_state_.url_poster->SetUploadData(content_type_, request_content_);
309 fetch_state_.url_poster->SetExtraRequestHeaders(extra_headers_);
310 fetch_state_.url_poster->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES);
311 fetch_state_.start_time = base::Time::Now();
313 fetch_state_.url_poster->Start();
316 int HttpBridge::GetResponseContentLength() const {
317 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_);
318 base::AutoLock lock(fetch_state_lock_);
319 DCHECK(fetch_state_.request_completed);
320 return fetch_state_.response_content.size();
323 const char* HttpBridge::GetResponseContent() const {
324 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_);
325 base::AutoLock lock(fetch_state_lock_);
326 DCHECK(fetch_state_.request_completed);
327 return fetch_state_.response_content.data();
330 const std::string HttpBridge::GetResponseHeaderValue(
331 const std::string& name) const {
333 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_);
334 base::AutoLock lock(fetch_state_lock_);
335 DCHECK(fetch_state_.request_completed);
337 std::string value;
338 fetch_state_.response_headers->EnumerateHeader(NULL, name, &value);
339 return value;
342 void HttpBridge::Abort() {
343 base::AutoLock lock(fetch_state_lock_);
345 // Release |request_context_getter_| as soon as possible so that it is
346 // destroyed in the right order on its network task runner.
347 context_getter_for_request_ = NULL;
349 DCHECK(!fetch_state_.aborted);
350 if (fetch_state_.aborted || fetch_state_.request_completed)
351 return;
353 fetch_state_.aborted = true;
354 if (!network_task_runner_->PostTask(
355 FROM_HERE,
356 base::Bind(&HttpBridge::DestroyURLFetcherOnIOThread, this,
357 fetch_state_.url_poster,
358 fetch_state_.http_request_timeout_timer.release()))) {
359 // Madness ensues.
360 NOTREACHED() << "Could not post task to delete URLFetcher";
363 fetch_state_.url_poster = NULL;
364 fetch_state_.error_code = net::ERR_ABORTED;
365 http_post_completed_.Signal();
368 void HttpBridge::DestroyURLFetcherOnIOThread(
369 net::URLFetcher* fetcher,
370 base::Timer* fetch_timer) {
371 DCHECK(network_task_runner_->BelongsToCurrentThread());
372 if (fetch_timer)
373 delete fetch_timer;
374 delete fetcher;
377 void HttpBridge::OnURLFetchComplete(const net::URLFetcher* source) {
378 DCHECK(network_task_runner_->BelongsToCurrentThread());
380 base::AutoLock lock(fetch_state_lock_);
382 // Stop the request timer now that the request completed.
383 if (fetch_state_.http_request_timeout_timer.get())
384 fetch_state_.http_request_timeout_timer.reset();
386 if (fetch_state_.aborted)
387 return;
389 fetch_state_.end_time = base::Time::Now();
390 fetch_state_.request_completed = true;
391 fetch_state_.request_succeeded =
392 (net::URLRequestStatus::SUCCESS == source->GetStatus().status());
393 fetch_state_.http_response_code = source->GetResponseCode();
394 fetch_state_.error_code = source->GetStatus().error();
396 if (fetch_state_.request_succeeded)
397 LogTimeout(false);
398 UMA_HISTOGRAM_LONG_TIMES("Sync.URLFetchTime",
399 fetch_state_.end_time - fetch_state_.start_time);
401 // Use a real (non-debug) log to facilitate troubleshooting in the wild.
402 VLOG(2) << "HttpBridge::OnURLFetchComplete for: "
403 << fetch_state_.url_poster->GetURL().spec();
404 VLOG(1) << "HttpBridge received response code: "
405 << fetch_state_.http_response_code;
407 source->GetResponseAsString(&fetch_state_.response_content);
408 fetch_state_.response_headers = source->GetResponseHeaders();
409 UpdateNetworkTime();
411 // End of the line for url_poster_. It lives only on the IO loop.
412 // We defer deletion because we're inside a callback from a component of the
413 // URLFetcher, so it seems most natural / "polite" to let the stack unwind.
414 base::MessageLoop::current()->DeleteSoon(FROM_HERE, fetch_state_.url_poster);
415 fetch_state_.url_poster = NULL;
417 // Wake the blocked syncer thread in MakeSynchronousPost.
418 // WARNING: DONT DO ANYTHING AFTER THIS CALL! |this| may be deleted!
419 http_post_completed_.Signal();
422 void HttpBridge::OnURLFetchDownloadProgress(const net::URLFetcher* source,
423 int64 current, int64 total) {
424 DCHECK(network_task_runner_->BelongsToCurrentThread());
425 // Reset the delay when forward progress is made.
426 base::AutoLock lock(fetch_state_lock_);
427 if (fetch_state_.http_request_timeout_timer.get())
428 fetch_state_.http_request_timeout_timer->Reset();
431 void HttpBridge::OnURLFetchUploadProgress(const net::URLFetcher* source,
432 int64 current, int64 total) {
433 DCHECK(network_task_runner_->BelongsToCurrentThread());
434 // Reset the delay when forward progress is made.
435 base::AutoLock lock(fetch_state_lock_);
436 if (fetch_state_.http_request_timeout_timer.get())
437 fetch_state_.http_request_timeout_timer->Reset();
440 void HttpBridge::OnURLFetchTimedOut() {
441 DCHECK(network_task_runner_->BelongsToCurrentThread());
443 base::AutoLock lock(fetch_state_lock_);
444 if (!fetch_state_.url_poster)
445 return;
447 LogTimeout(true);
448 DVLOG(1) << "Sync url fetch timed out. Canceling.";
450 fetch_state_.end_time = base::Time::Now();
451 fetch_state_.request_completed = true;
452 fetch_state_.request_succeeded = false;
453 fetch_state_.http_response_code = -1;
454 fetch_state_.error_code = net::URLRequestStatus::FAILED;
456 // This method is called by the timer, not the url fetcher implementation,
457 // so it's safe to delete the fetcher here.
458 delete fetch_state_.url_poster;
459 fetch_state_.url_poster = NULL;
461 // Timer is smart enough to handle being deleted as part of the invoked task.
462 fetch_state_.http_request_timeout_timer.reset();
464 // Wake the blocked syncer thread in MakeSynchronousPost.
465 // WARNING: DONT DO ANYTHING AFTER THIS CALL! |this| may be deleted!
466 http_post_completed_.Signal();
469 net::URLRequestContextGetter* HttpBridge::GetRequestContextGetterForTest()
470 const {
471 base::AutoLock lock(fetch_state_lock_);
472 return context_getter_for_request_.get();
475 void HttpBridge::UpdateNetworkTime() {
476 std::string sane_time_str;
477 if (!fetch_state_.request_succeeded || fetch_state_.start_time.is_null() ||
478 fetch_state_.end_time < fetch_state_.start_time ||
479 !fetch_state_.response_headers ||
480 !fetch_state_.response_headers->EnumerateHeader(NULL, "Sane-Time-Millis",
481 &sane_time_str)) {
482 return;
485 int64 sane_time_ms = 0;
486 if (base::StringToInt64(sane_time_str, &sane_time_ms)) {
487 network_time_update_callback_.Run(
488 base::Time::FromJsTime(sane_time_ms),
489 base::TimeDelta::FromMilliseconds(1),
490 fetch_state_.end_time - fetch_state_.start_time);
494 } // namespace syncer