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