diff options
author | akalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-22 12:11:37 +0000 |
---|---|---|
committer | akalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-22 12:11:37 +0000 |
commit | 5d5c13d1df9ffe304f595ea886092a75d4be381e (patch) | |
tree | 24df0b3f3ccd708fcb555a9320e46837f519cbe5 /sync | |
parent | a1733df46d06f88f1d212de14a0ba352a5383731 (diff) | |
download | chromium_src-5d5c13d1df9ffe304f595ea886092a75d4be381e.zip chromium_src-5d5c13d1df9ffe304f595ea886092a75d4be381e.tar.gz chromium_src-5d5c13d1df9ffe304f595ea886092a75d4be381e.tar.bz2 |
[Sync] Move HttpBridge to sync/
Remove all references to content in HttpBridge.
Clean up handling of HTTP user agent in HttpBridge.
BUG=133791
TEST=
Review URL: https://chromiumcodereview.appspot.com/10645004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@143575 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sync')
-rw-r--r-- | sync/engine/net/server_connection_manager.cc | 4 | ||||
-rw-r--r-- | sync/engine/net/server_connection_manager.h | 8 | ||||
-rw-r--r-- | sync/engine/syncer_proto_util_unittest.cc | 2 | ||||
-rw-r--r-- | sync/internal_api/DEPS | 4 | ||||
-rw-r--r-- | sync/internal_api/http_bridge.cc | 317 | ||||
-rw-r--r-- | sync/internal_api/http_bridge_unittest.cc | 404 | ||||
-rw-r--r-- | sync/internal_api/public/http_bridge.h | 232 | ||||
-rw-r--r-- | sync/internal_api/public/http_post_provider_interface.h | 4 | ||||
-rw-r--r-- | sync/internal_api/public/sync_manager.h | 4 | ||||
-rw-r--r-- | sync/internal_api/sync_manager.cc | 6 | ||||
-rw-r--r-- | sync/internal_api/syncapi_server_connection_manager.cc | 4 | ||||
-rw-r--r-- | sync/internal_api/syncapi_server_connection_manager.h | 1 | ||||
-rw-r--r-- | sync/internal_api/syncapi_server_connection_manager_unittest.cc | 5 | ||||
-rw-r--r-- | sync/internal_api/syncapi_unittest.cc | 3 | ||||
-rw-r--r-- | sync/sync.gyp | 5 | ||||
-rw-r--r-- | sync/test/engine/mock_connection_manager.cc | 2 |
16 files changed, 971 insertions, 34 deletions
diff --git a/sync/engine/net/server_connection_manager.cc b/sync/engine/net/server_connection_manager.cc index 92f083e..152223a 100644 --- a/sync/engine/net/server_connection_manager.cc +++ b/sync/engine/net/server_connection_manager.cc @@ -168,11 +168,9 @@ ScopedServerStatusWatcher::~ScopedServerStatusWatcher() { ServerConnectionManager::ServerConnectionManager( const string& server, int port, - bool use_ssl, - const string& user_agent) + bool use_ssl) : sync_server_(server), sync_server_port_(port), - user_agent_(user_agent), use_ssl_(use_ssl), proto_sync_path_(kSyncServerSyncPath), get_time_path_(kSyncServerGetTimePath), diff --git a/sync/engine/net/server_connection_manager.h b/sync/engine/net/server_connection_manager.h index 4083ba2..c61352e 100644 --- a/sync/engine/net/server_connection_manager.h +++ b/sync/engine/net/server_connection_manager.h @@ -176,8 +176,7 @@ class ServerConnectionManager { ServerConnectionManager(const std::string& server, int port, - bool use_ssl, - const std::string& user_agent); + bool use_ssl); virtual ~ServerConnectionManager(); @@ -191,8 +190,6 @@ class ServerConnectionManager { void AddListener(ServerConnectionEventListener* listener); void RemoveListener(ServerConnectionEventListener* listener); - inline std::string user_agent() const { return user_agent_; } - inline HttpResponse::ServerConnectionCode server_status() const { DCHECK(thread_checker_.CalledOnValidThread()); return server_status_; @@ -287,9 +284,6 @@ class ServerConnectionManager { // The unique id of the user's client. std::string client_id_; - // The user-agent string for HTTP. - std::string user_agent_; - // Indicates whether or not requests should be made using HTTPS. bool use_ssl_; diff --git a/sync/engine/syncer_proto_util_unittest.cc b/sync/engine/syncer_proto_util_unittest.cc index 753e490..b0c9f6e 100644 --- a/sync/engine/syncer_proto_util_unittest.cc +++ b/sync/engine/syncer_proto_util_unittest.cc @@ -206,7 +206,7 @@ TEST_F(SyncerProtoUtilTest, AddRequestBirthday) { class DummyConnectionManager : public csync::ServerConnectionManager { public: DummyConnectionManager() - : ServerConnectionManager("unused", 0, false, "version"), + : ServerConnectionManager("unused", 0, false), send_error_(false), access_denied_(false) {} diff --git a/sync/internal_api/DEPS b/sync/internal_api/DEPS index 955b31e..ab23f90 100644 --- a/sync/internal_api/DEPS +++ b/sync/internal_api/DEPS @@ -1,8 +1,6 @@ include_rules = [ "+googleurl", - "+net/base/net_errors.h", - "+net/base/network_change_notifier.h", - "+net/http/http_status_code.h", + "+net", "+sync/engine", "+sync/js", "+sync/notifier", diff --git a/sync/internal_api/http_bridge.cc b/sync/internal_api/http_bridge.cc new file mode 100644 index 0000000..6aa6c4a --- /dev/null +++ b/sync/internal_api/http_bridge.cc @@ -0,0 +1,317 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "sync/internal_api/public/http_bridge.h" + +#include "base/message_loop.h" +#include "base/message_loop_proxy.h" +#include "base/string_number_conversions.h" +#include "net/base/host_resolver.h" +#include "net/base/load_flags.h" +#include "net/base/net_errors.h" +#include "net/cookies/cookie_monster.h" +#include "net/http/http_cache.h" +#include "net/http/http_network_layer.h" +#include "net/http/http_response_headers.h" +#include "net/proxy/proxy_service.h" +#include "net/url_request/url_fetcher.h" +#include "net/url_request/url_request_context.h" +#include "net/url_request/url_request_status.h" + +namespace browser_sync { + +HttpBridge::RequestContextGetter::RequestContextGetter( + net::URLRequestContextGetter* baseline_context_getter, + const std::string& user_agent) + : baseline_context_getter_(baseline_context_getter), + network_task_runner_( + baseline_context_getter_->GetNetworkTaskRunner()), + user_agent_(user_agent) { + DCHECK(baseline_context_getter_); + DCHECK(network_task_runner_); + DCHECK(!user_agent_.empty()); +} + +HttpBridge::RequestContextGetter::~RequestContextGetter() {} + +net::URLRequestContext* +HttpBridge::RequestContextGetter::GetURLRequestContext() { + // Lazily create the context. + if (!context_.get()) { + net::URLRequestContext* baseline_context = + baseline_context_getter_->GetURLRequestContext(); + context_.reset( + new RequestContext(baseline_context, GetNetworkTaskRunner(), + user_agent_)); + baseline_context_getter_ = NULL; + } + + return context_.get(); +} + +scoped_refptr<base::SingleThreadTaskRunner> +HttpBridge::RequestContextGetter::GetNetworkTaskRunner() const { + return network_task_runner_; +} + +HttpBridgeFactory::HttpBridgeFactory( + net::URLRequestContextGetter* baseline_context_getter, + const std::string& user_agent) + : request_context_getter_( + new HttpBridge::RequestContextGetter( + baseline_context_getter, user_agent)) {} + +HttpBridgeFactory::~HttpBridgeFactory() { +} + +csync::HttpPostProviderInterface* HttpBridgeFactory::Create() { + HttpBridge* http = new HttpBridge(request_context_getter_); + http->AddRef(); + return http; +} + +void HttpBridgeFactory::Destroy(csync::HttpPostProviderInterface* http) { + static_cast<HttpBridge*>(http)->Release(); +} + +HttpBridge::RequestContext::RequestContext( + net::URLRequestContext* baseline_context, + const scoped_refptr<base::SingleThreadTaskRunner>& + network_task_runner, + const std::string& user_agent) + : baseline_context_(baseline_context), + network_task_runner_(network_task_runner), + user_agent_(user_agent) { + DCHECK(!user_agent_.empty()); + + // Create empty, in-memory cookie store. + set_cookie_store(new net::CookieMonster(NULL, NULL)); + + // We don't use a cache for bridged loads, but we do want to share proxy info. + set_host_resolver(baseline_context->host_resolver()); + set_proxy_service(baseline_context->proxy_service()); + set_ssl_config_service(baseline_context->ssl_config_service()); + + // We want to share the HTTP session data with the network layer factory, + // which includes auth_cache for proxies. + // Session is not refcounted so we need to be careful to not lose the parent + // context. + net::HttpNetworkSession* session = + baseline_context->http_transaction_factory()->GetSession(); + DCHECK(session); + set_http_transaction_factory(new net::HttpNetworkLayer(session)); + + // TODO(timsteele): We don't currently listen for pref changes of these + // fields or CookiePolicy; I'm not sure we want to strictly follow the + // default settings, since for example if the user chooses to block all + // cookies, sync will start failing. Also it seems like accept_lang/charset + // should be tied to whatever the sync servers expect (if anything). These + // fields should probably just be settable by sync backend; though we should + // figure out if we need to give the user explicit control over policies etc. + set_accept_language(baseline_context->accept_language()); + set_accept_charset(baseline_context->accept_charset()); + + set_net_log(baseline_context->net_log()); +} + +HttpBridge::RequestContext::~RequestContext() { + DCHECK(network_task_runner_->BelongsToCurrentThread()); + delete http_transaction_factory(); +} + +const std::string& HttpBridge::RequestContext::GetUserAgent( + const GURL& url) const { + return user_agent_; +} + +HttpBridge::URLFetchState::URLFetchState() : url_poster(NULL), + aborted(false), + request_completed(false), + request_succeeded(false), + http_response_code(-1), + error_code(-1) {} +HttpBridge::URLFetchState::~URLFetchState() {} + +HttpBridge::HttpBridge(HttpBridge::RequestContextGetter* context_getter) + : context_getter_for_request_(context_getter), + network_task_runner_( + context_getter_for_request_->GetNetworkTaskRunner()), + created_on_loop_(MessageLoop::current()), + http_post_completed_(false, false) { +} + +HttpBridge::~HttpBridge() { +} + +void HttpBridge::SetExtraRequestHeaders(const char * headers) { + DCHECK(extra_headers_.empty()) + << "HttpBridge::SetExtraRequestHeaders called twice."; + extra_headers_.assign(headers); +} + +void HttpBridge::SetURL(const char* url, int port) { + DCHECK_EQ(MessageLoop::current(), created_on_loop_); + if (DCHECK_IS_ON()) { + base::AutoLock lock(fetch_state_lock_); + DCHECK(!fetch_state_.request_completed); + } + DCHECK(url_for_request_.is_empty()) + << "HttpBridge::SetURL called more than once?!"; + GURL temp(url); + GURL::Replacements replacements; + std::string port_str = base::IntToString(port); + replacements.SetPort(port_str.c_str(), + url_parse::Component(0, port_str.length())); + url_for_request_ = temp.ReplaceComponents(replacements); +} + +void HttpBridge::SetPostPayload(const char* content_type, + int content_length, + const char* content) { + DCHECK_EQ(MessageLoop::current(), created_on_loop_); + if (DCHECK_IS_ON()) { + base::AutoLock lock(fetch_state_lock_); + DCHECK(!fetch_state_.request_completed); + } + DCHECK(content_type_.empty()) << "Bridge payload already set."; + DCHECK_GE(content_length, 0) << "Content length < 0"; + content_type_ = content_type; + if (!content || (content_length == 0)) { + DCHECK_EQ(content_length, 0); + request_content_ = " "; // TODO(timsteele): URLFetcher requires non-empty + // content for POSTs whereas CURL does not, for now + // we hack this to support the sync backend. + } else { + request_content_.assign(content, content_length); + } +} + +bool HttpBridge::MakeSynchronousPost(int* error_code, int* response_code) { + DCHECK_EQ(MessageLoop::current(), created_on_loop_); + if (DCHECK_IS_ON()) { + base::AutoLock lock(fetch_state_lock_); + DCHECK(!fetch_state_.request_completed); + } + DCHECK(url_for_request_.is_valid()) << "Invalid URL for request"; + DCHECK(!content_type_.empty()) << "Payload not set"; + + if (!network_task_runner_->PostTask( + FROM_HERE, + base::Bind(&HttpBridge::CallMakeAsynchronousPost, this))) { + // This usually happens when we're in a unit test. + LOG(WARNING) << "Could not post CallMakeAsynchronousPost task"; + return false; + } + + // Block until network request completes or is aborted. See + // OnURLFetchComplete and Abort. + http_post_completed_.Wait(); + + base::AutoLock lock(fetch_state_lock_); + DCHECK(fetch_state_.request_completed || fetch_state_.aborted); + *error_code = fetch_state_.error_code; + *response_code = fetch_state_.http_response_code; + return fetch_state_.request_succeeded; +} + +void HttpBridge::MakeAsynchronousPost() { + DCHECK(network_task_runner_->BelongsToCurrentThread()); + base::AutoLock lock(fetch_state_lock_); + DCHECK(!fetch_state_.request_completed); + if (fetch_state_.aborted) + return; + + fetch_state_.url_poster = net::URLFetcher::Create( + url_for_request_, net::URLFetcher::POST, this); + fetch_state_.url_poster->SetRequestContext(context_getter_for_request_); + fetch_state_.url_poster->SetUploadData(content_type_, request_content_); + fetch_state_.url_poster->SetExtraRequestHeaders(extra_headers_); + fetch_state_.url_poster->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES); + fetch_state_.url_poster->Start(); +} + +int HttpBridge::GetResponseContentLength() const { + DCHECK_EQ(MessageLoop::current(), created_on_loop_); + base::AutoLock lock(fetch_state_lock_); + DCHECK(fetch_state_.request_completed); + return fetch_state_.response_content.size(); +} + +const char* HttpBridge::GetResponseContent() const { + DCHECK_EQ(MessageLoop::current(), created_on_loop_); + base::AutoLock lock(fetch_state_lock_); + DCHECK(fetch_state_.request_completed); + return fetch_state_.response_content.data(); +} + +const std::string HttpBridge::GetResponseHeaderValue( + const std::string& name) const { + + DCHECK_EQ(MessageLoop::current(), created_on_loop_); + base::AutoLock lock(fetch_state_lock_); + DCHECK(fetch_state_.request_completed); + + std::string value; + fetch_state_.response_headers->EnumerateHeader(NULL, name, &value); + return value; +} + +void HttpBridge::Abort() { + base::AutoLock lock(fetch_state_lock_); + DCHECK(!fetch_state_.aborted); + if (fetch_state_.aborted || fetch_state_.request_completed) + return; + + fetch_state_.aborted = true; + if (!network_task_runner_->PostTask( + FROM_HERE, + base::Bind(&HttpBridge::DestroyURLFetcherOnIOThread, this, + fetch_state_.url_poster))) { + // Madness ensues. + NOTREACHED() << "Could not post task to delete URLFetcher"; + } + + fetch_state_.url_poster = NULL; + fetch_state_.error_code = net::ERR_ABORTED; + http_post_completed_.Signal(); +} + +void HttpBridge::DestroyURLFetcherOnIOThread(net::URLFetcher* fetcher) { + DCHECK(network_task_runner_->BelongsToCurrentThread()); + delete fetcher; +} + +void HttpBridge::OnURLFetchComplete(const net::URLFetcher* source) { + DCHECK(network_task_runner_->BelongsToCurrentThread()); + base::AutoLock lock(fetch_state_lock_); + if (fetch_state_.aborted) + return; + + fetch_state_.request_completed = true; + fetch_state_.request_succeeded = + (net::URLRequestStatus::SUCCESS == source->GetStatus().status()); + fetch_state_.http_response_code = source->GetResponseCode(); + fetch_state_.error_code = source->GetStatus().error(); + + // Use a real (non-debug) log to facilitate troubleshooting in the wild. + VLOG(2) << "HttpBridge::OnURLFetchComplete for: " + << fetch_state_.url_poster->GetURL().spec(); + VLOG(1) << "HttpBridge received response code: " + << fetch_state_.http_response_code; + + source->GetResponseAsString(&fetch_state_.response_content); + fetch_state_.response_headers = source->GetResponseHeaders(); + + // End of the line for url_poster_. It lives only on the IO loop. + // We defer deletion because we're inside a callback from a component of the + // URLFetcher, so it seems most natural / "polite" to let the stack unwind. + MessageLoop::current()->DeleteSoon(FROM_HERE, fetch_state_.url_poster); + fetch_state_.url_poster = NULL; + + // Wake the blocked syncer thread in MakeSynchronousPost. + // WARNING: DONT DO ANYTHING AFTER THIS CALL! |this| may be deleted! + http_post_completed_.Signal(); +} + +} // namespace browser_sync diff --git a/sync/internal_api/http_bridge_unittest.cc b/sync/internal_api/http_bridge_unittest.cc new file mode 100644 index 0000000..a4a4ceb --- /dev/null +++ b/sync/internal_api/http_bridge_unittest.cc @@ -0,0 +1,404 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/message_loop_proxy.h" +#include "base/synchronization/waitable_event.h" +#include "base/threading/thread.h" +#include "net/test/test_server.h" +#include "net/url_request/test_url_fetcher_factory.h" +#include "net/url_request/url_fetcher_delegate.h" +#include "net/url_request/url_request_test_util.h" +#include "sync/internal_api/public/http_bridge.h" +#include "testing/gtest/include/gtest/gtest.h" + +using browser_sync::HttpBridge; + +namespace { +// TODO(timsteele): Should use PathService here. See Chromium Issue 3113. +const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data"); +} + +class SyncHttpBridgeTest : public testing::Test { + public: + SyncHttpBridgeTest() + : test_server_(net::TestServer::TYPE_HTTP, + net::TestServer::kLocalhost, + FilePath(kDocRoot)), + fake_default_request_context_getter_(NULL), + bridge_for_race_test_(NULL), + io_thread_("IO thread") { + } + + virtual void SetUp() { + base::Thread::Options options; + options.message_loop_type = MessageLoop::TYPE_IO; + io_thread_.StartWithOptions(options); + } + + virtual void TearDown() { + if (fake_default_request_context_getter_) { + GetIOThreadLoop()->ReleaseSoon(FROM_HERE, + fake_default_request_context_getter_); + fake_default_request_context_getter_ = NULL; + } + io_thread_.Stop(); + } + + HttpBridge* BuildBridge() { + if (!fake_default_request_context_getter_) { + fake_default_request_context_getter_ = + new TestURLRequestContextGetter(io_thread_.message_loop_proxy()); + fake_default_request_context_getter_->AddRef(); + } + HttpBridge* bridge = new HttpBridge( + new HttpBridge::RequestContextGetter( + fake_default_request_context_getter_, + "user agent")); + return bridge; + } + + static void Abort(HttpBridge* bridge) { + bridge->Abort(); + } + + // Used by AbortAndReleaseBeforeFetchCompletes to test an interesting race + // condition. + void RunSyncThreadBridgeUseTest(base::WaitableEvent* signal_when_created, + base::WaitableEvent* signal_when_released); + + static void TestSameHttpNetworkSession(MessageLoop* main_message_loop, + SyncHttpBridgeTest* test) { + scoped_refptr<HttpBridge> http_bridge(test->BuildBridge()); + EXPECT_TRUE(test->GetTestRequestContextGetter()); + net::HttpNetworkSession* test_session = + test->GetTestRequestContextGetter()->GetURLRequestContext()-> + http_transaction_factory()->GetSession(); + EXPECT_EQ(test_session, + http_bridge->GetRequestContextGetter()-> + GetURLRequestContext()-> + http_transaction_factory()->GetSession()); + main_message_loop->PostTask(FROM_HERE, MessageLoop::QuitClosure()); + } + + MessageLoop* GetIOThreadLoop() { + return io_thread_.message_loop(); + } + + // Note this is lazy created, so don't call this before your bridge. + TestURLRequestContextGetter* GetTestRequestContextGetter() { + return fake_default_request_context_getter_; + } + + net::TestServer test_server_; + + base::Thread* io_thread() { return &io_thread_; } + + HttpBridge* bridge_for_race_test() { return bridge_for_race_test_; } + + private: + // A make-believe "default" request context, as would be returned by + // Profile::GetDefaultRequestContext(). Created lazily by BuildBridge. + TestURLRequestContextGetter* fake_default_request_context_getter_; + + HttpBridge* bridge_for_race_test_; + + // Separate thread for IO used by the HttpBridge. + base::Thread io_thread_; + MessageLoop loop_; +}; + +// An HttpBridge that doesn't actually make network requests and just calls +// back with dummy response info. +// TODO(tim): Instead of inheriting here we should inject a component +// responsible for the MakeAsynchronousPost bit. +class ShuntedHttpBridge : public HttpBridge { + public: + // If |never_finishes| is true, the simulated request never actually + // returns. + ShuntedHttpBridge(net::URLRequestContextGetter* baseline_context_getter, + SyncHttpBridgeTest* test, bool never_finishes) + : HttpBridge( + new HttpBridge::RequestContextGetter( + baseline_context_getter, "user agent")), + test_(test), never_finishes_(never_finishes) { } + protected: + virtual void MakeAsynchronousPost() { + ASSERT_TRUE(MessageLoop::current() == test_->GetIOThreadLoop()); + if (never_finishes_) + return; + + // We don't actually want to make a request for this test, so just callback + // as if it completed. + test_->GetIOThreadLoop()->PostTask(FROM_HERE, + base::Bind(&ShuntedHttpBridge::CallOnURLFetchComplete, this)); + } + private: + ~ShuntedHttpBridge() {} + + void CallOnURLFetchComplete() { + ASSERT_TRUE(MessageLoop::current() == test_->GetIOThreadLoop()); + // We return no cookies and a dummy content response. + net::ResponseCookies cookies; + + std::string response_content = "success!"; + net::TestURLFetcher fetcher(0, GURL(), NULL); + fetcher.set_url(GURL("www.google.com")); + fetcher.set_response_code(200); + fetcher.set_cookies(cookies); + fetcher.SetResponseString(response_content); + OnURLFetchComplete(&fetcher); + } + SyncHttpBridgeTest* test_; + bool never_finishes_; +}; + +void SyncHttpBridgeTest::RunSyncThreadBridgeUseTest( + base::WaitableEvent* signal_when_created, + base::WaitableEvent* signal_when_released) { + scoped_refptr<net::URLRequestContextGetter> ctx_getter( + new TestURLRequestContextGetter(io_thread_.message_loop_proxy())); + { + scoped_refptr<ShuntedHttpBridge> bridge(new ShuntedHttpBridge( + ctx_getter, this, true)); + bridge->SetURL("http://www.google.com", 9999); + bridge->SetPostPayload("text/plain", 2, " "); + bridge_for_race_test_ = bridge; + signal_when_created->Signal(); + + int os_error = 0; + int response_code = 0; + bridge->MakeSynchronousPost(&os_error, &response_code); + bridge_for_race_test_ = NULL; + } + signal_when_released->Signal(); +} + +TEST_F(SyncHttpBridgeTest, TestUsesSameHttpNetworkSession) { + // Run this test on the IO thread because we can only call + // URLRequestContextGetter::GetURLRequestContext on the IO thread. + io_thread()->message_loop()->PostTask( + FROM_HERE, + base::Bind(&SyncHttpBridgeTest::TestSameHttpNetworkSession, + MessageLoop::current(), this)); + MessageLoop::current()->Run(); +} + +// Test the HttpBridge without actually making any network requests. +TEST_F(SyncHttpBridgeTest, TestMakeSynchronousPostShunted) { + scoped_refptr<net::URLRequestContextGetter> ctx_getter( + new TestURLRequestContextGetter(io_thread()->message_loop_proxy())); + scoped_refptr<HttpBridge> http_bridge(new ShuntedHttpBridge( + ctx_getter, this, false)); + http_bridge->SetURL("http://www.google.com", 9999); + http_bridge->SetPostPayload("text/plain", 2, " "); + + int os_error = 0; + int response_code = 0; + bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); + EXPECT_TRUE(success); + EXPECT_EQ(200, response_code); + EXPECT_EQ(0, os_error); + + EXPECT_EQ(8, http_bridge->GetResponseContentLength()); + EXPECT_EQ(std::string("success!"), + std::string(http_bridge->GetResponseContent())); +} + +// Full round-trip test of the HttpBridge, using default UA string and +// no request cookies. +TEST_F(SyncHttpBridgeTest, TestMakeSynchronousPostLiveWithPayload) { + ASSERT_TRUE(test_server_.Start()); + + scoped_refptr<HttpBridge> http_bridge(BuildBridge()); + + std::string payload = "this should be echoed back"; + GURL echo = test_server_.GetURL("echo"); + http_bridge->SetURL(echo.spec().c_str(), echo.IntPort()); + http_bridge->SetPostPayload("application/x-www-form-urlencoded", + payload.length() + 1, payload.c_str()); + int os_error = 0; + int response_code = 0; + bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); + EXPECT_TRUE(success); + EXPECT_EQ(200, response_code); + EXPECT_EQ(0, os_error); + + EXPECT_EQ(payload.length() + 1, + static_cast<size_t>(http_bridge->GetResponseContentLength())); + EXPECT_EQ(payload, std::string(http_bridge->GetResponseContent())); +} + +// Full round-trip test of the HttpBridge. +TEST_F(SyncHttpBridgeTest, TestMakeSynchronousPostLiveComprehensive) { + ASSERT_TRUE(test_server_.Start()); + + scoped_refptr<HttpBridge> http_bridge(BuildBridge()); + + GURL echo_header = test_server_.GetURL("echoall"); + http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort()); + + std::string test_payload = "###TEST PAYLOAD###"; + http_bridge->SetPostPayload("text/html", test_payload.length() + 1, + test_payload.c_str()); + + int os_error = 0; + int response_code = 0; + bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); + EXPECT_TRUE(success); + EXPECT_EQ(200, response_code); + EXPECT_EQ(0, os_error); + + std::string response(http_bridge->GetResponseContent(), + http_bridge->GetResponseContentLength()); + EXPECT_EQ(std::string::npos, response.find("Cookie:")); + EXPECT_NE(std::string::npos, response.find("User-Agent: user agent")); + EXPECT_NE(std::string::npos, response.find(test_payload.c_str())); +} + +TEST_F(SyncHttpBridgeTest, TestExtraRequestHeaders) { + ASSERT_TRUE(test_server_.Start()); + + scoped_refptr<HttpBridge> http_bridge(BuildBridge()); + + GURL echo_header = test_server_.GetURL("echoall"); + + http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort()); + http_bridge->SetExtraRequestHeaders("test:fnord"); + + std::string test_payload = "###TEST PAYLOAD###"; + http_bridge->SetPostPayload("text/html", test_payload.length() + 1, + test_payload.c_str()); + + int os_error = 0; + int response_code = 0; + bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); + EXPECT_TRUE(success); + EXPECT_EQ(200, response_code); + EXPECT_EQ(0, os_error); + + std::string response(http_bridge->GetResponseContent(), + http_bridge->GetResponseContentLength()); + + EXPECT_NE(std::string::npos, response.find("fnord")); + EXPECT_NE(std::string::npos, response.find(test_payload.c_str())); +} + +TEST_F(SyncHttpBridgeTest, TestResponseHeader) { + ASSERT_TRUE(test_server_.Start()); + + scoped_refptr<HttpBridge> http_bridge(BuildBridge()); + + GURL echo_header = test_server_.GetURL("echoall"); + http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort()); + + std::string test_payload = "###TEST PAYLOAD###"; + http_bridge->SetPostPayload("text/html", test_payload.length() + 1, + test_payload.c_str()); + + int os_error = 0; + int response_code = 0; + bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); + EXPECT_TRUE(success); + EXPECT_EQ(200, response_code); + EXPECT_EQ(0, os_error); + + EXPECT_EQ(http_bridge->GetResponseHeaderValue("Content-type"), "text/html"); + EXPECT_TRUE(http_bridge->GetResponseHeaderValue("invalid-header").empty()); +} + +TEST_F(SyncHttpBridgeTest, Abort) { + scoped_refptr<net::URLRequestContextGetter> ctx_getter( + new TestURLRequestContextGetter(io_thread()->message_loop_proxy())); + scoped_refptr<ShuntedHttpBridge> http_bridge(new ShuntedHttpBridge( + ctx_getter, this, true)); + http_bridge->SetURL("http://www.google.com", 9999); + http_bridge->SetPostPayload("text/plain", 2, " "); + + int os_error = 0; + int response_code = 0; + + io_thread()->message_loop_proxy()->PostTask( + FROM_HERE, + base::Bind(&SyncHttpBridgeTest::Abort, http_bridge)); + bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); + EXPECT_FALSE(success); + EXPECT_EQ(net::ERR_ABORTED, os_error); +} + +TEST_F(SyncHttpBridgeTest, AbortLate) { + scoped_refptr<net::URLRequestContextGetter> ctx_getter( + new TestURLRequestContextGetter(io_thread()->message_loop_proxy())); + scoped_refptr<ShuntedHttpBridge> http_bridge(new ShuntedHttpBridge( + ctx_getter, this, false)); + http_bridge->SetURL("http://www.google.com", 9999); + http_bridge->SetPostPayload("text/plain", 2, " "); + + int os_error = 0; + int response_code = 0; + + bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); + ASSERT_TRUE(success); + http_bridge->Abort(); + // Ensures no double-free of URLFetcher, etc. +} + +// Tests an interesting case where code using the HttpBridge aborts the fetch +// and releases ownership before a pending fetch completed callback is issued by +// the underlying URLFetcher (and before that URLFetcher is destroyed, which +// would cancel the callback). +TEST_F(SyncHttpBridgeTest, AbortAndReleaseBeforeFetchComplete) { + base::Thread sync_thread("SyncThread"); + sync_thread.Start(); + + // First, block the sync thread on the post. + base::WaitableEvent signal_when_created(false, false); + base::WaitableEvent signal_when_released(false, false); + sync_thread.message_loop()->PostTask(FROM_HERE, + base::Bind(&SyncHttpBridgeTest::RunSyncThreadBridgeUseTest, + base::Unretained(this), + &signal_when_created, + &signal_when_released)); + + // Stop IO so we can control order of operations. + base::WaitableEvent io_waiter(false, false); + ASSERT_TRUE(io_thread()->message_loop_proxy()->PostTask( + FROM_HERE, + base::Bind(&base::WaitableEvent::Wait, base::Unretained(&io_waiter)))); + + signal_when_created.Wait(); // Wait till we have a bridge to abort. + ASSERT_TRUE(bridge_for_race_test()); + + // Schedule the fetch completion callback (but don't run it yet). Don't take + // a reference to the bridge to mimic URLFetcher's handling of the delegate. + net::URLFetcherDelegate* delegate = + static_cast<net::URLFetcherDelegate*>(bridge_for_race_test()); + net::ResponseCookies cookies; + std::string response_content = "success!"; + net::TestURLFetcher fetcher(0, GURL(), NULL); + fetcher.set_url(GURL("www.google.com")); + fetcher.set_response_code(200); + fetcher.set_cookies(cookies); + fetcher.SetResponseString(response_content); + ASSERT_TRUE(io_thread()->message_loop_proxy()->PostTask( + FROM_HERE, + base::Bind(&net::URLFetcherDelegate::OnURLFetchComplete, + base::Unretained(delegate), &fetcher))); + + // Abort the fetch. This should be smart enough to handle the case where + // the bridge is destroyed before the callback scheduled above completes. + bridge_for_race_test()->Abort(); + + // Wait until the sync thread releases its ref on the bridge. + signal_when_released.Wait(); + ASSERT_FALSE(bridge_for_race_test()); + + // Unleash the hounds. The fetch completion callback should fire first, and + // succeed even though we Release()d the bridge above because the call to + // Abort should have held a reference. + io_waiter.Signal(); + + // Done. + sync_thread.Stop(); + io_thread()->Stop(); +} diff --git a/sync/internal_api/public/http_bridge.h b/sync/internal_api/public/http_bridge.h new file mode 100644 index 0000000..cec5526 --- /dev/null +++ b/sync/internal_api/public/http_bridge.h @@ -0,0 +1,232 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SYNC_INTERNAL_API_PUBLIC_HTTP_BRIDGE_H_ +#define SYNC_INTERNAL_API_PUBLIC_HTTP_BRIDGE_H_ +#pragma once + +#include <string> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/gtest_prod_util.h" +#include "base/memory/ref_counted.h" +#include "base/synchronization/lock.h" +#include "base/synchronization/waitable_event.h" +#include "googleurl/src/gurl.h" +#include "net/url_request/url_fetcher_delegate.h" +#include "net/url_request/url_request_context.h" +#include "net/url_request/url_request_context_getter.h" +#include "sync/internal_api/public/http_post_provider_factory.h" +#include "sync/internal_api/public/http_post_provider_interface.h" + +class MessageLoop; +class HttpBridgeTest; + +namespace net { +class HttpResponseHeaders; +class URLFetcher; +} + +namespace browser_sync { + +// A bridge between the syncer and Chromium HTTP layers. +// Provides a way for the sync backend to use Chromium directly for HTTP +// requests rather than depending on a third party provider (e.g libcurl). +// This is a one-time use bridge. Create one for each request you want to make. +// It is RefCountedThreadSafe because it can PostTask to the io loop, and thus +// needs to stick around across context switches, etc. +class HttpBridge : public base::RefCountedThreadSafe<HttpBridge>, + public csync::HttpPostProviderInterface, + public net::URLFetcherDelegate { + public: + // A request context used for HTTP requests bridged from the sync backend. + // A bridged RequestContext has a dedicated in-memory cookie store and does + // not use a cache. Thus the same type can be used for incognito mode. + class RequestContext : public net::URLRequestContext { + public: + // |baseline_context| is used to obtain the accept-language, + // accept-charsets, and proxy service information for bridged requests. + // Typically |baseline_context| should be the net::URLRequestContext of the + // currently active profile. + RequestContext( + net::URLRequestContext* baseline_context, + const scoped_refptr<base::SingleThreadTaskRunner>& + network_task_runner, + const std::string& user_agent); + + // The destructor MUST be called on the IO thread. + virtual ~RequestContext(); + + virtual const std::string& GetUserAgent(const GURL& url) const OVERRIDE; + + private: + net::URLRequestContext* const baseline_context_; + const scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_; + const std::string user_agent_; + + DISALLOW_COPY_AND_ASSIGN(RequestContext); + }; + + // Lazy-getter for RequestContext objects. + class RequestContextGetter : public net::URLRequestContextGetter { + public: + RequestContextGetter( + net::URLRequestContextGetter* baseline_context_getter, + const std::string& user_agent); + + // net::URLRequestContextGetter implementation. + virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE; + virtual scoped_refptr<base::SingleThreadTaskRunner> + GetNetworkTaskRunner() const OVERRIDE; + + protected: + virtual ~RequestContextGetter(); + + private: + scoped_refptr<net::URLRequestContextGetter> baseline_context_getter_; + const scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_; + // User agent to apply to the net::URLRequestContext. + const std::string user_agent_; + + // Lazily initialized by GetURLRequestContext(). + scoped_ptr<RequestContext> context_; + + DISALLOW_COPY_AND_ASSIGN(RequestContextGetter); + }; + + explicit HttpBridge(RequestContextGetter* context); + + // csync::HttpPostProvider implementation. + virtual void SetExtraRequestHeaders(const char* headers) OVERRIDE; + virtual void SetURL(const char* url, int port) OVERRIDE; + virtual void SetPostPayload(const char* content_type, int content_length, + const char* content) OVERRIDE; + virtual bool MakeSynchronousPost(int* error_code, + int* response_code) OVERRIDE; + virtual void Abort() OVERRIDE; + + // WARNING: these response content methods are used to extract plain old data + // and not null terminated strings, so you should make sure you have read + // GetResponseContentLength() characters when using GetResponseContent. e.g + // string r(b->GetResponseContent(), b->GetResponseContentLength()). + virtual int GetResponseContentLength() const OVERRIDE; + virtual const char* GetResponseContent() const OVERRIDE; + virtual const std::string GetResponseHeaderValue( + const std::string& name) const OVERRIDE; + + // net::URLFetcherDelegate implementation. + virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; + +#if defined(UNIT_TEST) + net::URLRequestContextGetter* GetRequestContextGetter() const { + return context_getter_for_request_; + } +#endif + + protected: + friend class base::RefCountedThreadSafe<HttpBridge>; + + virtual ~HttpBridge(); + + // Protected virtual so the unit test can override to shunt network requests. + virtual void MakeAsynchronousPost(); + + private: + friend class ::HttpBridgeTest; + + // Called on the IO loop to issue the network request. The extra level + // of indirection is so that the unit test can override this behavior but we + // still have a function to statically pass to PostTask. + void CallMakeAsynchronousPost() { MakeAsynchronousPost(); } + + // Used to destroy a fetcher when the bridge is Abort()ed, to ensure that + // a reference to |this| is held while flushing any pending fetch completion + // callbacks coming from the IO thread en route to finally destroying the + // fetcher. + void DestroyURLFetcherOnIOThread(net::URLFetcher* fetcher); + + // Gets a customized net::URLRequestContext for bridged requests. See + // RequestContext definition for details. + const scoped_refptr<RequestContextGetter> context_getter_for_request_; + + const scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_; + + // The message loop of the thread we were created on. This is the thread that + // will block on MakeSynchronousPost while the IO thread fetches data from + // the network. + // This should be the main syncer thread (SyncerThread) which is what blocks + // on network IO through curl_easy_perform. + MessageLoop* const created_on_loop_; + + // The URL to POST to. + GURL url_for_request_; + + // POST payload information. + std::string content_type_; + std::string request_content_; + std::string extra_headers_; + + // A waitable event we use to provide blocking semantics to + // MakeSynchronousPost. We block created_on_loop_ while the IO loop fetches + // network request. + base::WaitableEvent http_post_completed_; + + struct URLFetchState { + URLFetchState(); + ~URLFetchState(); + // Our hook into the network layer is a URLFetcher. USED ONLY ON THE IO + // LOOP, so we can block created_on_loop_ while the fetch is in progress. + // NOTE: This is not a scoped_ptr for a reason. It must be deleted on the + // same thread that created it, which isn't the same thread |this| gets + // deleted on. We must manually delete url_poster_ on the IO loop. + net::URLFetcher* url_poster; + + // Used to support 'Abort' functionality. + bool aborted; + + // Cached response data. + bool request_completed; + bool request_succeeded; + int http_response_code; + int error_code; + std::string response_content; + scoped_refptr<net::HttpResponseHeaders> response_headers; + }; + + // This lock synchronizes use of state involved in the flow to fetch a URL + // using URLFetcher. Because we can Abort() from any thread, for example, + // this flow needs to be synchronized to gracefully clean up URLFetcher and + // return appropriate values in |error_code|. + mutable base::Lock fetch_state_lock_; + URLFetchState fetch_state_; + + DISALLOW_COPY_AND_ASSIGN(HttpBridge); +}; + +class HttpBridgeFactory : public csync::HttpPostProviderFactory { + public: + HttpBridgeFactory( + net::URLRequestContextGetter* baseline_context_getter, + const std::string& user_agent); + virtual ~HttpBridgeFactory(); + + // csync::HttpPostProviderFactory: + virtual csync::HttpPostProviderInterface* Create() OVERRIDE; + virtual void Destroy(csync::HttpPostProviderInterface* http) OVERRIDE; + + private: + // This request context is built on top of the baseline context and shares + // common components. + HttpBridge::RequestContextGetter* GetRequestContextGetter(); + + const scoped_refptr<HttpBridge::RequestContextGetter> + request_context_getter_; + + DISALLOW_COPY_AND_ASSIGN(HttpBridgeFactory); +}; + +} // namespace browser_sync + +#endif // SYNC_INTERNAL_API_PUBLIC_HTTP_BRIDGE_H_ diff --git a/sync/internal_api/public/http_post_provider_interface.h b/sync/internal_api/public/http_post_provider_interface.h index adee0df..378e18f 100644 --- a/sync/internal_api/public/http_post_provider_interface.h +++ b/sync/internal_api/public/http_post_provider_interface.h @@ -16,10 +16,6 @@ namespace csync { // want to make a subsequent POST. class HttpPostProviderInterface { public: - // Use specified user agent string when POSTing. If not called a default UA - // may be used. - virtual void SetUserAgent(const char* user_agent) = 0; - // Add additional headers to the request. virtual void SetExtraRequestHeaders(const char* headers) = 0; diff --git a/sync/internal_api/public/sync_manager.h b/sync/internal_api/public/sync_manager.h index 86f2b6d..3a2cf2e 100644 --- a/sync/internal_api/public/sync_manager.h +++ b/sync/internal_api/public/sync_manager.h @@ -368,6 +368,9 @@ class SyncManager { // HTTP header. Used internally when collecting stats to classify clients. // |sync_notifier| is owned and used to listen for notifications. // |report_unrecoverable_error_function| may be NULL. + // + // TODO(akalin): Replace the |post_factory| parameter with a + // URLFetcher parameter. bool Init(const FilePath& database_location, const csync::WeakHandle<csync::JsEventHandler>& event_handler, @@ -381,7 +384,6 @@ class SyncManager { csync::ExtensionsActivityMonitor* extensions_activity_monitor, ChangeDelegate* change_delegate, - const std::string& user_agent, const SyncCredentials& credentials, csync::SyncNotifier* sync_notifier, const std::string& restored_key_for_bootstrapping, diff --git a/sync/internal_api/sync_manager.cc b/sync/internal_api/sync_manager.cc index 25eee06..eb5a02d 100644 --- a/sync/internal_api/sync_manager.cc +++ b/sync/internal_api/sync_manager.cc @@ -204,7 +204,6 @@ class SyncManager::SyncInternal csync::ExtensionsActivityMonitor* extensions_activity_monitor, ChangeDelegate* change_delegate, - const std::string& user_agent, const SyncCredentials& credentials, csync::SyncNotifier* sync_notifier, const std::string& restored_key_for_bootstrapping, @@ -720,7 +719,6 @@ bool SyncManager::Init( const std::vector<csync::ModelSafeWorker*>& workers, csync::ExtensionsActivityMonitor* extensions_activity_monitor, ChangeDelegate* change_delegate, - const std::string& user_agent, const SyncCredentials& credentials, csync::SyncNotifier* sync_notifier, const std::string& restored_key_for_bootstrapping, @@ -743,7 +741,6 @@ bool SyncManager::Init( workers, extensions_activity_monitor, change_delegate, - user_agent, credentials, sync_notifier, restored_key_for_bootstrapping, @@ -866,7 +863,6 @@ bool SyncManager::SyncInternal::Init( const std::vector<csync::ModelSafeWorker*>& workers, csync::ExtensionsActivityMonitor* extensions_activity_monitor, ChangeDelegate* change_delegate, - const std::string& user_agent, const SyncCredentials& credentials, csync::SyncNotifier* sync_notifier, const std::string& restored_key_for_bootstrapping, @@ -905,7 +901,7 @@ bool SyncManager::SyncInternal::Init( report_unrecoverable_error_function_)); connection_manager_.reset(new SyncAPIServerConnectionManager( - sync_server_and_path, port, use_ssl, user_agent, post_factory)); + sync_server_and_path, port, use_ssl, post_factory)); net::NetworkChangeNotifier::AddIPAddressObserver(this); observing_ip_address_changes_ = true; diff --git a/sync/internal_api/syncapi_server_connection_manager.cc b/sync/internal_api/syncapi_server_connection_manager.cc index 078c6fc..f2abcc9 100644 --- a/sync/internal_api/syncapi_server_connection_manager.cc +++ b/sync/internal_api/syncapi_server_connection_manager.cc @@ -37,7 +37,6 @@ bool SyncAPIBridgedConnection::Init(const char* path, std::string connection_url = MakeConnectionURL(sync_server, path, use_ssl); HttpPostProviderInterface* http = post_provider_; - http->SetUserAgent(scm_->user_agent().c_str()); http->SetURL(connection_url.c_str(), sync_server_port); if (!auth_token.empty()) { @@ -90,9 +89,8 @@ SyncAPIServerConnectionManager::SyncAPIServerConnectionManager( const std::string& server, int port, bool use_ssl, - const std::string& client_version, HttpPostProviderFactory* factory) - : ServerConnectionManager(server, port, use_ssl, client_version), + : ServerConnectionManager(server, port, use_ssl), post_provider_factory_(factory) { DCHECK(post_provider_factory_.get()); } diff --git a/sync/internal_api/syncapi_server_connection_manager.h b/sync/internal_api/syncapi_server_connection_manager.h index 5a3f952..9678045 100644 --- a/sync/internal_api/syncapi_server_connection_manager.h +++ b/sync/internal_api/syncapi_server_connection_manager.h @@ -55,7 +55,6 @@ class SyncAPIServerConnectionManager SyncAPIServerConnectionManager(const std::string& server, int port, bool use_ssl, - const std::string& client_version, HttpPostProviderFactory* factory); virtual ~SyncAPIServerConnectionManager(); diff --git a/sync/internal_api/syncapi_server_connection_manager_unittest.cc b/sync/internal_api/syncapi_server_connection_manager_unittest.cc index 67b3e25..a6e34d0 100644 --- a/sync/internal_api/syncapi_server_connection_manager_unittest.cc +++ b/sync/internal_api/syncapi_server_connection_manager_unittest.cc @@ -29,7 +29,6 @@ class BlockingHttpPost : public HttpPostProviderInterface { BlockingHttpPost() : wait_for_abort_(false, false) {} virtual ~BlockingHttpPost() {} - virtual void SetUserAgent(const char* user_agent) OVERRIDE {} virtual void SetExtraRequestHeaders(const char* headers) OVERRIDE {} virtual void SetURL(const char* url, int port) OVERRIDE {} virtual void SetPostPayload(const char* content_type, @@ -74,7 +73,7 @@ class BlockingHttpPostFactory : public HttpPostProviderFactory { TEST(SyncAPIServerConnectionManagerTest, EarlyAbortPost) { SyncAPIServerConnectionManager server( - "server", 0, true, "1", new BlockingHttpPostFactory()); + "server", 0, true, new BlockingHttpPostFactory()); ServerConnectionManager::PostBufferParams params; ScopedServerStatusWatcher watcher(&server, ¶ms.response); @@ -90,7 +89,7 @@ TEST(SyncAPIServerConnectionManagerTest, EarlyAbortPost) { TEST(SyncAPIServerConnectionManagerTest, AbortPost) { SyncAPIServerConnectionManager server( - "server", 0, true, "1", new BlockingHttpPostFactory()); + "server", 0, true, new BlockingHttpPostFactory()); ServerConnectionManager::PostBufferParams params; ScopedServerStatusWatcher watcher(&server, ¶ms.response); diff --git a/sync/internal_api/syncapi_unittest.cc b/sync/internal_api/syncapi_unittest.cc index 8384de2..1d125ce 100644 --- a/sync/internal_api/syncapi_unittest.cc +++ b/sync/internal_api/syncapi_unittest.cc @@ -653,7 +653,6 @@ class TestHttpPostProviderInterface : public HttpPostProviderInterface { public: virtual ~TestHttpPostProviderInterface() {} - virtual void SetUserAgent(const char* user_agent) OVERRIDE {} virtual void SetExtraRequestHeaders(const char* headers) OVERRIDE {} virtual void SetURL(const char* url, int port) OVERRIDE {} virtual void SetPostPayload(const char* content_type, @@ -785,7 +784,7 @@ class SyncManagerTest : public testing::Test, "bogus", 0, false, base::MessageLoopProxy::current(), new TestHttpPostProviderFactory(), routing_info, workers, - &extensions_activity_monitor_, this, "bogus", + &extensions_activity_monitor_, this, credentials, sync_notifier_mock_, "", csync::SyncManager::TEST_IN_MEMORY, diff --git a/sync/sync.gyp b/sync/sync.gyp index 7fca6b9..9d4cd1f 100644 --- a/sync/sync.gyp +++ b/sync/sync.gyp @@ -297,6 +297,7 @@ 'internal_api/public/base_transaction.h', 'internal_api/public/change_record.h', 'internal_api/public/configure_reason.h', + 'internal_api/public/http_bridge.h', 'internal_api/public/http_post_provider_factory.h', 'internal_api/public/http_post_provider_interface.h', 'internal_api/public/read_node.h', @@ -312,6 +313,7 @@ 'internal_api/change_reorder_buffer.h', 'internal_api/debug_info_event_listener.cc', 'internal_api/debug_info_event_listener.h', + 'internal_api/http_bridge.cc', 'internal_api/js_mutation_event_observer.cc', 'internal_api/js_mutation_event_observer.h', 'internal_api/js_sync_manager_observer.cc', @@ -639,6 +641,7 @@ 'dependencies': [ '../base/base.gyp:base', '../net/net.gyp:net', + '../net/net.gyp:net_test_support', '../testing/gmock.gyp:gmock', '../testing/gtest.gyp:gtest', 'protocol/sync_proto.gyp:sync_proto', @@ -652,6 +655,7 @@ 'export_dependent_settings': [ '../base/base.gyp:base', '../net/net.gyp:net', + '../net/net.gyp:net_test_support', '../testing/gmock.gyp:gmock', '../testing/gtest.gyp:gtest', 'protocol/sync_proto.gyp:sync_proto', @@ -668,6 +672,7 @@ 'sources': [ 'internal_api/public/change_record_unittest.cc', 'internal_api/debug_info_event_listener_unittest.cc', + 'internal_api/http_bridge_unittest.cc', 'internal_api/js_mutation_event_observer_unittest.cc', 'internal_api/js_sync_manager_observer_unittest.cc', 'internal_api/syncapi_server_connection_manager_unittest.cc', diff --git a/sync/test/engine/mock_connection_manager.cc b/sync/test/engine/mock_connection_manager.cc index 4bf97f5..ab29b9a 100644 --- a/sync/test/engine/mock_connection_manager.cc +++ b/sync/test/engine/mock_connection_manager.cc @@ -41,7 +41,7 @@ using syncable::WriteTransaction; static char kValidAuthToken[] = "AuthToken"; MockConnectionManager::MockConnectionManager(syncable::Directory* directory) - : ServerConnectionManager("unused", 0, false, "version"), + : ServerConnectionManager("unused", 0, false), server_reachable_(true), conflict_all_commits_(false), conflict_n_commits_(0), |