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 "base/synchronization/waitable_event.h"
6#include "base/threading/thread.h"
7#include "net/test/spawned_test_server/spawned_test_server.h"
8#include "net/url_request/test_url_fetcher_factory.h"
9#include "net/url_request/url_fetcher_delegate.h"
10#include "net/url_request/url_request_test_util.h"
11#include "sync/internal_api/public/base/cancelation_signal.h"
12#include "sync/internal_api/public/http_bridge.h"
13#include "testing/gtest/include/gtest/gtest.h"
14
15namespace syncer {
16
17namespace {
18// TODO(timsteele): Should use PathService here. See Chromium Issue 3113.
19const base::FilePath::CharType kDocRoot[] =
20    FILE_PATH_LITERAL("chrome/test/data");
21}
22
23class SyncHttpBridgeTest : public testing::Test {
24 public:
25  SyncHttpBridgeTest()
26      : test_server_(net::SpawnedTestServer::TYPE_HTTP,
27                     net::SpawnedTestServer::kLocalhost,
28                     base::FilePath(kDocRoot)),
29        fake_default_request_context_getter_(NULL),
30        bridge_for_race_test_(NULL),
31        io_thread_("IO thread") {
32  }
33
34  virtual void SetUp() {
35    base::Thread::Options options;
36    options.message_loop_type = base::MessageLoop::TYPE_IO;
37    io_thread_.StartWithOptions(options);
38  }
39
40  virtual void TearDown() {
41    if (fake_default_request_context_getter_) {
42      GetIOThreadLoop()->ReleaseSoon(FROM_HERE,
43          fake_default_request_context_getter_);
44      fake_default_request_context_getter_ = NULL;
45    }
46    io_thread_.Stop();
47  }
48
49  HttpBridge* BuildBridge() {
50    if (!fake_default_request_context_getter_) {
51      fake_default_request_context_getter_ =
52          new net::TestURLRequestContextGetter(io_thread_.message_loop_proxy());
53      fake_default_request_context_getter_->AddRef();
54    }
55    HttpBridge* bridge = new HttpBridge(
56        new HttpBridge::RequestContextGetter(
57            fake_default_request_context_getter_,
58            "user agent"),
59        NetworkTimeUpdateCallback());
60    return bridge;
61  }
62
63  static void Abort(HttpBridge* bridge) {
64    bridge->Abort();
65  }
66
67  // Used by AbortAndReleaseBeforeFetchCompletes to test an interesting race
68  // condition.
69  void RunSyncThreadBridgeUseTest(base::WaitableEvent* signal_when_created,
70                                  base::WaitableEvent* signal_when_released);
71
72  static void TestSameHttpNetworkSession(base::MessageLoop* main_message_loop,
73                                         SyncHttpBridgeTest* test) {
74    scoped_refptr<HttpBridge> http_bridge(test->BuildBridge());
75    EXPECT_TRUE(test->GetTestRequestContextGetter());
76    net::HttpNetworkSession* test_session =
77        test->GetTestRequestContextGetter()->GetURLRequestContext()->
78        http_transaction_factory()->GetSession();
79    EXPECT_EQ(test_session,
80              http_bridge->GetRequestContextGetterForTest()->
81                  GetURLRequestContext()->
82                  http_transaction_factory()->GetSession());
83    main_message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
84  }
85
86  base::MessageLoop* GetIOThreadLoop() { return io_thread_.message_loop(); }
87
88  // Note this is lazy created, so don't call this before your bridge.
89  net::TestURLRequestContextGetter* GetTestRequestContextGetter() {
90    return fake_default_request_context_getter_;
91  }
92
93  net::SpawnedTestServer test_server_;
94
95  base::Thread* io_thread() { return &io_thread_; }
96
97  HttpBridge* bridge_for_race_test() { return bridge_for_race_test_; }
98
99 private:
100  // A make-believe "default" request context, as would be returned by
101  // Profile::GetDefaultRequestContext().  Created lazily by BuildBridge.
102  net::TestURLRequestContextGetter* fake_default_request_context_getter_;
103
104  HttpBridge* bridge_for_race_test_;
105
106  // Separate thread for IO used by the HttpBridge.
107  base::Thread io_thread_;
108  base::MessageLoop loop_;
109};
110
111// An HttpBridge that doesn't actually make network requests and just calls
112// back with dummy response info.
113// TODO(tim): Instead of inheriting here we should inject a component
114// responsible for the MakeAsynchronousPost bit.
115class ShuntedHttpBridge : public HttpBridge {
116 public:
117  // If |never_finishes| is true, the simulated request never actually
118  // returns.
119  ShuntedHttpBridge(net::URLRequestContextGetter* baseline_context_getter,
120                    SyncHttpBridgeTest* test, bool never_finishes)
121      : HttpBridge(
122          new HttpBridge::RequestContextGetter(
123              baseline_context_getter, "user agent"),
124          NetworkTimeUpdateCallback()),
125        test_(test), never_finishes_(never_finishes) { }
126 protected:
127  virtual void MakeAsynchronousPost() OVERRIDE {
128    ASSERT_TRUE(base::MessageLoop::current() == test_->GetIOThreadLoop());
129    if (never_finishes_)
130      return;
131
132    // We don't actually want to make a request for this test, so just callback
133    // as if it completed.
134    test_->GetIOThreadLoop()->PostTask(FROM_HERE,
135        base::Bind(&ShuntedHttpBridge::CallOnURLFetchComplete, this));
136  }
137 private:
138  virtual ~ShuntedHttpBridge() {}
139
140  void CallOnURLFetchComplete() {
141    ASSERT_TRUE(base::MessageLoop::current() == test_->GetIOThreadLoop());
142    // We return no cookies and a dummy content response.
143    net::ResponseCookies cookies;
144
145    std::string response_content = "success!";
146    net::TestURLFetcher fetcher(0, GURL(), NULL);
147    fetcher.set_url(GURL("www.google.com"));
148    fetcher.set_response_code(200);
149    fetcher.set_cookies(cookies);
150    fetcher.SetResponseString(response_content);
151    OnURLFetchComplete(&fetcher);
152  }
153  SyncHttpBridgeTest* test_;
154  bool never_finishes_;
155};
156
157void SyncHttpBridgeTest::RunSyncThreadBridgeUseTest(
158    base::WaitableEvent* signal_when_created,
159    base::WaitableEvent* signal_when_released) {
160  scoped_refptr<net::URLRequestContextGetter> ctx_getter(
161      new net::TestURLRequestContextGetter(io_thread_.message_loop_proxy()));
162  {
163    scoped_refptr<ShuntedHttpBridge> bridge(
164        new ShuntedHttpBridge(ctx_getter.get(), this, true));
165    bridge->SetURL("http://www.google.com", 9999);
166    bridge->SetPostPayload("text/plain", 2, " ");
167    bridge_for_race_test_ = bridge.get();
168    signal_when_created->Signal();
169
170    int os_error = 0;
171    int response_code = 0;
172    bridge->MakeSynchronousPost(&os_error, &response_code);
173    bridge_for_race_test_ = NULL;
174  }
175  signal_when_released->Signal();
176}
177
178TEST_F(SyncHttpBridgeTest, TestUsesSameHttpNetworkSession) {
179  // Run this test on the IO thread because we can only call
180  // URLRequestContextGetter::GetURLRequestContext on the IO thread.
181  io_thread()->message_loop()
182      ->PostTask(FROM_HERE,
183                 base::Bind(&SyncHttpBridgeTest::TestSameHttpNetworkSession,
184                            base::MessageLoop::current(),
185                            this));
186  base::MessageLoop::current()->Run();
187}
188
189// Test the HttpBridge without actually making any network requests.
190TEST_F(SyncHttpBridgeTest, TestMakeSynchronousPostShunted) {
191  scoped_refptr<net::URLRequestContextGetter> ctx_getter(
192      new net::TestURLRequestContextGetter(io_thread()->message_loop_proxy()));
193  scoped_refptr<HttpBridge> http_bridge(
194      new ShuntedHttpBridge(ctx_getter.get(), this, false));
195  http_bridge->SetURL("http://www.google.com", 9999);
196  http_bridge->SetPostPayload("text/plain", 2, " ");
197
198  int os_error = 0;
199  int response_code = 0;
200  bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
201  EXPECT_TRUE(success);
202  EXPECT_EQ(200, response_code);
203  EXPECT_EQ(0, os_error);
204
205  EXPECT_EQ(8, http_bridge->GetResponseContentLength());
206  EXPECT_EQ(std::string("success!"),
207            std::string(http_bridge->GetResponseContent()));
208}
209
210// Full round-trip test of the HttpBridge, using default UA string and
211// no request cookies.
212TEST_F(SyncHttpBridgeTest, TestMakeSynchronousPostLiveWithPayload) {
213  ASSERT_TRUE(test_server_.Start());
214
215  scoped_refptr<HttpBridge> http_bridge(BuildBridge());
216
217  std::string payload = "this should be echoed back";
218  GURL echo = test_server_.GetURL("echo");
219  http_bridge->SetURL(echo.spec().c_str(), echo.IntPort());
220  http_bridge->SetPostPayload("application/x-www-form-urlencoded",
221                              payload.length() + 1, payload.c_str());
222  int os_error = 0;
223  int response_code = 0;
224  bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
225  EXPECT_TRUE(success);
226  EXPECT_EQ(200, response_code);
227  EXPECT_EQ(0, os_error);
228
229  EXPECT_EQ(payload.length() + 1,
230            static_cast<size_t>(http_bridge->GetResponseContentLength()));
231  EXPECT_EQ(payload, std::string(http_bridge->GetResponseContent()));
232}
233
234// Full round-trip test of the HttpBridge.
235TEST_F(SyncHttpBridgeTest, TestMakeSynchronousPostLiveComprehensive) {
236  ASSERT_TRUE(test_server_.Start());
237
238  scoped_refptr<HttpBridge> http_bridge(BuildBridge());
239
240  GURL echo_header = test_server_.GetURL("echoall");
241  http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
242
243  std::string test_payload = "###TEST PAYLOAD###";
244  http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
245                              test_payload.c_str());
246
247  int os_error = 0;
248  int response_code = 0;
249  bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
250  EXPECT_TRUE(success);
251  EXPECT_EQ(200, response_code);
252  EXPECT_EQ(0, os_error);
253
254  std::string response(http_bridge->GetResponseContent(),
255                       http_bridge->GetResponseContentLength());
256  EXPECT_EQ(std::string::npos, response.find("Cookie:"));
257  EXPECT_NE(std::string::npos, response.find("User-Agent: user agent"));
258  EXPECT_NE(std::string::npos, response.find(test_payload.c_str()));
259}
260
261TEST_F(SyncHttpBridgeTest, TestExtraRequestHeaders) {
262  ASSERT_TRUE(test_server_.Start());
263
264  scoped_refptr<HttpBridge> http_bridge(BuildBridge());
265
266  GURL echo_header = test_server_.GetURL("echoall");
267
268  http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
269  http_bridge->SetExtraRequestHeaders("test:fnord");
270
271  std::string test_payload = "###TEST PAYLOAD###";
272  http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
273                              test_payload.c_str());
274
275  int os_error = 0;
276  int response_code = 0;
277  bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
278  EXPECT_TRUE(success);
279  EXPECT_EQ(200, response_code);
280  EXPECT_EQ(0, os_error);
281
282  std::string response(http_bridge->GetResponseContent(),
283                       http_bridge->GetResponseContentLength());
284
285  EXPECT_NE(std::string::npos, response.find("fnord"));
286  EXPECT_NE(std::string::npos, response.find(test_payload.c_str()));
287}
288
289TEST_F(SyncHttpBridgeTest, TestResponseHeader) {
290  ASSERT_TRUE(test_server_.Start());
291
292  scoped_refptr<HttpBridge> http_bridge(BuildBridge());
293
294  GURL echo_header = test_server_.GetURL("echoall");
295  http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
296
297  std::string test_payload = "###TEST PAYLOAD###";
298  http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
299                              test_payload.c_str());
300
301  int os_error = 0;
302  int response_code = 0;
303  bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
304  EXPECT_TRUE(success);
305  EXPECT_EQ(200, response_code);
306  EXPECT_EQ(0, os_error);
307
308  EXPECT_EQ(http_bridge->GetResponseHeaderValue("Content-type"), "text/html");
309  EXPECT_TRUE(http_bridge->GetResponseHeaderValue("invalid-header").empty());
310}
311
312TEST_F(SyncHttpBridgeTest, Abort) {
313  scoped_refptr<net::URLRequestContextGetter> ctx_getter(
314      new net::TestURLRequestContextGetter(io_thread()->message_loop_proxy()));
315  scoped_refptr<ShuntedHttpBridge> http_bridge(
316      new ShuntedHttpBridge(ctx_getter.get(), this, true));
317  http_bridge->SetURL("http://www.google.com", 9999);
318  http_bridge->SetPostPayload("text/plain", 2, " ");
319
320  int os_error = 0;
321  int response_code = 0;
322
323  io_thread()->message_loop_proxy()->PostTask(
324      FROM_HERE,
325      base::Bind(&SyncHttpBridgeTest::Abort, http_bridge));
326  bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
327  EXPECT_FALSE(success);
328  EXPECT_EQ(net::ERR_ABORTED, os_error);
329}
330
331TEST_F(SyncHttpBridgeTest, AbortLate) {
332  scoped_refptr<net::URLRequestContextGetter> ctx_getter(
333      new net::TestURLRequestContextGetter(io_thread()->message_loop_proxy()));
334  scoped_refptr<ShuntedHttpBridge> http_bridge(
335      new ShuntedHttpBridge(ctx_getter.get(), this, false));
336  http_bridge->SetURL("http://www.google.com", 9999);
337  http_bridge->SetPostPayload("text/plain", 2, " ");
338
339  int os_error = 0;
340  int response_code = 0;
341
342  bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
343  ASSERT_TRUE(success);
344  http_bridge->Abort();
345  // Ensures no double-free of URLFetcher, etc.
346}
347
348// Tests an interesting case where code using the HttpBridge aborts the fetch
349// and releases ownership before a pending fetch completed callback is issued by
350// the underlying URLFetcher (and before that URLFetcher is destroyed, which
351// would cancel the callback).
352TEST_F(SyncHttpBridgeTest, AbortAndReleaseBeforeFetchComplete) {
353  base::Thread sync_thread("SyncThread");
354  sync_thread.Start();
355
356  // First, block the sync thread on the post.
357  base::WaitableEvent signal_when_created(false, false);
358  base::WaitableEvent signal_when_released(false, false);
359  sync_thread.message_loop()->PostTask(FROM_HERE,
360      base::Bind(&SyncHttpBridgeTest::RunSyncThreadBridgeUseTest,
361                 base::Unretained(this),
362                 &signal_when_created,
363                 &signal_when_released));
364
365  // Stop IO so we can control order of operations.
366  base::WaitableEvent io_waiter(false, false);
367  ASSERT_TRUE(io_thread()->message_loop_proxy()->PostTask(
368      FROM_HERE,
369      base::Bind(&base::WaitableEvent::Wait, base::Unretained(&io_waiter))));
370
371  signal_when_created.Wait();  // Wait till we have a bridge to abort.
372  ASSERT_TRUE(bridge_for_race_test());
373
374  // Schedule the fetch completion callback (but don't run it yet). Don't take
375  // a reference to the bridge to mimic URLFetcher's handling of the delegate.
376  net::URLFetcherDelegate* delegate =
377      static_cast<net::URLFetcherDelegate*>(bridge_for_race_test());
378  net::ResponseCookies cookies;
379  std::string response_content = "success!";
380  net::TestURLFetcher fetcher(0, GURL(), NULL);
381  fetcher.set_url(GURL("www.google.com"));
382  fetcher.set_response_code(200);
383  fetcher.set_cookies(cookies);
384  fetcher.SetResponseString(response_content);
385  ASSERT_TRUE(io_thread()->message_loop_proxy()->PostTask(
386      FROM_HERE,
387      base::Bind(&net::URLFetcherDelegate::OnURLFetchComplete,
388          base::Unretained(delegate), &fetcher)));
389
390  // Abort the fetch. This should be smart enough to handle the case where
391  // the bridge is destroyed before the callback scheduled above completes.
392  bridge_for_race_test()->Abort();
393
394  // Wait until the sync thread releases its ref on the bridge.
395  signal_when_released.Wait();
396  ASSERT_FALSE(bridge_for_race_test());
397
398  // Unleash the hounds. The fetch completion callback should fire first, and
399  // succeed even though we Release()d the bridge above because the call to
400  // Abort should have held a reference.
401  io_waiter.Signal();
402
403  // Done.
404  sync_thread.Stop();
405  io_thread()->Stop();
406}
407
408void HttpBridgeRunOnSyncThread(
409    net::URLRequestContextGetter* baseline_context_getter,
410    CancelationSignal* factory_cancelation_signal,
411    syncer::HttpPostProviderFactory** bridge_factory_out,
412    syncer::HttpPostProviderInterface** bridge_out,
413    base::WaitableEvent* signal_when_created,
414    base::WaitableEvent* wait_for_shutdown) {
415  scoped_ptr<syncer::HttpBridgeFactory> bridge_factory(
416      new syncer::HttpBridgeFactory(baseline_context_getter,
417                                    NetworkTimeUpdateCallback(),
418                                    factory_cancelation_signal));
419  bridge_factory->Init("test");
420  *bridge_factory_out = bridge_factory.get();
421
422  HttpPostProviderInterface* bridge = bridge_factory->Create();
423  *bridge_out = bridge;
424
425  signal_when_created->Signal();
426  wait_for_shutdown->Wait();
427
428  bridge_factory->Destroy(bridge);
429}
430
431void WaitOnIOThread(base::WaitableEvent* signal_wait_start,
432                    base::WaitableEvent* wait_done) {
433  signal_wait_start->Signal();
434  wait_done->Wait();
435}
436
437// Tests RequestContextGetter is properly released on IO thread even when
438// IO thread stops before sync thread.
439TEST_F(SyncHttpBridgeTest, RequestContextGetterReleaseOrder) {
440  base::Thread sync_thread("SyncThread");
441  sync_thread.Start();
442
443  syncer::HttpPostProviderFactory* factory = NULL;
444  syncer::HttpPostProviderInterface* bridge = NULL;
445
446  scoped_refptr<net::URLRequestContextGetter> baseline_context_getter(
447      new net::TestURLRequestContextGetter(io_thread()->message_loop_proxy()));
448
449  base::WaitableEvent signal_when_created(false, false);
450  base::WaitableEvent wait_for_shutdown(false, false);
451
452  CancelationSignal release_request_context_signal;
453
454  // Create bridge factory and factory on sync thread and wait for the creation
455  // to finish.
456  sync_thread.message_loop()->PostTask(FROM_HERE,
457      base::Bind(&HttpBridgeRunOnSyncThread,
458                 base::Unretained(baseline_context_getter.get()),
459                 &release_request_context_signal ,&factory, &bridge,
460                 &signal_when_created, &wait_for_shutdown));
461  signal_when_created.Wait();
462
463  // Simulate sync shutdown by aborting bridge and shutting down factory on
464  // frontend.
465  bridge->Abort();
466  release_request_context_signal.Signal();
467
468  // Wait for sync's RequestContextGetter to be cleared on IO thread and
469  // check for reference count.
470  base::WaitableEvent signal_wait_start(false, false);
471  base::WaitableEvent wait_done(false, false);
472  io_thread()->message_loop()->PostTask(
473      FROM_HERE,
474      base::Bind(&WaitOnIOThread, &signal_wait_start, &wait_done));
475  signal_wait_start.Wait();
476  // |baseline_context_getter| should have only one reference from local
477  // variable.
478  EXPECT_TRUE(baseline_context_getter->HasOneRef());
479  baseline_context_getter = NULL;
480
481  // Unblock and stop IO thread before sync thread.
482  wait_done.Signal();
483  io_thread()->Stop();
484
485  // Unblock and stop sync thread.
486  wait_for_shutdown.Signal();
487  sync_thread.Stop();
488}
489
490// Attempt to release the URLRequestContextGetter before the HttpBridgeFactory
491// is initialized.
492TEST_F(SyncHttpBridgeTest, EarlyAbortFactory) {
493  // In a real scenario, the following would happen on many threads.  For
494  // simplicity, this test uses only one thread.
495
496  scoped_refptr<net::URLRequestContextGetter> baseline_context_getter(
497      new net::TestURLRequestContextGetter(io_thread()->message_loop_proxy()));
498  CancelationSignal release_request_context_signal;
499
500  // UI Thread: Initialize the HttpBridgeFactory.  The next step would be to
501  // post a task to SBH::Core to have it initialized.
502  scoped_ptr<syncer::HttpBridgeFactory> factory(
503      new HttpBridgeFactory(baseline_context_getter.get(),
504                            NetworkTimeUpdateCallback(),
505                            &release_request_context_signal));
506
507  // UI Thread: A very early shutdown request arrives and executes on the UI
508  // thread before the posted sync thread task is run.
509  release_request_context_signal.Signal();
510
511  // Sync thread: Finally run the posted task, only to find that our
512  // HttpBridgeFactory has been neutered.  Should not crash.
513  factory->Init("TestUserAgent");
514
515  // At this point, attempting to use the factory would trigger a crash.  Both
516  // this test and the real world code should make sure this never happens.
517};
518
519}  // namespace syncer
520