1 // Copyright (c) 2011 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 "chrome/browser/sync/glue/http_bridge.h" 6 7 #include "base/message_loop.h" 8 #include "base/message_loop_proxy.h" 9 #include "base/string_number_conversions.h" 10 #include "content/browser/browser_thread.h" 11 #include "net/base/cookie_monster.h" 12 #include "net/base/host_resolver.h" 13 #include "net/base/load_flags.h" 14 #include "net/base/net_errors.h" 15 #include "net/http/http_cache.h" 16 #include "net/http/http_network_layer.h" 17 #include "net/http/http_response_headers.h" 18 #include "net/proxy/proxy_service.h" 19 #include "net/url_request/url_request_context.h" 20 #include "net/url_request/url_request_status.h" 21 #include "webkit/glue/webkit_glue.h" 22 23 namespace browser_sync { 24 25 HttpBridge::RequestContextGetter::RequestContextGetter( 26 net::URLRequestContextGetter* baseline_context_getter) 27 : baseline_context_getter_(baseline_context_getter) { 28 } 29 30 net::URLRequestContext* 31 HttpBridge::RequestContextGetter::GetURLRequestContext() { 32 // Lazily create the context. 33 if (!context_) { 34 net::URLRequestContext* baseline_context = 35 baseline_context_getter_->GetURLRequestContext(); 36 context_ = new RequestContext(baseline_context); 37 baseline_context_getter_ = NULL; 38 } 39 40 // Apply the user agent which was set earlier. 41 if (is_user_agent_set()) 42 context_->set_user_agent(user_agent_); 43 44 return context_; 45 } 46 47 scoped_refptr<base::MessageLoopProxy> 48 HttpBridge::RequestContextGetter::GetIOMessageLoopProxy() const { 49 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO); 50 } 51 52 HttpBridgeFactory::HttpBridgeFactory( 53 net::URLRequestContextGetter* baseline_context_getter) { 54 DCHECK(baseline_context_getter != NULL); 55 request_context_getter_ = 56 new HttpBridge::RequestContextGetter(baseline_context_getter); 57 } 58 59 HttpBridgeFactory::~HttpBridgeFactory() { 60 } 61 62 sync_api::HttpPostProviderInterface* HttpBridgeFactory::Create() { 63 HttpBridge* http = new HttpBridge(request_context_getter_); 64 http->AddRef(); 65 return http; 66 } 67 68 void HttpBridgeFactory::Destroy(sync_api::HttpPostProviderInterface* http) { 69 static_cast<HttpBridge*>(http)->Release(); 70 } 71 72 HttpBridge::RequestContext::RequestContext( 73 net::URLRequestContext* baseline_context) 74 : baseline_context_(baseline_context) { 75 76 // Create empty, in-memory cookie store. 77 set_cookie_store(new net::CookieMonster(NULL, NULL)); 78 79 // We don't use a cache for bridged loads, but we do want to share proxy info. 80 set_host_resolver(baseline_context->host_resolver()); 81 set_proxy_service(baseline_context->proxy_service()); 82 set_ssl_config_service(baseline_context->ssl_config_service()); 83 84 // We want to share the HTTP session data with the network layer factory, 85 // which includes auth_cache for proxies. 86 // Session is not refcounted so we need to be careful to not lose the parent 87 // context. 88 net::HttpNetworkSession* session = 89 baseline_context->http_transaction_factory()->GetSession(); 90 DCHECK(session); 91 set_http_transaction_factory(new net::HttpNetworkLayer(session)); 92 93 // TODO(timsteele): We don't currently listen for pref changes of these 94 // fields or CookiePolicy; I'm not sure we want to strictly follow the 95 // default settings, since for example if the user chooses to block all 96 // cookies, sync will start failing. Also it seems like accept_lang/charset 97 // should be tied to whatever the sync servers expect (if anything). These 98 // fields should probably just be settable by sync backend; though we should 99 // figure out if we need to give the user explicit control over policies etc. 100 set_accept_language(baseline_context->accept_language()); 101 set_accept_charset(baseline_context->accept_charset()); 102 103 // We default to the browser's user agent. This can (and should) be overridden 104 // with set_user_agent. 105 set_user_agent(webkit_glue::GetUserAgent(GURL())); 106 107 set_net_log(baseline_context->net_log()); 108 } 109 110 HttpBridge::RequestContext::~RequestContext() { 111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 112 delete http_transaction_factory(); 113 } 114 115 HttpBridge::URLFetchState::URLFetchState() : url_poster(NULL), 116 aborted(false), 117 request_completed(false), 118 request_succeeded(false), 119 http_response_code(-1), 120 os_error_code(-1) {} 121 HttpBridge::URLFetchState::~URLFetchState() {} 122 123 HttpBridge::HttpBridge(HttpBridge::RequestContextGetter* context_getter) 124 : context_getter_for_request_(context_getter), 125 created_on_loop_(MessageLoop::current()), 126 http_post_completed_(false, false) { 127 } 128 129 HttpBridge::~HttpBridge() { 130 } 131 132 void HttpBridge::SetUserAgent(const char* user_agent) { 133 DCHECK_EQ(MessageLoop::current(), created_on_loop_); 134 if (DCHECK_IS_ON()) { 135 base::AutoLock lock(fetch_state_lock_); 136 DCHECK(!fetch_state_.request_completed); 137 } 138 context_getter_for_request_->set_user_agent(user_agent); 139 } 140 141 void HttpBridge::SetExtraRequestHeaders(const char * headers) { 142 DCHECK(extra_headers_.empty()) 143 << "HttpBridge::SetExtraRequestHeaders called twice."; 144 extra_headers_.assign(headers); 145 } 146 147 void HttpBridge::SetURL(const char* url, int port) { 148 DCHECK_EQ(MessageLoop::current(), created_on_loop_); 149 if (DCHECK_IS_ON()) { 150 base::AutoLock lock(fetch_state_lock_); 151 DCHECK(!fetch_state_.request_completed); 152 } 153 DCHECK(url_for_request_.is_empty()) 154 << "HttpBridge::SetURL called more than once?!"; 155 GURL temp(url); 156 GURL::Replacements replacements; 157 std::string port_str = base::IntToString(port); 158 replacements.SetPort(port_str.c_str(), 159 url_parse::Component(0, port_str.length())); 160 url_for_request_ = temp.ReplaceComponents(replacements); 161 } 162 163 void HttpBridge::SetPostPayload(const char* content_type, 164 int content_length, 165 const char* content) { 166 DCHECK_EQ(MessageLoop::current(), created_on_loop_); 167 if (DCHECK_IS_ON()) { 168 base::AutoLock lock(fetch_state_lock_); 169 DCHECK(!fetch_state_.request_completed); 170 } 171 DCHECK(content_type_.empty()) << "Bridge payload already set."; 172 DCHECK_GE(content_length, 0) << "Content length < 0"; 173 content_type_ = content_type; 174 if (!content || (content_length == 0)) { 175 DCHECK_EQ(content_length, 0); 176 request_content_ = " "; // TODO(timsteele): URLFetcher requires non-empty 177 // content for POSTs whereas CURL does not, for now 178 // we hack this to support the sync backend. 179 } else { 180 request_content_.assign(content, content_length); 181 } 182 } 183 184 bool HttpBridge::MakeSynchronousPost(int* os_error_code, int* response_code) { 185 DCHECK_EQ(MessageLoop::current(), created_on_loop_); 186 if (DCHECK_IS_ON()) { 187 base::AutoLock lock(fetch_state_lock_); 188 DCHECK(!fetch_state_.request_completed); 189 } 190 DCHECK(url_for_request_.is_valid()) << "Invalid URL for request"; 191 DCHECK(!content_type_.empty()) << "Payload not set"; 192 193 if (!BrowserThread::PostTask( 194 BrowserThread::IO, FROM_HERE, 195 NewRunnableMethod(this, &HttpBridge::CallMakeAsynchronousPost))) { 196 // This usually happens when we're in a unit test. 197 LOG(WARNING) << "Could not post CallMakeAsynchronousPost task"; 198 return false; 199 } 200 201 if (!http_post_completed_.Wait()) // Block until network request completes 202 NOTREACHED(); // or is aborted. See OnURLFetchComplete 203 // and Abort. 204 205 base::AutoLock lock(fetch_state_lock_); 206 DCHECK(fetch_state_.request_completed || fetch_state_.aborted); 207 *os_error_code = fetch_state_.os_error_code; 208 *response_code = fetch_state_.http_response_code; 209 return fetch_state_.request_succeeded; 210 } 211 212 void HttpBridge::MakeAsynchronousPost() { 213 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 214 base::AutoLock lock(fetch_state_lock_); 215 DCHECK(!fetch_state_.request_completed); 216 if (fetch_state_.aborted) 217 return; 218 219 fetch_state_.url_poster = new URLFetcher(url_for_request_, 220 URLFetcher::POST, this); 221 fetch_state_.url_poster->set_request_context(context_getter_for_request_); 222 fetch_state_.url_poster->set_upload_data(content_type_, request_content_); 223 fetch_state_.url_poster->set_extra_request_headers(extra_headers_); 224 fetch_state_.url_poster->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES); 225 fetch_state_.url_poster->Start(); 226 } 227 228 int HttpBridge::GetResponseContentLength() const { 229 DCHECK_EQ(MessageLoop::current(), created_on_loop_); 230 base::AutoLock lock(fetch_state_lock_); 231 DCHECK(fetch_state_.request_completed); 232 return fetch_state_.response_content.size(); 233 } 234 235 const char* HttpBridge::GetResponseContent() const { 236 DCHECK_EQ(MessageLoop::current(), created_on_loop_); 237 base::AutoLock lock(fetch_state_lock_); 238 DCHECK(fetch_state_.request_completed); 239 return fetch_state_.response_content.data(); 240 } 241 242 const std::string HttpBridge::GetResponseHeaderValue( 243 const std::string& name) const { 244 245 DCHECK_EQ(MessageLoop::current(), created_on_loop_); 246 base::AutoLock lock(fetch_state_lock_); 247 DCHECK(fetch_state_.request_completed); 248 249 std::string value; 250 fetch_state_.response_headers->EnumerateHeader(NULL, name, &value); 251 return value; 252 } 253 254 void HttpBridge::Abort() { 255 base::AutoLock lock(fetch_state_lock_); 256 DCHECK(!fetch_state_.aborted); 257 if (fetch_state_.aborted || fetch_state_.request_completed) 258 return; 259 260 fetch_state_.aborted = true; 261 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, 262 fetch_state_.url_poster); 263 fetch_state_.url_poster = NULL; 264 fetch_state_.os_error_code = net::ERR_ABORTED; 265 http_post_completed_.Signal(); 266 } 267 268 void HttpBridge::OnURLFetchComplete(const URLFetcher *source, 269 const GURL &url, 270 const net::URLRequestStatus &status, 271 int response_code, 272 const ResponseCookies &cookies, 273 const std::string &data) { 274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 275 base::AutoLock lock(fetch_state_lock_); 276 if (fetch_state_.aborted) 277 return; 278 279 fetch_state_.request_completed = true; 280 fetch_state_.request_succeeded = 281 (net::URLRequestStatus::SUCCESS == status.status()); 282 fetch_state_.http_response_code = response_code; 283 fetch_state_.os_error_code = status.os_error(); 284 285 fetch_state_.response_content = data; 286 fetch_state_.response_headers = source->response_headers(); 287 288 // End of the line for url_poster_. It lives only on the IO loop. 289 // We defer deletion because we're inside a callback from a component of the 290 // URLFetcher, so it seems most natural / "polite" to let the stack unwind. 291 MessageLoop::current()->DeleteSoon(FROM_HERE, fetch_state_.url_poster); 292 fetch_state_.url_poster = NULL; 293 294 // Wake the blocked syncer thread in MakeSynchronousPost. 295 // WARNING: DONT DO ANYTHING AFTER THIS CALL! |this| may be deleted! 296 http_post_completed_.Signal(); 297 } 298 299 } // namespace browser_sync 300