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