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/dns/host_resolver.h" 14 #include "net/http/http_cache.h" 15 #include "net/http/http_network_layer.h" 16 #include "net/http/http_response_headers.h" 17 #include "net/proxy/proxy_service.h" 18 #include "net/url_request/static_http_user_agent_settings.h" 19 #include "net/url_request/url_fetcher.h" 20 #include "net/url_request/url_request_context.h" 21 #include "net/url_request/url_request_status.h" 22 23 namespace syncer { 24 25 HttpBridge::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 37 HttpBridge::RequestContextGetter::~RequestContextGetter() {} 38 39 net::URLRequestContext* 40 HttpBridge::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 54 scoped_refptr<base::SingleThreadTaskRunner> 55 HttpBridge::RequestContextGetter::GetNetworkTaskRunner() const { 56 return network_task_runner_; 57 } 58 59 HttpBridgeFactory::HttpBridgeFactory( 60 net::URLRequestContextGetter* baseline_context_getter, 61 const std::string& user_agent, 62 const NetworkTimeUpdateCallback& network_time_update_callback) 63 : request_context_getter_( 64 new HttpBridge::RequestContextGetter( 65 baseline_context_getter, user_agent)), 66 network_time_update_callback_(network_time_update_callback) { 67 } 68 69 HttpBridgeFactory::~HttpBridgeFactory() { 70 } 71 72 HttpPostProviderInterface* HttpBridgeFactory::Create() { 73 HttpBridge* http = new HttpBridge(request_context_getter_.get(), 74 network_time_update_callback_); 75 http->AddRef(); 76 return http; 77 } 78 79 void HttpBridgeFactory::Destroy(HttpPostProviderInterface* http) { 80 static_cast<HttpBridge*>(http)->Release(); 81 } 82 83 HttpBridge::RequestContext::RequestContext( 84 net::URLRequestContext* baseline_context, 85 const scoped_refptr<base::SingleThreadTaskRunner>& 86 network_task_runner, 87 const std::string& user_agent) 88 : baseline_context_(baseline_context), 89 network_task_runner_(network_task_runner) { 90 DCHECK(!user_agent.empty()); 91 92 // Create empty, in-memory cookie store. 93 set_cookie_store(new net::CookieMonster(NULL, NULL)); 94 95 // We don't use a cache for bridged loads, but we do want to share proxy info. 96 set_host_resolver(baseline_context->host_resolver()); 97 set_proxy_service(baseline_context->proxy_service()); 98 set_ssl_config_service(baseline_context->ssl_config_service()); 99 100 // We want to share the HTTP session data with the network layer factory, 101 // which includes auth_cache for proxies. 102 // Session is not refcounted so we need to be careful to not lose the parent 103 // context. 104 net::HttpNetworkSession* session = 105 baseline_context->http_transaction_factory()->GetSession(); 106 DCHECK(session); 107 set_http_transaction_factory(new net::HttpNetworkLayer(session)); 108 109 // TODO(timsteele): We don't currently listen for pref changes of these 110 // fields or CookiePolicy; I'm not sure we want to strictly follow the 111 // default settings, since for example if the user chooses to block all 112 // cookies, sync will start failing. Also it seems like accept_lang/charset 113 // should be tied to whatever the sync servers expect (if anything). These 114 // fields should probably just be settable by sync backend; though we should 115 // figure out if we need to give the user explicit control over policies etc. 116 http_user_agent_settings_.reset(new net::StaticHttpUserAgentSettings( 117 baseline_context->GetAcceptLanguage(), 118 user_agent)); 119 set_http_user_agent_settings(http_user_agent_settings_.get()); 120 121 set_net_log(baseline_context->net_log()); 122 } 123 124 HttpBridge::RequestContext::~RequestContext() { 125 DCHECK(network_task_runner_->BelongsToCurrentThread()); 126 delete http_transaction_factory(); 127 } 128 129 HttpBridge::URLFetchState::URLFetchState() : url_poster(NULL), 130 aborted(false), 131 request_completed(false), 132 request_succeeded(false), 133 http_response_code(-1), 134 error_code(-1) {} 135 HttpBridge::URLFetchState::~URLFetchState() {} 136 137 HttpBridge::HttpBridge( 138 HttpBridge::RequestContextGetter* context_getter, 139 const NetworkTimeUpdateCallback& network_time_update_callback) 140 : context_getter_for_request_(context_getter), 141 network_task_runner_( 142 context_getter_for_request_->GetNetworkTaskRunner()), 143 created_on_loop_(base::MessageLoop::current()), 144 http_post_completed_(false, false), 145 network_time_update_callback_(network_time_update_callback) { 146 } 147 148 HttpBridge::~HttpBridge() { 149 } 150 151 void HttpBridge::SetExtraRequestHeaders(const char * headers) { 152 DCHECK(extra_headers_.empty()) 153 << "HttpBridge::SetExtraRequestHeaders called twice."; 154 extra_headers_.assign(headers); 155 } 156 157 void HttpBridge::SetURL(const char* url, int port) { 158 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_); 159 if (DCHECK_IS_ON()) { 160 base::AutoLock lock(fetch_state_lock_); 161 DCHECK(!fetch_state_.request_completed); 162 } 163 DCHECK(url_for_request_.is_empty()) 164 << "HttpBridge::SetURL called more than once?!"; 165 GURL temp(url); 166 GURL::Replacements replacements; 167 std::string port_str = base::IntToString(port); 168 replacements.SetPort(port_str.c_str(), 169 url_parse::Component(0, port_str.length())); 170 url_for_request_ = temp.ReplaceComponents(replacements); 171 } 172 173 void HttpBridge::SetPostPayload(const char* content_type, 174 int content_length, 175 const char* content) { 176 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_); 177 if (DCHECK_IS_ON()) { 178 base::AutoLock lock(fetch_state_lock_); 179 DCHECK(!fetch_state_.request_completed); 180 } 181 DCHECK(content_type_.empty()) << "Bridge payload already set."; 182 DCHECK_GE(content_length, 0) << "Content length < 0"; 183 content_type_ = content_type; 184 if (!content || (content_length == 0)) { 185 DCHECK_EQ(content_length, 0); 186 request_content_ = " "; // TODO(timsteele): URLFetcher requires non-empty 187 // content for POSTs whereas CURL does not, for now 188 // we hack this to support the sync backend. 189 } else { 190 request_content_.assign(content, content_length); 191 } 192 } 193 194 bool HttpBridge::MakeSynchronousPost(int* error_code, int* response_code) { 195 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_); 196 if (DCHECK_IS_ON()) { 197 base::AutoLock lock(fetch_state_lock_); 198 DCHECK(!fetch_state_.request_completed); 199 } 200 DCHECK(url_for_request_.is_valid()) << "Invalid URL for request"; 201 DCHECK(!content_type_.empty()) << "Payload not set"; 202 203 if (!network_task_runner_->PostTask( 204 FROM_HERE, 205 base::Bind(&HttpBridge::CallMakeAsynchronousPost, this))) { 206 // This usually happens when we're in a unit test. 207 LOG(WARNING) << "Could not post CallMakeAsynchronousPost task"; 208 return false; 209 } 210 211 // Block until network request completes or is aborted. See 212 // OnURLFetchComplete and Abort. 213 http_post_completed_.Wait(); 214 215 base::AutoLock lock(fetch_state_lock_); 216 DCHECK(fetch_state_.request_completed || fetch_state_.aborted); 217 *error_code = fetch_state_.error_code; 218 *response_code = fetch_state_.http_response_code; 219 return fetch_state_.request_succeeded; 220 } 221 222 void HttpBridge::MakeAsynchronousPost() { 223 DCHECK(network_task_runner_->BelongsToCurrentThread()); 224 base::AutoLock lock(fetch_state_lock_); 225 DCHECK(!fetch_state_.request_completed); 226 if (fetch_state_.aborted) 227 return; 228 229 fetch_state_.url_poster = net::URLFetcher::Create( 230 url_for_request_, net::URLFetcher::POST, this); 231 fetch_state_.url_poster->SetRequestContext(context_getter_for_request_.get()); 232 fetch_state_.url_poster->SetUploadData(content_type_, request_content_); 233 fetch_state_.url_poster->SetExtraRequestHeaders(extra_headers_); 234 fetch_state_.url_poster->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES); 235 fetch_state_.start_time = base::Time::Now(); 236 fetch_state_.url_poster->Start(); 237 } 238 239 int HttpBridge::GetResponseContentLength() const { 240 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_); 241 base::AutoLock lock(fetch_state_lock_); 242 DCHECK(fetch_state_.request_completed); 243 return fetch_state_.response_content.size(); 244 } 245 246 const char* HttpBridge::GetResponseContent() const { 247 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_); 248 base::AutoLock lock(fetch_state_lock_); 249 DCHECK(fetch_state_.request_completed); 250 return fetch_state_.response_content.data(); 251 } 252 253 const std::string HttpBridge::GetResponseHeaderValue( 254 const std::string& name) const { 255 256 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_); 257 base::AutoLock lock(fetch_state_lock_); 258 DCHECK(fetch_state_.request_completed); 259 260 std::string value; 261 fetch_state_.response_headers->EnumerateHeader(NULL, name, &value); 262 return value; 263 } 264 265 void HttpBridge::Abort() { 266 base::AutoLock lock(fetch_state_lock_); 267 DCHECK(!fetch_state_.aborted); 268 if (fetch_state_.aborted || fetch_state_.request_completed) 269 return; 270 271 fetch_state_.aborted = true; 272 if (!network_task_runner_->PostTask( 273 FROM_HERE, 274 base::Bind(&HttpBridge::DestroyURLFetcherOnIOThread, this, 275 fetch_state_.url_poster))) { 276 // Madness ensues. 277 NOTREACHED() << "Could not post task to delete URLFetcher"; 278 } 279 280 fetch_state_.url_poster = NULL; 281 fetch_state_.error_code = net::ERR_ABORTED; 282 http_post_completed_.Signal(); 283 } 284 285 void HttpBridge::DestroyURLFetcherOnIOThread(net::URLFetcher* fetcher) { 286 DCHECK(network_task_runner_->BelongsToCurrentThread()); 287 delete fetcher; 288 } 289 290 void HttpBridge::OnURLFetchComplete(const net::URLFetcher* source) { 291 DCHECK(network_task_runner_->BelongsToCurrentThread()); 292 base::AutoLock lock(fetch_state_lock_); 293 if (fetch_state_.aborted) 294 return; 295 296 fetch_state_.end_time = base::Time::Now(); 297 fetch_state_.request_completed = true; 298 fetch_state_.request_succeeded = 299 (net::URLRequestStatus::SUCCESS == source->GetStatus().status()); 300 fetch_state_.http_response_code = source->GetResponseCode(); 301 fetch_state_.error_code = source->GetStatus().error(); 302 303 // Use a real (non-debug) log to facilitate troubleshooting in the wild. 304 VLOG(2) << "HttpBridge::OnURLFetchComplete for: " 305 << fetch_state_.url_poster->GetURL().spec(); 306 VLOG(1) << "HttpBridge received response code: " 307 << fetch_state_.http_response_code; 308 309 source->GetResponseAsString(&fetch_state_.response_content); 310 fetch_state_.response_headers = source->GetResponseHeaders(); 311 UpdateNetworkTime(); 312 313 // End of the line for url_poster_. It lives only on the IO loop. 314 // We defer deletion because we're inside a callback from a component of the 315 // URLFetcher, so it seems most natural / "polite" to let the stack unwind. 316 base::MessageLoop::current()->DeleteSoon(FROM_HERE, fetch_state_.url_poster); 317 fetch_state_.url_poster = NULL; 318 319 // Wake the blocked syncer thread in MakeSynchronousPost. 320 // WARNING: DONT DO ANYTHING AFTER THIS CALL! |this| may be deleted! 321 http_post_completed_.Signal(); 322 } 323 324 net::URLRequestContextGetter* HttpBridge::GetRequestContextGetterForTest() 325 const { 326 return context_getter_for_request_.get(); 327 } 328 329 void HttpBridge::UpdateNetworkTime() { 330 std::string sane_time_str; 331 if (!fetch_state_.request_succeeded || fetch_state_.start_time.is_null() || 332 fetch_state_.end_time < fetch_state_.start_time || 333 !fetch_state_.response_headers->EnumerateHeader(NULL, "Sane-Time-Millis", 334 &sane_time_str)) { 335 return; 336 } 337 338 int64 sane_time_ms = 0; 339 if (base::StringToInt64(sane_time_str, &sane_time_ms)) { 340 network_time_update_callback_.Run( 341 base::Time::FromJsTime(sane_time_ms), 342 base::TimeDelta::FromMilliseconds(1), 343 fetch_state_.end_time - fetch_state_.start_time); 344 } 345 } 346 347 } // namespace syncer 348