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 5#include "sync/internal_api/public/http_bridge.h" 6 7#include "base/message_loop/message_loop.h" 8#include "base/message_loop/message_loop_proxy.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" 22 23namespace syncer { 24 25HttpBridge::RequestContextGetter::RequestContextGetter( 26 net::URLRequestContextGetter* baseline_context_getter, 27 const std::string& user_agent) 28 : baseline_context_getter_(baseline_context_getter), 29 network_task_runner_( 30 baseline_context_getter_->GetNetworkTaskRunner()), 31 user_agent_(user_agent) { 32 DCHECK(baseline_context_getter_.get()); 33 DCHECK(network_task_runner_.get()); 34 DCHECK(!user_agent_.empty()); 35} 36 37HttpBridge::RequestContextGetter::~RequestContextGetter() {} 38 39net::URLRequestContext* 40HttpBridge::RequestContextGetter::GetURLRequestContext() { 41 // Lazily create the context. 42 if (!context_) { 43 net::URLRequestContext* baseline_context = 44 baseline_context_getter_->GetURLRequestContext(); 45 context_.reset( 46 new RequestContext(baseline_context, GetNetworkTaskRunner(), 47 user_agent_)); 48 baseline_context_getter_ = NULL; 49 } 50 51 return context_.get(); 52} 53 54scoped_refptr<base::SingleThreadTaskRunner> 55HttpBridge::RequestContextGetter::GetNetworkTaskRunner() const { 56 return network_task_runner_; 57} 58 59HttpBridgeFactory::HttpBridgeFactory( 60 net::URLRequestContextGetter* baseline_context_getter, 61 const NetworkTimeUpdateCallback& network_time_update_callback, 62 CancelationSignal* cancelation_signal) 63 : baseline_request_context_getter_(baseline_context_getter), 64 network_time_update_callback_(network_time_update_callback), 65 cancelation_signal_(cancelation_signal) { 66 // Registration should never fail. This should happen on the UI thread during 67 // init. It would be impossible for a shutdown to have been requested at this 68 // point. 69 bool result = cancelation_signal_->TryRegisterHandler(this); 70 DCHECK(result); 71} 72 73HttpBridgeFactory::~HttpBridgeFactory() { 74 cancelation_signal_->UnregisterHandler(this); 75} 76 77void HttpBridgeFactory::Init(const std::string& user_agent) { 78 base::AutoLock lock(context_getter_lock_); 79 80 if (!baseline_request_context_getter_.get()) { 81 // Uh oh. We've been aborted before we finished initializing. There's no 82 // point in initializating further; let's just return right away. 83 return; 84 } 85 86 request_context_getter_ = 87 new HttpBridge::RequestContextGetter( 88 baseline_request_context_getter_, user_agent); 89} 90 91HttpPostProviderInterface* HttpBridgeFactory::Create() { 92 base::AutoLock lock(context_getter_lock_); 93 94 // If we've been asked to shut down (something which may happen asynchronously 95 // and at pretty much any time), then we won't have a request_context_getter_. 96 // Some external mechanism must ensure that this function is not called after 97 // we've been asked to shut down. 98 CHECK(request_context_getter_.get()); 99 100 HttpBridge* http = new HttpBridge(request_context_getter_.get(), 101 network_time_update_callback_); 102 http->AddRef(); 103 return http; 104} 105 106void HttpBridgeFactory::Destroy(HttpPostProviderInterface* http) { 107 static_cast<HttpBridge*>(http)->Release(); 108} 109 110void HttpBridgeFactory::OnSignalReceived() { 111 base::AutoLock lock(context_getter_lock_); 112 // Release |baseline_request_context_getter_| as soon as possible so that it 113 // is destroyed in the right order on its network task runner. The 114 // |request_context_getter_| has a reference to the baseline, so we must 115 // drop our reference to it, too. 116 baseline_request_context_getter_ = NULL; 117 request_context_getter_ = NULL; 118} 119 120HttpBridge::RequestContext::RequestContext( 121 net::URLRequestContext* baseline_context, 122 const scoped_refptr<base::SingleThreadTaskRunner>& 123 network_task_runner, 124 const std::string& user_agent) 125 : baseline_context_(baseline_context), 126 network_task_runner_(network_task_runner), 127 job_factory_(new net::URLRequestJobFactoryImpl()) { 128 DCHECK(!user_agent.empty()); 129 130 // Create empty, in-memory cookie store. 131 set_cookie_store(new net::CookieMonster(NULL, NULL)); 132 133 // We don't use a cache for bridged loads, but we do want to share proxy info. 134 set_host_resolver(baseline_context->host_resolver()); 135 set_proxy_service(baseline_context->proxy_service()); 136 set_ssl_config_service(baseline_context->ssl_config_service()); 137 138 // Use its own job factory, which only supports http and https. 139 set_job_factory(job_factory_.get()); 140 141 // We want to share the HTTP session data with the network layer factory, 142 // which includes auth_cache for proxies. 143 // Session is not refcounted so we need to be careful to not lose the parent 144 // context. 145 net::HttpNetworkSession* session = 146 baseline_context->http_transaction_factory()->GetSession(); 147 DCHECK(session); 148 set_http_transaction_factory(new net::HttpNetworkLayer(session)); 149 150 // TODO(timsteele): We don't currently listen for pref changes of these 151 // fields or CookiePolicy; I'm not sure we want to strictly follow the 152 // default settings, since for example if the user chooses to block all 153 // cookies, sync will start failing. Also it seems like accept_lang/charset 154 // should be tied to whatever the sync servers expect (if anything). These 155 // fields should probably just be settable by sync backend; though we should 156 // figure out if we need to give the user explicit control over policies etc. 157 std::string accepted_language_list; 158 if (baseline_context->http_user_agent_settings()) { 159 accepted_language_list = 160 baseline_context->http_user_agent_settings()->GetAcceptLanguage(); 161 } 162 http_user_agent_settings_.reset(new net::StaticHttpUserAgentSettings( 163 accepted_language_list, 164 user_agent)); 165 set_http_user_agent_settings(http_user_agent_settings_.get()); 166 167 set_net_log(baseline_context->net_log()); 168} 169 170HttpBridge::RequestContext::~RequestContext() { 171 DCHECK(network_task_runner_->BelongsToCurrentThread()); 172 delete http_transaction_factory(); 173} 174 175HttpBridge::URLFetchState::URLFetchState() : url_poster(NULL), 176 aborted(false), 177 request_completed(false), 178 request_succeeded(false), 179 http_response_code(-1), 180 error_code(-1) {} 181HttpBridge::URLFetchState::~URLFetchState() {} 182 183HttpBridge::HttpBridge( 184 HttpBridge::RequestContextGetter* context_getter, 185 const NetworkTimeUpdateCallback& network_time_update_callback) 186 : created_on_loop_(base::MessageLoop::current()), 187 http_post_completed_(false, false), 188 context_getter_for_request_(context_getter), 189 network_task_runner_( 190 context_getter_for_request_->GetNetworkTaskRunner()), 191 network_time_update_callback_(network_time_update_callback) { 192} 193 194HttpBridge::~HttpBridge() { 195} 196 197void HttpBridge::SetExtraRequestHeaders(const char * headers) { 198 DCHECK(extra_headers_.empty()) 199 << "HttpBridge::SetExtraRequestHeaders called twice."; 200 extra_headers_.assign(headers); 201} 202 203void HttpBridge::SetURL(const char* url, int port) { 204#if DCHECK_IS_ON 205 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_); 206 { 207 base::AutoLock lock(fetch_state_lock_); 208 DCHECK(!fetch_state_.request_completed); 209 } 210 DCHECK(url_for_request_.is_empty()) 211 << "HttpBridge::SetURL called more than once?!"; 212#endif 213 GURL temp(url); 214 GURL::Replacements replacements; 215 std::string port_str = base::IntToString(port); 216 replacements.SetPort(port_str.c_str(), url::Component(0, port_str.length())); 217 url_for_request_ = temp.ReplaceComponents(replacements); 218} 219 220void HttpBridge::SetPostPayload(const char* content_type, 221 int content_length, 222 const char* content) { 223#if DCHECK_IS_ON 224 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_); 225 { 226 base::AutoLock lock(fetch_state_lock_); 227 DCHECK(!fetch_state_.request_completed); 228 } 229 DCHECK(content_type_.empty()) << "Bridge payload already set."; 230 DCHECK_GE(content_length, 0) << "Content length < 0"; 231#endif 232 content_type_ = content_type; 233 if (!content || (content_length == 0)) { 234 DCHECK_EQ(content_length, 0); 235 request_content_ = " "; // TODO(timsteele): URLFetcher requires non-empty 236 // content for POSTs whereas CURL does not, for now 237 // we hack this to support the sync backend. 238 } else { 239 request_content_.assign(content, content_length); 240 } 241} 242 243bool HttpBridge::MakeSynchronousPost(int* error_code, int* response_code) { 244#if DCHECK_IS_ON 245 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_); 246 { 247 base::AutoLock lock(fetch_state_lock_); 248 DCHECK(!fetch_state_.request_completed); 249 } 250 DCHECK(url_for_request_.is_valid()) << "Invalid URL for request"; 251 DCHECK(!content_type_.empty()) << "Payload not set"; 252#endif 253 254 if (!network_task_runner_->PostTask( 255 FROM_HERE, 256 base::Bind(&HttpBridge::CallMakeAsynchronousPost, this))) { 257 // This usually happens when we're in a unit test. 258 LOG(WARNING) << "Could not post CallMakeAsynchronousPost task"; 259 return false; 260 } 261 262 // Block until network request completes or is aborted. See 263 // OnURLFetchComplete and Abort. 264 http_post_completed_.Wait(); 265 266 base::AutoLock lock(fetch_state_lock_); 267 DCHECK(fetch_state_.request_completed || fetch_state_.aborted); 268 *error_code = fetch_state_.error_code; 269 *response_code = fetch_state_.http_response_code; 270 return fetch_state_.request_succeeded; 271} 272 273void HttpBridge::MakeAsynchronousPost() { 274 DCHECK(network_task_runner_->BelongsToCurrentThread()); 275 base::AutoLock lock(fetch_state_lock_); 276 DCHECK(!fetch_state_.request_completed); 277 if (fetch_state_.aborted) 278 return; 279 280 DCHECK(context_getter_for_request_.get()); 281 fetch_state_.url_poster = net::URLFetcher::Create( 282 url_for_request_, net::URLFetcher::POST, this); 283 fetch_state_.url_poster->SetRequestContext(context_getter_for_request_.get()); 284 fetch_state_.url_poster->SetUploadData(content_type_, request_content_); 285 fetch_state_.url_poster->SetExtraRequestHeaders(extra_headers_); 286 fetch_state_.url_poster->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES); 287 fetch_state_.start_time = base::Time::Now(); 288 fetch_state_.url_poster->Start(); 289} 290 291int HttpBridge::GetResponseContentLength() const { 292 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_); 293 base::AutoLock lock(fetch_state_lock_); 294 DCHECK(fetch_state_.request_completed); 295 return fetch_state_.response_content.size(); 296} 297 298const char* HttpBridge::GetResponseContent() const { 299 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_); 300 base::AutoLock lock(fetch_state_lock_); 301 DCHECK(fetch_state_.request_completed); 302 return fetch_state_.response_content.data(); 303} 304 305const std::string HttpBridge::GetResponseHeaderValue( 306 const std::string& name) const { 307 308 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_); 309 base::AutoLock lock(fetch_state_lock_); 310 DCHECK(fetch_state_.request_completed); 311 312 std::string value; 313 fetch_state_.response_headers->EnumerateHeader(NULL, name, &value); 314 return value; 315} 316 317void HttpBridge::Abort() { 318 base::AutoLock lock(fetch_state_lock_); 319 320 // Release |request_context_getter_| as soon as possible so that it is 321 // destroyed in the right order on its network task runner. 322 context_getter_for_request_ = NULL; 323 324 DCHECK(!fetch_state_.aborted); 325 if (fetch_state_.aborted || fetch_state_.request_completed) 326 return; 327 328 fetch_state_.aborted = true; 329 if (!network_task_runner_->PostTask( 330 FROM_HERE, 331 base::Bind(&HttpBridge::DestroyURLFetcherOnIOThread, this, 332 fetch_state_.url_poster))) { 333 // Madness ensues. 334 NOTREACHED() << "Could not post task to delete URLFetcher"; 335 } 336 337 fetch_state_.url_poster = NULL; 338 fetch_state_.error_code = net::ERR_ABORTED; 339 http_post_completed_.Signal(); 340} 341 342void HttpBridge::DestroyURLFetcherOnIOThread(net::URLFetcher* fetcher) { 343 DCHECK(network_task_runner_->BelongsToCurrentThread()); 344 delete fetcher; 345} 346 347void HttpBridge::OnURLFetchComplete(const net::URLFetcher* source) { 348 DCHECK(network_task_runner_->BelongsToCurrentThread()); 349 base::AutoLock lock(fetch_state_lock_); 350 if (fetch_state_.aborted) 351 return; 352 353 fetch_state_.end_time = base::Time::Now(); 354 fetch_state_.request_completed = true; 355 fetch_state_.request_succeeded = 356 (net::URLRequestStatus::SUCCESS == source->GetStatus().status()); 357 fetch_state_.http_response_code = source->GetResponseCode(); 358 fetch_state_.error_code = source->GetStatus().error(); 359 360 // Use a real (non-debug) log to facilitate troubleshooting in the wild. 361 VLOG(2) << "HttpBridge::OnURLFetchComplete for: " 362 << fetch_state_.url_poster->GetURL().spec(); 363 VLOG(1) << "HttpBridge received response code: " 364 << fetch_state_.http_response_code; 365 366 source->GetResponseAsString(&fetch_state_.response_content); 367 fetch_state_.response_headers = source->GetResponseHeaders(); 368 UpdateNetworkTime(); 369 370 // End of the line for url_poster_. It lives only on the IO loop. 371 // We defer deletion because we're inside a callback from a component of the 372 // URLFetcher, so it seems most natural / "polite" to let the stack unwind. 373 base::MessageLoop::current()->DeleteSoon(FROM_HERE, fetch_state_.url_poster); 374 fetch_state_.url_poster = NULL; 375 376 // Wake the blocked syncer thread in MakeSynchronousPost. 377 // WARNING: DONT DO ANYTHING AFTER THIS CALL! |this| may be deleted! 378 http_post_completed_.Signal(); 379} 380 381net::URLRequestContextGetter* HttpBridge::GetRequestContextGetterForTest() 382 const { 383 base::AutoLock lock(fetch_state_lock_); 384 return context_getter_for_request_.get(); 385} 386 387void HttpBridge::UpdateNetworkTime() { 388 std::string sane_time_str; 389 if (!fetch_state_.request_succeeded || fetch_state_.start_time.is_null() || 390 fetch_state_.end_time < fetch_state_.start_time || 391 !fetch_state_.response_headers->EnumerateHeader(NULL, "Sane-Time-Millis", 392 &sane_time_str)) { 393 return; 394 } 395 396 int64 sane_time_ms = 0; 397 if (base::StringToInt64(sane_time_str, &sane_time_ms)) { 398 network_time_update_callback_.Run( 399 base::Time::FromJsTime(sane_time_ms), 400 base::TimeDelta::FromMilliseconds(1), 401 fetch_state_.end_time - fetch_state_.start_time); 402 } 403} 404 405} // namespace syncer 406