Revert "Revert "Migrate gcm to network service's socket APIs""
This reverts commit 838e1b1949af36aec49042cd1df6d55396d0957b.
Reason for revert: Reland after fix
Mojo doesn't allow dropping response callbacks (see
https://groups.google.com/a/chromium.org/forum/#!topic/services-dev/zSNh16-tkaA
for discussion). The fix is to modify
ProxyResolvingSocketFactory::CreateProxyResolvingSocket to always invoke
the response callback even when the underlying socket is destroyed.
This CL also adds a regression test in proxy_resolving_socket_mojo_unittest.cc.
[email protected]
[email protected]
[email protected]
Cq-Include-Trybots: luci.chromium.try:ios-simulator-full-configs;luci.chromium.try:linux_mojo;master.tryserver.chromium.mac:ios-simulator-cronet
Change-Id: Ie9fdb93f965bbcf534253aaabe436c4de5f0666d
Bug: 862608, 868220
Cq-Include-Trybots: luci.chromium.try:ios-simulator-full-configs;luci.chromium.try:linux_mojo;master.tryserver.chromium.mac:ios-simulator-cronet
Change-Id: Ie9fdb93f965bbcf534253aaabe436c4de5f0666d
Reviewed-on: https://chromium-review.googlesource.com/1169345
Reviewed-by: Helen Li <[email protected]>
Reviewed-by: Maks Orlovich <[email protected]>
Reviewed-by: Daniel Cheng <[email protected]>
Reviewed-by: Peter Beverloo <[email protected]>
Commit-Queue: Helen Li <[email protected]>
Cr-Commit-Position: refs/heads/master@{#582318}
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index cca59ea3d..8ca357fc 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -522,6 +522,23 @@
waitable_event_.TimedWait(timeout);
}
+#if !defined(OS_ANDROID)
+void RequestProxyResolvingSocketFactoryOnUIThread(
+ network::mojom::ProxyResolvingSocketFactoryRequest request) {
+ network::mojom::NetworkContext* network_context =
+ g_browser_process->system_network_context_manager()->GetContext();
+ network_context->CreateProxyResolvingSocketFactory(std::move(request));
+}
+
+void RequestProxyResolvingSocketFactory(
+ network::mojom::ProxyResolvingSocketFactoryRequest request) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&RequestProxyResolvingSocketFactoryOnUIThread,
+ std::move(request)));
+}
+#endif
+
} // namespace
void BrowserProcessImpl::FlushLocalStateAndReply(base::OnceClosure reply) {
@@ -1338,7 +1355,7 @@
gcm_driver_ = gcm::CreateGCMDriverDesktop(
base::WrapUnique(new gcm::GCMClientFactory), local_state(), store_path,
- system_request_context(),
+ base::BindRepeating(&RequestProxyResolvingSocketFactory),
system_network_context_manager()->GetSharedURLLoaderFactory(),
chrome::GetChannel(), gcm::GetProductCategoryForSubtypes(local_state()),
content::BrowserThread::GetTaskRunnerForThread(
diff --git a/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc b/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
index f14183e4..25fc22c3 100644
--- a/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
+++ b/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
@@ -73,6 +73,28 @@
const char kTestExtensionName[] = "FooBar";
+void RequestProxyResolvingSocketFactoryOnUIThread(
+ Profile* profile,
+ base::WeakPtr<gcm::GCMProfileService> service,
+ network::mojom::ProxyResolvingSocketFactoryRequest request) {
+ if (!service)
+ return;
+ network::mojom::NetworkContext* network_context =
+ content::BrowserContext::GetDefaultStoragePartition(profile)
+ ->GetNetworkContext();
+ network_context->CreateProxyResolvingSocketFactory(std::move(request));
+}
+
+void RequestProxyResolvingSocketFactory(
+ Profile* profile,
+ base::WeakPtr<gcm::GCMProfileService> service,
+ network::mojom::ProxyResolvingSocketFactoryRequest request) {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&RequestProxyResolvingSocketFactoryOnUIThread, profile,
+ service, std::move(request)));
+}
+
} // namespace
// Helper class for asynchronous waiting.
@@ -208,6 +230,7 @@
{base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
return std::make_unique<gcm::GCMProfileService>(
profile->GetPrefs(), profile->GetPath(), profile->GetRequestContext(),
+ base::BindRepeating(&RequestProxyResolvingSocketFactory, profile),
content::BrowserContext::GetDefaultStoragePartition(profile)
->GetURLLoaderFactoryForBrowserProcess(),
chrome::GetChannel(),
diff --git a/chrome/browser/gcm/gcm_profile_service_factory.cc b/chrome/browser/gcm/gcm_profile_service_factory.cc
index 2890eb1..ed3be69 100644
--- a/chrome/browser/gcm/gcm_profile_service_factory.cc
+++ b/chrome/browser/gcm/gcm_profile_service_factory.cc
@@ -35,6 +35,38 @@
namespace gcm {
+namespace {
+
+#if !defined(OS_ANDROID)
+// Requests a ProxyResolvingSocketFactoryPtr on the UI thread. Note that a
+// WeakPtr of GCMProfileService is needed to detect when the KeyedService shuts
+// down, and avoid calling into |profile| which might have also been destroyed.
+void RequestProxyResolvingSocketFactoryOnUIThread(
+ Profile* profile,
+ base::WeakPtr<GCMProfileService> service,
+ network::mojom::ProxyResolvingSocketFactoryRequest request) {
+ if (!service)
+ return;
+ network::mojom::NetworkContext* network_context =
+ content::BrowserContext::GetDefaultStoragePartition(profile)
+ ->GetNetworkContext();
+ network_context->CreateProxyResolvingSocketFactory(std::move(request));
+}
+
+// A thread-safe wrapper to request a ProxyResolvingSocketFactoryPtr.
+void RequestProxyResolvingSocketFactory(
+ Profile* profile,
+ base::WeakPtr<GCMProfileService> service,
+ network::mojom::ProxyResolvingSocketFactoryRequest request) {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&RequestProxyResolvingSocketFactoryOnUIThread, profile,
+ std::move(service), std::move(request)));
+}
+#endif
+
+} // namespace
+
// static
GCMProfileService* GCMProfileServiceFactory::GetForProfile(
content::BrowserContext* profile) {
@@ -78,8 +110,9 @@
service = base::WrapUnique(
new GCMProfileService(profile->GetPath(), blocking_task_runner));
#else
- service = base::WrapUnique(new GCMProfileService(
+ service = std::make_unique<GCMProfileService>(
profile->GetPrefs(), profile->GetPath(), profile->GetRequestContext(),
+ base::BindRepeating(&RequestProxyResolvingSocketFactory, profile),
content::BrowserContext::GetDefaultStoragePartition(profile)
->GetURLLoaderFactoryForBrowserProcess(),
chrome::GetChannel(),
@@ -90,7 +123,7 @@
content::BrowserThread::UI),
content::BrowserThread::GetTaskRunnerForThread(
content::BrowserThread::IO),
- blocking_task_runner));
+ blocking_task_runner);
#endif
#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
offline_pages::PrefetchService* prefetch_service =
diff --git a/chrome/browser/gcm/gcm_profile_service_unittest.cc b/chrome/browser/gcm/gcm_profile_service_unittest.cc
index 7c72d74..55e0bf1 100644
--- a/chrome/browser/gcm/gcm_profile_service_unittest.cc
+++ b/chrome/browser/gcm/gcm_profile_service_unittest.cc
@@ -43,6 +43,27 @@
const char kTestAppID[] = "TestApp";
const char kUserID[] = "user";
+void RequestProxyResolvingSocketFactoryOnUIThread(
+ Profile* profile,
+ base::WeakPtr<gcm::GCMProfileService> service,
+ network::mojom::ProxyResolvingSocketFactoryRequest request) {
+ if (!service)
+ return;
+ return content::BrowserContext::GetDefaultStoragePartition(profile)
+ ->GetNetworkContext()
+ ->CreateProxyResolvingSocketFactory(std::move(request));
+}
+
+void RequestProxyResolvingSocketFactory(
+ Profile* profile,
+ base::WeakPtr<gcm::GCMProfileService> service,
+ network::mojom::ProxyResolvingSocketFactoryRequest request) {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&RequestProxyResolvingSocketFactoryOnUIThread, profile,
+ service, std::move(request)));
+}
+
std::unique_ptr<KeyedService> BuildGCMProfileService(
content::BrowserContext* context) {
Profile* profile = Profile::FromBrowserContext(context);
@@ -51,6 +72,7 @@
{base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
return std::make_unique<gcm::GCMProfileService>(
profile->GetPrefs(), profile->GetPath(), profile->GetRequestContext(),
+ base::BindRepeating(&RequestProxyResolvingSocketFactory, profile),
content::BrowserContext::GetDefaultStoragePartition(profile)
->GetURLLoaderFactoryForBrowserProcess(),
chrome::GetChannel(),
diff --git a/components/gcm_driver/BUILD.gn b/components/gcm_driver/BUILD.gn
index 0c5bcb1e..5ef587a 100644
--- a/components/gcm_driver/BUILD.gn
+++ b/components/gcm_driver/BUILD.gn
@@ -47,7 +47,9 @@
"//components/gcm_driver/common",
"//components/gcm_driver/crypto",
"//components/gcm_driver/instance_id",
+ "//crypto",
]
+
deps = [
":gcm_buildflags",
"//base:i18n",
@@ -64,6 +66,7 @@
"//net",
"//services/identity/public/cpp",
"//services/network/public/cpp",
+ "//services/network/public/mojom",
"//url:url",
]
@@ -140,6 +143,7 @@
"//net",
"//services/network:test_support",
"//services/network/public/cpp",
+ "//services/network/public/mojom",
"//testing/gtest",
]
diff --git a/components/gcm_driver/DEPS b/components/gcm_driver/DEPS
index 4adaea8..0fb497e1 100644
--- a/components/gcm_driver/DEPS
+++ b/components/gcm_driver/DEPS
@@ -21,6 +21,7 @@
"+net",
"+services/identity/public",
"+services/network/public/cpp",
+ "+services/network/public/mojom",
"+services/network/test",
"+third_party/leveldatabase", # Only used for tests.
]
diff --git a/components/gcm_driver/fake_gcm_client.cc b/components/gcm_driver/fake_gcm_client.cc
index 87e2bf9e..8c1db00 100644
--- a/components/gcm_driver/fake_gcm_client.cc
+++ b/components/gcm_driver/fake_gcm_client.cc
@@ -75,8 +75,9 @@
const ChromeBuildInfo& chrome_build_info,
const base::FilePath& store_path,
const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
- const scoped_refptr<net::URLRequestContextGetter>&
- url_request_context_getter,
+ base::RepeatingCallback<
+ void(network::mojom::ProxyResolvingSocketFactoryRequest)>
+ get_socket_factory_callback,
const scoped_refptr<network::SharedURLLoaderFactory>& url_loader_factory,
std::unique_ptr<Encryptor> encryptor,
Delegate* delegate) {
diff --git a/components/gcm_driver/fake_gcm_client.h b/components/gcm_driver/fake_gcm_client.h
index e1500d0..15be54d4 100644
--- a/components/gcm_driver/fake_gcm_client.h
+++ b/components/gcm_driver/fake_gcm_client.h
@@ -46,8 +46,9 @@
const ChromeBuildInfo& chrome_build_info,
const base::FilePath& store_path,
const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
- const scoped_refptr<net::URLRequestContextGetter>&
- url_request_context_getter,
+ base::RepeatingCallback<
+ void(network::mojom::ProxyResolvingSocketFactoryRequest)>
+ get_socket_factory_callback,
const scoped_refptr<network::SharedURLLoaderFactory>& url_loader_factory,
std::unique_ptr<Encryptor> encryptor,
Delegate* delegate) override;
diff --git a/components/gcm_driver/gcm_client.h b/components/gcm_driver/gcm_client.h
index 79a7789..e8bd9d6 100644
--- a/components/gcm_driver/gcm_client.h
+++ b/components/gcm_driver/gcm_client.h
@@ -16,6 +16,7 @@
#include "components/gcm_driver/common/gcm_messages.h"
#include "components/gcm_driver/gcm_activity.h"
#include "components/gcm_driver/registration_info.h"
+#include "services/network/public/mojom/proxy_resolving_socket.mojom.h"
template <class T> class scoped_refptr;
@@ -27,7 +28,6 @@
namespace net {
class IPEndPoint;
-class URLRequestContextGetter;
}
namespace network {
@@ -235,16 +235,18 @@
// |chrome_build_info|: chrome info, i.e., version, channel and etc.
// |store_path|: path to the GCM store.
// |blocking_task_runner|: for running blocking file tasks.
- // |url_request_context_getter|: for url requests. The GCMClient must be
- // deleted before the Getter's underlying URLRequestContext.
+ // |get_socket_factory_callback|: a callback that can accept a request for a
+ // network::mojom::ProxyResolvingSocketFactoryPtr. It needs to be safe to
+ // run on any thread.
// |delegate|: the delegate whose methods will be called asynchronously in
// response to events and messages.
virtual void Initialize(
const ChromeBuildInfo& chrome_build_info,
const base::FilePath& store_path,
const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
- const scoped_refptr<net::URLRequestContextGetter>&
- url_request_context_getter,
+ base::RepeatingCallback<
+ void(network::mojom::ProxyResolvingSocketFactoryRequest)>
+ get_socket_factory_callback,
const scoped_refptr<network::SharedURLLoaderFactory>& url_loader_factory,
std::unique_ptr<Encryptor> encryptor,
Delegate* delegate) = 0;
diff --git a/components/gcm_driver/gcm_client_impl.cc b/components/gcm_driver/gcm_client_impl.cc
index c30c7dcb..168bef6 100644
--- a/components/gcm_driver/gcm_client_impl.cc
+++ b/components/gcm_driver/gcm_client_impl.cc
@@ -41,7 +41,6 @@
#include "google_apis/gcm/monitoring/gcm_stats_recorder.h"
#include "google_apis/gcm/protocol/checkin.pb.h"
#include "google_apis/gcm/protocol/mcs.pb.h"
-#include "net/url_request/url_request_context.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "url/gurl.h"
@@ -279,10 +278,13 @@
std::unique_ptr<ConnectionFactory> GCMInternalsBuilder::BuildConnectionFactory(
const std::vector<GURL>& endpoints,
const net::BackoffEntry::Policy& backoff_policy,
- net::URLRequestContext* url_request_context,
+ base::RepeatingCallback<
+ void(network::mojom::ProxyResolvingSocketFactoryRequest)>
+ get_socket_factory_callback,
GCMStatsRecorder* recorder) {
- return base::WrapUnique<ConnectionFactory>(new ConnectionFactoryImpl(
- endpoints, backoff_policy, url_request_context, recorder));
+ return std::make_unique<ConnectionFactoryImpl>(
+ endpoints, backoff_policy, std::move(get_socket_factory_callback),
+ recorder);
}
GCMClientImpl::CheckinInfo::CheckinInfo()
@@ -318,7 +320,6 @@
start_mode_(DELAYED_START),
clock_(internals_builder_->GetClock()),
gcm_store_reset_(false),
- url_request_context_getter_(nullptr),
periodic_checkin_ptr_factory_(this),
destroying_gcm_store_ptr_factory_(this),
weak_ptr_factory_(this) {}
@@ -330,16 +331,16 @@
const ChromeBuildInfo& chrome_build_info,
const base::FilePath& path,
const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
- const scoped_refptr<net::URLRequestContextGetter>&
- url_request_context_getter,
+ base::RepeatingCallback<
+ void(network::mojom::ProxyResolvingSocketFactoryRequest)>
+ get_socket_factory_callback,
const scoped_refptr<network::SharedURLLoaderFactory>& url_loader_factory,
std::unique_ptr<Encryptor> encryptor,
GCMClient::Delegate* delegate) {
DCHECK_EQ(UNINITIALIZED, state_);
- DCHECK(url_request_context_getter);
DCHECK(delegate);
- url_request_context_getter_ = url_request_context_getter;
+ get_socket_factory_callback_ = std::move(get_socket_factory_callback);
url_loader_factory_ = url_loader_factory;
chrome_build_info_ = chrome_build_info;
@@ -498,8 +499,8 @@
if (fallback_endpoint.is_valid())
endpoints.push_back(fallback_endpoint);
connection_factory_ = internals_builder_->BuildConnectionFactory(
- endpoints, GetGCMBackoffPolicy(),
- url_request_context_getter_->GetURLRequestContext(), &recorder_);
+ endpoints, GetGCMBackoffPolicy(), get_socket_factory_callback_,
+ &recorder_);
connection_factory_->SetConnectionListener(this);
mcs_client_ = internals_builder_->BuildMCSClient(
chrome_build_info_.version, clock_, connection_factory_.get(),
diff --git a/components/gcm_driver/gcm_client_impl.h b/components/gcm_driver/gcm_client_impl.h
index d2c730a3..5f9edd6 100644
--- a/components/gcm_driver/gcm_client_impl.h
+++ b/components/gcm_driver/gcm_client_impl.h
@@ -29,7 +29,7 @@
#include "google_apis/gcm/protocol/android_checkin.pb.h"
#include "google_apis/gcm/protocol/checkin.pb.h"
#include "net/http/http_status_code.h"
-#include "net/url_request/url_request_context_getter.h"
+#include "services/network/public/mojom/proxy_resolving_socket.mojom.h"
class GURL;
@@ -42,10 +42,6 @@
class DataMessageStanza;
} // namespace mcs_proto
-namespace net {
-class URLRequestContext;
-} // namespace net
-
namespace network {
class SharedURLLoaderFactory;
} // namespace network
@@ -73,7 +69,9 @@
virtual std::unique_ptr<ConnectionFactory> BuildConnectionFactory(
const std::vector<GURL>& endpoints,
const net::BackoffEntry::Policy& backoff_policy,
- net::URLRequestContext* url_request_context,
+ base::RepeatingCallback<
+ void(network::mojom::ProxyResolvingSocketFactoryRequest)>
+ get_socket_factory_callback,
GCMStatsRecorder* recorder);
};
@@ -112,8 +110,9 @@
const ChromeBuildInfo& chrome_build_info,
const base::FilePath& store_path,
const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
- const scoped_refptr<net::URLRequestContextGetter>&
- url_request_context_getter,
+ base::RepeatingCallback<
+ void(network::mojom::ProxyResolvingSocketFactoryRequest)>
+ get_socket_factory_callback,
const scoped_refptr<network::SharedURLLoaderFactory>& url_loader_factory,
std::unique_ptr<Encryptor> encryptor,
GCMClient::Delegate* delegate) override;
@@ -369,7 +368,10 @@
bool gcm_store_reset_;
std::unique_ptr<ConnectionFactory> connection_factory_;
- scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
+ base::RepeatingCallback<void(
+ network::mojom::ProxyResolvingSocketFactoryRequest)>
+ get_socket_factory_callback_;
+
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
// Controls receiving and sending of packets and reliable message queueing.
diff --git a/components/gcm_driver/gcm_client_impl_unittest.cc b/components/gcm_driver/gcm_client_impl_unittest.cc
index a2895c0e..f4404026 100644
--- a/components/gcm_driver/gcm_client_impl_unittest.cc
+++ b/components/gcm_driver/gcm_client_impl_unittest.cc
@@ -9,6 +9,7 @@
#include <initializer_list>
#include <memory>
+#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
@@ -230,7 +231,9 @@
std::unique_ptr<ConnectionFactory> BuildConnectionFactory(
const std::vector<GURL>& endpoints,
const net::BackoffEntry::Policy& backoff_policy,
- net::URLRequestContext* url_request_context,
+ base::RepeatingCallback<
+ void(network::mojom::ProxyResolvingSocketFactoryRequest)>
+ get_socket_factory_callback,
GCMStatsRecorder* recorder) override;
private:
@@ -260,7 +263,9 @@
FakeGCMInternalsBuilder::BuildConnectionFactory(
const std::vector<GURL>& endpoints,
const net::BackoffEntry::Policy& backoff_policy,
- net::URLRequestContext* url_request_context,
+ base::RepeatingCallback<
+ void(network::mojom::ProxyResolvingSocketFactoryRequest)>
+ get_socket_factory_callback,
GCMStatsRecorder* recorder) {
return base::WrapUnique<ConnectionFactory>(new FakeConnectionFactory());
}
@@ -622,8 +627,7 @@
chrome_build_info.version = kChromeVersion;
chrome_build_info.product_category_for_subtypes = kProductCategoryForSubtypes;
gcm_client_->Initialize(
- chrome_build_info, gcm_store_path(), task_runner_,
- url_request_context_getter_,
+ chrome_build_info, gcm_store_path(), task_runner_, base::DoNothing(),
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_),
base::WrapUnique<Encryptor>(new FakeEncryptor), this);
diff --git a/components/gcm_driver/gcm_desktop_utils.cc b/components/gcm_driver/gcm_desktop_utils.cc
index e1c9cfd..57c82121 100644
--- a/components/gcm_driver/gcm_desktop_utils.cc
+++ b/components/gcm_driver/gcm_desktop_utils.cc
@@ -93,7 +93,9 @@
std::unique_ptr<GCMClientFactory> gcm_client_factory,
PrefService* prefs,
const base::FilePath& store_path,
- const scoped_refptr<net::URLRequestContextGetter>& request_context,
+ base::RepeatingCallback<
+ void(network::mojom::ProxyResolvingSocketFactoryRequest)>
+ get_socket_factory_callback,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
version_info::Channel channel,
const std::string& product_category_for_subtypes,
@@ -104,8 +106,8 @@
std::move(gcm_client_factory),
GetChromeBuildInfo(channel, product_category_for_subtypes),
GetChannelStatusRequestUrl(channel), GetUserAgent(channel), prefs,
- store_path, request_context, url_loader_factory, ui_task_runner,
- io_task_runner, blocking_task_runner));
+ store_path, get_socket_factory_callback, url_loader_factory,
+ ui_task_runner, io_task_runner, blocking_task_runner));
}
} // namespace gcm
diff --git a/components/gcm_driver/gcm_desktop_utils.h b/components/gcm_driver/gcm_desktop_utils.h
index 8663fb4..105cd20 100644
--- a/components/gcm_driver/gcm_desktop_utils.h
+++ b/components/gcm_driver/gcm_desktop_utils.h
@@ -10,16 +10,13 @@
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
#include "components/version_info/version_info.h"
+#include "services/network/public/mojom/proxy_resolving_socket.mojom.h"
class PrefService;
namespace base {
class FilePath;
}
-namespace net {
-class URLRequestContextGetter;
-}
-
namespace network {
class SharedURLLoaderFactory;
}
@@ -33,7 +30,9 @@
std::unique_ptr<GCMClientFactory> gcm_client_factory,
PrefService* prefs,
const base::FilePath& store_path,
- const scoped_refptr<net::URLRequestContextGetter>& request_context,
+ base::RepeatingCallback<
+ void(network::mojom::ProxyResolvingSocketFactoryRequest)>
+ get_socket_factory_callback,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
version_info::Channel channel,
const std::string& product_category_for_subtypes,
diff --git a/components/gcm_driver/gcm_driver_desktop.cc b/components/gcm_driver/gcm_driver_desktop.cc
index 864e3cd..d5a93c60 100644
--- a/components/gcm_driver/gcm_driver_desktop.cc
+++ b/components/gcm_driver/gcm_driver_desktop.cc
@@ -26,7 +26,6 @@
#include "components/gcm_driver/system_encryptor.h"
#include "google_apis/gcm/engine/account_mapping.h"
#include "net/base/ip_endpoint.h"
-#include "net/url_request/url_request_context_getter.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#if defined(OS_CHROMEOS)
@@ -73,7 +72,9 @@
std::unique_ptr<GCMClientFactory> gcm_client_factory,
const GCMClient::ChromeBuildInfo& chrome_build_info,
const base::FilePath& store_path,
- const scoped_refptr<net::URLRequestContextGetter>& request_context,
+ base::RepeatingCallback<
+ void(network::mojom::ProxyResolvingSocketFactoryRequest)>
+ get_socket_factory_callback,
std::unique_ptr<network::SharedURLLoaderFactoryInfo> loader_factory_info,
const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
void Start(GCMClient::StartMode start_mode,
@@ -145,7 +146,9 @@
std::unique_ptr<GCMClientFactory> gcm_client_factory,
const GCMClient::ChromeBuildInfo& chrome_build_info,
const base::FilePath& store_path,
- const scoped_refptr<net::URLRequestContextGetter>& request_context,
+ base::RepeatingCallback<
+ void(network::mojom::ProxyResolvingSocketFactoryRequest)>
+ get_socket_factory_callback,
std::unique_ptr<network::SharedURLLoaderFactoryInfo> loader_factory_info,
const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) {
DCHECK(io_thread_->RunsTasksInCurrentSequence());
@@ -156,7 +159,8 @@
network::SharedURLLoaderFactory::Create(std::move(loader_factory_info));
gcm_client_->Initialize(chrome_build_info, store_path, blocking_task_runner,
- request_context, url_loader_factory_for_io,
+ std::move(get_socket_factory_callback),
+ url_loader_factory_for_io,
std::make_unique<SystemEncryptor>(), this);
}
@@ -505,7 +509,9 @@
const std::string& user_agent,
PrefService* prefs,
const base::FilePath& store_path,
- const scoped_refptr<net::URLRequestContextGetter>& request_context,
+ base::RepeatingCallback<
+ void(network::mojom::ProxyResolvingSocketFactoryRequest)>
+ get_socket_factory_callback,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_for_ui,
const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
const scoped_refptr<base::SequencedTaskRunner>& io_thread,
@@ -540,7 +546,7 @@
base::BindOnce(&GCMDriverDesktop::IOWorker::Initialize,
base::Unretained(io_worker_.get()),
std::move(gcm_client_factory), chrome_build_info,
- store_path, request_context,
+ store_path, std::move(get_socket_factory_callback),
// ->Clone() permits creation of an equivalent
// SharedURLLoaderFactory on IO thread.
url_loader_factory_for_ui->Clone(), blocking_task_runner));
diff --git a/components/gcm_driver/gcm_driver_desktop.h b/components/gcm_driver/gcm_driver_desktop.h
index c2713e12..697dcc8 100644
--- a/components/gcm_driver/gcm_driver_desktop.h
+++ b/components/gcm_driver/gcm_driver_desktop.h
@@ -22,6 +22,7 @@
#include "components/gcm_driver/gcm_client.h"
#include "components/gcm_driver/gcm_connection_observer.h"
#include "components/gcm_driver/gcm_driver.h"
+#include "services/network/public/mojom/proxy_resolving_socket.mojom.h"
class PrefService;
@@ -30,10 +31,6 @@
class SequencedTaskRunner;
}
-namespace net {
-class URLRequestContextGetter;
-}
-
namespace network {
class SharedURLLoaderFactory;
}
@@ -57,7 +54,9 @@
const std::string& user_agent,
PrefService* prefs,
const base::FilePath& store_path,
- const scoped_refptr<net::URLRequestContextGetter>& request_context,
+ base::RepeatingCallback<
+ void(network::mojom::ProxyResolvingSocketFactoryRequest)>
+ get_socket_factory_callback,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_for_ui,
const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
const scoped_refptr<base::SequencedTaskRunner>& io_thread,
diff --git a/components/gcm_driver/gcm_driver_desktop_unittest.cc b/components/gcm_driver/gcm_driver_desktop_unittest.cc
index c31e7437..3ea40822 100644
--- a/components/gcm_driver/gcm_driver_desktop_unittest.cc
+++ b/components/gcm_driver/gcm_driver_desktop_unittest.cc
@@ -243,15 +243,15 @@
new net::TestURLRequestContextGetter(io_thread_.task_runner());
GCMClient::ChromeBuildInfo chrome_build_info;
chrome_build_info.product_category_for_subtypes = "com.chrome.macosx";
- driver_.reset(new GCMDriverDesktop(
+ driver_ = std::make_unique<GCMDriverDesktop>(
std::unique_ptr<GCMClientFactory>(new FakeGCMClientFactory(
base::ThreadTaskRunnerHandle::Get(), io_thread_.task_runner())),
chrome_build_info, kTestChannelStatusRequestURL, "user-agent-string",
- &prefs_, temp_dir_.GetPath(), request_context,
+ &prefs_, temp_dir_.GetPath(), base::DoNothing(),
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_),
base::ThreadTaskRunnerHandle::Get(), io_thread_.task_runner(),
- message_loop_.task_runner()));
+ message_loop_.task_runner());
gcm_app_handler_.reset(new FakeGCMAppHandler);
gcm_connection_observer_.reset(new FakeGCMConnectionObserver);
diff --git a/components/gcm_driver/gcm_profile_service.cc b/components/gcm_driver/gcm_profile_service.cc
index 9ba06f5..47bd3d00 100644
--- a/components/gcm_driver/gcm_profile_service.cc
+++ b/components/gcm_driver/gcm_profile_service.cc
@@ -142,6 +142,10 @@
PrefService* prefs,
base::FilePath path,
net::URLRequestContextGetter* request_context,
+ base::RepeatingCallback<
+ void(base::WeakPtr<GCMProfileService>,
+ network::mojom::ProxyResolvingSocketFactoryRequest)>
+ get_socket_factory_callback,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
version_info::Channel channel,
const std::string& product_category_for_subtypes,
@@ -150,11 +154,12 @@
const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner,
const scoped_refptr<base::SequencedTaskRunner>& io_task_runner,
scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner)
- : identity_manager_(identity_manager),
- request_context_(request_context) {
+ : identity_manager_(identity_manager), request_context_(request_context) {
driver_ = CreateGCMDriverDesktop(
std::move(gcm_client_factory), prefs,
- path.Append(gcm_driver::kGCMStoreDirname), request_context_,
+ path.Append(gcm_driver::kGCMStoreDirname),
+ base::BindRepeating(get_socket_factory_callback,
+ weak_ptr_factory_.GetWeakPtr()),
url_loader_factory, channel, product_category_for_subtypes,
ui_task_runner, io_task_runner, blocking_task_runner);
diff --git a/components/gcm_driver/gcm_profile_service.h b/components/gcm_driver/gcm_profile_service.h
index ba66cdf..0da5c055 100644
--- a/components/gcm_driver/gcm_profile_service.h
+++ b/components/gcm_driver/gcm_profile_service.h
@@ -13,10 +13,12 @@
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "build/build_config.h"
#include "components/gcm_driver/gcm_buildflags.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/version_info/version_info.h"
+#include "services/network/public/mojom/proxy_resolving_socket.mojom.h"
class PrefService;
@@ -44,6 +46,9 @@
// Providing GCM service, via GCMDriver.
class GCMProfileService : public KeyedService {
public:
+ using GetProxyResolvingFactoryCallback = base::RepeatingCallback<void(
+ network::mojom::ProxyResolvingSocketFactoryRequest)>;
+
#if BUILDFLAG(USE_GCM_FROM_PLATFORM)
GCMProfileService(
base::FilePath path,
@@ -53,6 +58,10 @@
PrefService* prefs,
base::FilePath path,
net::URLRequestContextGetter* request_context,
+ base::RepeatingCallback<
+ void(base::WeakPtr<GCMProfileService>,
+ network::mojom::ProxyResolvingSocketFactoryRequest)>
+ get_socket_factory_callback,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
version_info::Channel channel,
const std::string& product_category_for_subtypes,
@@ -92,6 +101,11 @@
std::unique_ptr<IdentityObserver> identity_observer_;
#endif
+ GetProxyResolvingFactoryCallback get_socket_factory_callback_;
+
+ // WeakPtr generated by the factory must be dereferenced on the UI thread.
+ base::WeakPtrFactory<GCMProfileService> weak_ptr_factory_{this};
+
DISALLOW_COPY_AND_ASSIGN(GCMProfileService);
};
diff --git a/components/gcm_driver/instance_id/BUILD.gn b/components/gcm_driver/instance_id/BUILD.gn
index b0936a1..5a316155 100644
--- a/components/gcm_driver/instance_id/BUILD.gn
+++ b/components/gcm_driver/instance_id/BUILD.gn
@@ -22,6 +22,7 @@
"//components/keyed_service/core:core",
"//components/prefs:prefs",
"//crypto",
+ "//services/network/public/mojom",
]
if (use_gcm_from_platform) {
diff --git a/google_apis/gcm/BUILD.gn b/google_apis/gcm/BUILD.gn
index 97642da9..bc2bef948 100644
--- a/google_apis/gcm/BUILD.gn
+++ b/google_apis/gcm/BUILD.gn
@@ -66,9 +66,10 @@
deps = [
"//base",
"//base/third_party/dynamic_annotations",
+ "//mojo/public/cpp/system:system",
"//net",
- "//services/network:network_service",
"//services/network/public/cpp",
+ "//services/network/public/mojom",
"//third_party/leveldatabase",
"//url",
]
@@ -107,6 +108,7 @@
]
deps = [
"//base",
+ "//mojo/public/cpp/system:system",
"//net",
"//net:test_support",
"//testing/gtest",
@@ -164,8 +166,10 @@
"//base",
"//base/test:test_support",
"//mojo/core/embedder",
+ "//mojo/public/cpp/system:system",
"//net",
"//net:test_support",
+ "//services/network:network_service",
"//services/network:test_support",
"//testing/gtest",
"//third_party/protobuf:protobuf_lite",
diff --git a/google_apis/gcm/DEPS b/google_apis/gcm/DEPS
index a044cbe8..ad4f5f8 100644
--- a/google_apis/gcm/DEPS
+++ b/google_apis/gcm/DEPS
@@ -11,4 +11,5 @@
"+net",
"+third_party/leveldatabase",
"+services/network",
+ "+mojo/public/cpp",
]
diff --git a/google_apis/gcm/base/socket_stream.cc b/google_apis/gcm/base/socket_stream.cc
index 6674d9c..964005c 100644
--- a/google_apis/gcm/base/socket_stream.cc
+++ b/google_apis/gcm/base/socket_stream.cc
@@ -21,15 +21,22 @@
} // namespace
-SocketInputStream::SocketInputStream(net::StreamSocket* socket)
- : socket_(socket),
+SocketInputStream::SocketInputStream(mojo::ScopedDataPipeConsumerHandle stream)
+ : stream_(std::move(stream)),
+ stream_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL),
+ read_size_(0),
io_buffer_(new net::IOBuffer(kDefaultBufferSize)),
- read_buffer_(new net::DrainableIOBuffer(io_buffer_.get(),
- kDefaultBufferSize)),
+ read_buffer_(
+ new net::DrainableIOBuffer(io_buffer_.get(), kDefaultBufferSize)),
next_pos_(0),
last_error_(net::OK),
weak_ptr_factory_(this) {
- DCHECK(socket->IsConnected());
+ stream_watcher_.Watch(
+ stream_.get(),
+ MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
+ base::BindRepeating(&SocketInputStream::ReadMore,
+ base::Unretained(this)));
}
SocketInputStream::~SocketInputStream() {
@@ -85,39 +92,74 @@
return read_buffer_->BytesConsumed() - next_pos_;
}
-net::Error SocketInputStream::Refresh(const base::Closure& callback,
+net::Error SocketInputStream::Refresh(base::OnceClosure callback,
int byte_limit) {
+ DCHECK(!read_callback_);
DCHECK_NE(GetState(), CLOSED);
DCHECK_NE(GetState(), READING);
DCHECK_GT(byte_limit, 0);
if (byte_limit > read_buffer_->BytesRemaining()) {
LOG(ERROR) << "Out of buffer space, closing input stream.";
- CloseStream(net::ERR_FILE_TOO_BIG, base::Closure());
+ CloseStream(net::ERR_FILE_TOO_BIG);
return net::OK;
}
- if (!socket_->IsConnected()) {
- LOG(ERROR) << "Socket was disconnected, closing input stream";
- CloseStream(net::ERR_CONNECTION_CLOSED, base::Closure());
- return net::OK;
+ read_size_ = byte_limit;
+ read_callback_ = std::move(callback);
+ stream_watcher_.ArmOrNotify();
+ last_error_ = net::ERR_IO_PENDING;
+ return net::ERR_IO_PENDING;
+}
+
+void SocketInputStream::ReadMore(
+ MojoResult result,
+ const mojo::HandleSignalsState& /* ignored */) {
+ DCHECK(read_callback_);
+ DCHECK_NE(0u, read_size_);
+
+ uint32_t num_bytes = read_size_;
+ if (result == MOJO_RESULT_OK) {
+ DVLOG(1) << "Refreshing input stream, limit of " << num_bytes << " bytes.";
+ result = stream_->ReadData(read_buffer_->data(), &num_bytes,
+ MOJO_READ_DATA_FLAG_NONE);
+ DVLOG(1) << "Read returned mojo result" << result;
}
- DVLOG(1) << "Refreshing input stream, limit of " << byte_limit << " bytes.";
- int result =
- socket_->Read(read_buffer_.get(),
- byte_limit,
- base::Bind(&SocketInputStream::RefreshCompletionCallback,
- weak_ptr_factory_.GetWeakPtr(),
- callback));
- DVLOG(1) << "Read returned " << result;
- if (result == net::ERR_IO_PENDING) {
- last_error_ = net::ERR_IO_PENDING;
- return net::ERR_IO_PENDING;
+ if (result == MOJO_RESULT_SHOULD_WAIT) {
+ stream_watcher_.ArmOrNotify();
+ return;
}
- RefreshCompletionCallback(base::Closure(), result);
- return net::OK;
+ read_size_ = 0;
+ if (result != MOJO_RESULT_OK) {
+ CloseStream(net::ERR_FAILED);
+ std::move(read_callback_).Run();
+ return;
+ }
+
+ // If an EOF has been received, close the stream.
+ if (result == MOJO_RESULT_OK && num_bytes == 0) {
+ CloseStream(net::ERR_CONNECTION_CLOSED);
+ std::move(read_callback_).Run();
+ return;
+ }
+
+ // If an error occurred before the completion callback could complete, ignore
+ // the result.
+ if (GetState() == CLOSED)
+ return;
+
+ last_error_ = net::OK;
+ read_buffer_->DidConsume(num_bytes);
+ // TODO(zea): investigating crbug.com/409985
+ CHECK_GT(UnreadByteCount(), 0);
+
+ DVLOG(1) << "Refresh complete with " << num_bytes << " new bytes. "
+ << "Current position " << next_pos_ << " of "
+ << read_buffer_->BytesConsumed() << ".";
+
+ std::move(read_callback_).Run();
}
void SocketInputStream::RebuildBuffer() {
@@ -162,39 +204,6 @@
return READY;
}
-void SocketInputStream::RefreshCompletionCallback(
- const base::Closure& callback, int result) {
- // If an error occurred before the completion callback could complete, ignore
- // the result.
- if (GetState() == CLOSED)
- return;
-
- // Result == 0 implies EOF, which is treated as an error.
- if (result == 0)
- result = net::ERR_CONNECTION_CLOSED;
-
- DCHECK_NE(result, net::ERR_IO_PENDING);
-
- if (result < net::OK) {
- DVLOG(1) << "Failed to refresh socket: " << result;
- CloseStream(static_cast<net::Error>(result), callback);
- return;
- }
-
- DCHECK_GT(result, 0);
- last_error_ = net::OK;
- read_buffer_->DidConsume(result);
- // TODO(zea): investigating crbug.com/409985
- CHECK_GT(UnreadByteCount(), 0);
-
- DVLOG(1) << "Refresh complete with " << result << " new bytes. "
- << "Current position " << next_pos_
- << " of " << read_buffer_->BytesConsumed() << ".";
-
- if (!callback.is_null())
- callback.Run();
-}
-
void SocketInputStream::ResetInternal() {
read_buffer_->SetOffset(0);
next_pos_ = 0;
@@ -202,26 +211,27 @@
weak_ptr_factory_.InvalidateWeakPtrs(); // Invalidate any callbacks.
}
-void SocketInputStream::CloseStream(net::Error error,
- const base::Closure& callback) {
+void SocketInputStream::CloseStream(net::Error error) {
DCHECK_LT(error, net::ERR_IO_PENDING);
ResetInternal();
last_error_ = error;
LOG(ERROR) << "Closing stream with result " << error;
- if (!callback.is_null())
- callback.Run();
}
SocketOutputStream::SocketOutputStream(
- net::StreamSocket* socket,
- const net::NetworkTrafficAnnotationTag& traffic_annotation)
- : socket_(socket),
+ mojo::ScopedDataPipeProducerHandle stream)
+ : stream_(std::move(stream)),
+ stream_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL),
io_buffer_(new net::IOBufferWithSize(kDefaultBufferSize)),
next_pos_(0),
last_error_(net::OK),
- traffic_annotation_(traffic_annotation),
weak_ptr_factory_(this) {
- DCHECK(socket->IsConnected());
+ stream_watcher_.Watch(
+ stream_.get(),
+ MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
+ base::BindRepeating(&SocketOutputStream::WriteMore,
+ base::Unretained(this)));
}
SocketOutputStream::~SocketOutputStream() {
@@ -254,7 +264,8 @@
return next_pos_;
}
-net::Error SocketOutputStream::Flush(const base::Closure& callback) {
+net::Error SocketOutputStream::Flush(base::OnceClosure callback) {
+ DCHECK(!write_callback_);
DCHECK_EQ(GetState(), READY);
if (!write_buffer_) {
@@ -262,27 +273,52 @@
io_buffer_.get(), next_pos_);
}
- if (!socket_->IsConnected()) {
- LOG(ERROR) << "Socket was disconnected, closing output stream";
- last_error_ = net::ERR_CONNECTION_CLOSED;
- return net::OK;
- }
+ last_error_ = net::ERR_IO_PENDING;
+ stream_watcher_.ArmOrNotify();
+ write_callback_ = std::move(callback);
+ return net::ERR_IO_PENDING;
+}
- DVLOG(1) << "Flushing " << write_buffer_->BytesRemaining()
- << " bytes into socket.";
- int result =
- socket_->Write(write_buffer_.get(), write_buffer_->BytesRemaining(),
- base::Bind(&SocketOutputStream::FlushCompletionCallback,
- weak_ptr_factory_.GetWeakPtr(), callback),
- traffic_annotation_);
- DVLOG(1) << "Write returned " << result;
- if (result == net::ERR_IO_PENDING) {
- last_error_ = net::ERR_IO_PENDING;
- return net::ERR_IO_PENDING;
- }
+void SocketOutputStream::WriteMore(MojoResult result,
+ const mojo::HandleSignalsState& state) {
+ DCHECK(write_callback_);
+ DCHECK(write_buffer_);
- FlushCompletionCallback(base::Closure(), result);
- return net::OK;
+ uint32_t num_bytes = write_buffer_->BytesRemaining();
+ DVLOG(1) << "Flushing " << num_bytes << " bytes into socket.";
+ if (result == MOJO_RESULT_OK) {
+ result = stream_->WriteData(write_buffer_->data(), &num_bytes,
+ MOJO_WRITE_DATA_FLAG_NONE);
+ }
+ if (result == MOJO_RESULT_SHOULD_WAIT) {
+ stream_watcher_.ArmOrNotify();
+ return;
+ }
+ if (result != MOJO_RESULT_OK) {
+ LOG(ERROR) << "Failed to flush socket.";
+ last_error_ = net::ERR_FAILED;
+ std::move(write_callback_).Run();
+ return;
+ }
+ DVLOG(1) << "Wrote " << num_bytes;
+ // If an error occurred before the completion callback could complete, ignore
+ // the result.
+ if (GetState() == CLOSED)
+ return;
+
+ DCHECK_GE(num_bytes, 0u);
+ last_error_ = net::OK;
+ write_buffer_->DidConsume(num_bytes);
+ if (write_buffer_->BytesRemaining() > 0) {
+ DVLOG(1) << "Partial flush complete. Retrying.";
+ // Only a partial write was completed. Flush again to finish the write.
+ Flush(std::move(write_callback_));
+ return;
+ }
+ DVLOG(1) << "Socket flush complete.";
+ write_buffer_ = nullptr;
+ next_pos_ = 0;
+ std::move(write_callback_).Run();
}
SocketOutputStream::State SocketOutputStream::GetState() const{
@@ -303,43 +339,4 @@
return last_error_;
}
-void SocketOutputStream::FlushCompletionCallback(
- const base::Closure& callback, int result) {
- // If an error occurred before the completion callback could complete, ignore
- // the result.
- if (GetState() == CLOSED)
- return;
-
- // Result == 0 implies EOF, which is treated as an error.
- if (result == 0)
- result = net::ERR_CONNECTION_CLOSED;
-
- DCHECK_NE(result, net::ERR_IO_PENDING);
-
- if (result < net::OK) {
- LOG(ERROR) << "Failed to flush socket.";
- last_error_ = static_cast<net::Error>(result);
- if (!callback.is_null())
- callback.Run();
- return;
- }
-
- DCHECK_GT(result, net::OK);
- last_error_ = net::OK;
- write_buffer_->DidConsume(result);
-
- if (write_buffer_->BytesRemaining() > 0) {
- DVLOG(1) << "Partial flush complete. Retrying.";
- // Only a partial write was completed. Flush again to finish the write.
- Flush(callback);
- return;
- }
-
- DVLOG(1) << "Socket flush complete.";
- write_buffer_ = nullptr;
- next_pos_ = 0;
- if (!callback.is_null())
- callback.Run();
-}
-
} // namespace gcm
diff --git a/google_apis/gcm/base/socket_stream.h b/google_apis/gcm/base/socket_stream.h
index c68acd00..63556b2 100644
--- a/google_apis/gcm/base/socket_stream.h
+++ b/google_apis/gcm/base/socket_stream.h
@@ -2,14 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// Protobuf ZeroCopy[Input/Output]Stream implementations capable of using a
-// net::StreamSocket. Built to work with Protobuf CodedStreams.
+// Protobuf ZeroCopy[Input/Output]Stream implementations capable of using
+// mojo data pipes. Built to work with Protobuf CodedStreams.
#ifndef GOOGLE_APIS_GCM_BASE_SOCKET_STREAM_H_
#define GOOGLE_APIS_GCM_BASE_SOCKET_STREAM_H_
#include <stdint.h>
+#include "base/callback.h"
#include "base/callback_forward.h"
#include "base/compiler_specific.h"
#include "base/macros.h"
@@ -17,24 +18,21 @@
#include "base/memory/weak_ptr.h"
#include "google/protobuf/io/zero_copy_stream.h"
#include "google_apis/gcm/base/gcm_export.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "mojo/public/cpp/system/simple_watcher.h"
#include "net/base/net_errors.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
namespace net {
class DrainableIOBuffer;
class IOBuffer;
class IOBufferWithSize;
-class StreamSocket;
} // namespace net
namespace gcm {
-// A helper class for interacting with a net::StreamSocket that is receiving
-// protobuf encoded messages. A SocketInputStream does not take ownership of
-// the socket itself, and it is expected that the life of the input stream
-// should match the life of the socket itself (while the socket remains
-// connected). If an error is encounters, the input stream will store the error
-// in |last_error_|, and GetState() will be set to CLOSED.
+// A helper class for interacting with a mojo consumer pipe that is receiving
+// protobuf encoded messages. If an error is encounters, the input stream will
+// store the error in |last_error_|, and GetState() will be set to CLOSED.
// Typical usage:
// 1. Check the GetState() of the input stream before using it. If CLOSED, the
// input stream must be rebuilt (and the socket likely needs to be
@@ -66,7 +64,7 @@
};
// |socket| should already be connected.
- explicit SocketInputStream(net::StreamSocket* socket);
+ explicit SocketInputStream(mojo::ScopedDataPipeConsumerHandle stream);
~SocketInputStream() override;
// ZeroCopyInputStream implementation.
@@ -85,7 +83,7 @@
// net::OK without invoking callback.
// Note: GetState() (and possibly last_error()) should be checked upon
// completion to determine whether the Refresh encountered an error.
- net::Error Refresh(const base::Closure& callback, int byte_limit);
+ net::Error Refresh(base::OnceClosure callback, int byte_limit);
// Rebuilds the buffer state by copying over any unread data to the beginning
// of the buffer and resetting the buffer read/write positions.
@@ -94,7 +92,9 @@
void RebuildBuffer();
// Returns the last fatal error encountered. Only valid if GetState() ==
- // CLOSED.
+ // CLOSED. Note that all network read errors will be reported as
+ // net::ERR_FAILED, because mojo data pipe doesn't allow surfacing a more
+ // specific error code.
net::Error last_error() const;
// Returns the current state.
@@ -104,15 +104,17 @@
// Clears the local state.
void ResetInternal();
- // Callback for Socket::Read calls.
- void RefreshCompletionCallback(const base::Closure& callback, int result);
+ void ReadMore(MojoResult result, const mojo::HandleSignalsState& state);
// Permanently closes the stream.
- void CloseStream(net::Error error, const base::Closure& callback);
+ void CloseStream(net::Error error);
// Internal net components.
- net::StreamSocket* const socket_;
+ mojo::ScopedDataPipeConsumerHandle stream_;
+ mojo::SimpleWatcher stream_watcher_;
+ uint32_t read_size_;
const scoped_refptr<net::IOBuffer> io_buffer_;
+ base::OnceClosure read_callback_;
// IOBuffer implementation that wraps the data within |io_buffer_| that hasn't
// been written to yet by Socket::Read calls.
const scoped_refptr<net::DrainableIOBuffer> read_buffer_;
@@ -131,19 +133,16 @@
DISALLOW_COPY_AND_ASSIGN(SocketInputStream);
};
-// A helper class for writing to a SocketStream with protobuf encoded data.
-// A SocketOutputStream does not take ownership of the socket itself, and it is
-// expected that the life of the output stream should match the life of the
-// socket itself (while the socket remains connected).
-// Typical usage:
+// A helper class for writing to a mojo producer handle with protobuf encoded
+// data. Typical usage:
// 1. Check the GetState() of the output stream before using it. If CLOSED, the
// output stream must be rebuilt (and the socket likely needs to be
// reconnected, as an error was encountered).
// 2. If EMPTY, the output stream can be written via a CodedOutputStream using
// the ZeroCopyOutputStream interface.
// 3. Once done writing, GetState() should be READY, so call Flush(..) to write
-// the buffer into the StreamSocket. Wait for the callback to be invoked
-// (it's invalid to write to an output stream while it's flushing).
+// the buffer into the mojo producer handle. Wait for the callback to be
+// invoked (it's invalid to write to an output stream while it's flushing).
// 4. Check the GetState() again to ensure the Flush was successful. GetState()
// should be EMPTY again.
// 5. Repeat.
@@ -161,10 +160,7 @@
CLOSED,
};
- // |socket| should already be connected.
- SocketOutputStream(
- net::StreamSocket* socket,
- const net::NetworkTrafficAnnotationTag& traffic_annotation);
+ explicit SocketOutputStream(mojo::ScopedDataPipeProducerHandle stream);
~SocketOutputStream() override;
// ZeroCopyOutputStream implementation.
@@ -173,20 +169,24 @@
int64_t ByteCount() const override;
// Writes the buffer into the Socket.
- net::Error Flush(const base::Closure& callback);
+ net::Error Flush(base::OnceClosure callback);
// Returns the last fatal error encountered. Only valid if GetState() ==
- // CLOSED.
+ // CLOSED. Note that All network read errors will be reported as
+ // net::ERR_FAILED, because mojo data pipe doesn't allow surfacing a more
+ // specific error code.
net::Error last_error() const;
// Returns the current state.
State GetState() const;
private:
- void FlushCompletionCallback(const base::Closure& callback, int result);
+ void WriteMore(MojoResult result, const mojo::HandleSignalsState& state);
// Internal net components.
- net::StreamSocket* const socket_;
+ mojo::ScopedDataPipeProducerHandle stream_;
+ mojo::SimpleWatcher stream_watcher_;
+ base::OnceClosure write_callback_;
const scoped_refptr<net::IOBufferWithSize> io_buffer_;
// IOBuffer implementation that wraps the data within |io_buffer_| that hasn't
// been written to the socket yet.
@@ -201,11 +201,6 @@
// Note: last_error_ == net::ERR_IO_PENDING implies GetState() == FLUSHING.
net::Error last_error_;
- // Network traffic annotation for downstream socket write. SocketOutputStream
- // is not reused, hence annotation can be added in constructor and used in all
- // subsequent writes.
- const net::NetworkTrafficAnnotationTag traffic_annotation_;
-
base::WeakPtrFactory<SocketOutputStream> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(SocketOutputStream);
diff --git a/google_apis/gcm/base/socket_stream_unittest.cc b/google_apis/gcm/base/socket_stream_unittest.cc
index 7da26d1..b386443 100644
--- a/google_apis/gcm/base/socket_stream_unittest.cc
+++ b/google_apis/gcm/base/socket_stream_unittest.cc
@@ -16,10 +16,16 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/string_piece.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/scoped_task_environment.h"
#include "net/base/ip_address.h"
#include "net/log/net_log_source.h"
#include "net/socket/socket_test_util.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "net/url_request/url_request_test_util.h"
+#include "services/network/network_context.h"
+#include "services/network/network_service.h"
+#include "services/network/public/mojom/proxy_resolving_socket.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace gcm {
@@ -35,77 +41,6 @@
const char kWriteData[] = "write_data";
const int kWriteDataSize = arraysize(kWriteData) - 1;
-// A net::StreamSocket that returns a partial write only for the first time.
-class FirstWritePartialSocket : public net::StreamSocket {
- public:
- FirstWritePartialSocket() {}
- ~FirstWritePartialSocket() override {}
-
- // Returns the data that is actually written to the socket.
- const std::string& actual_data_written() { return actual_data_written_; }
-
- // net::Socket implementation.
- int Write(
- net::IOBuffer* buf,
- int buf_len,
- net::CompletionOnceCallback callback,
- const net::NetworkTrafficAnnotationTag& traffic_annotation) override {
- // Make the first write as a partial write.
- if (!write_invoked_) {
- write_invoked_ = true;
- actual_data_written_.append(buf->data(), buf_len / 2);
- return buf_len / 2;
- }
- // For subsequent writes, write everything that caller has passed to us.
- actual_data_written_.append(buf->data(), buf_len);
- return buf_len;
- }
- int Read(net::IOBuffer* buf,
- int buf_len,
- net::CompletionOnceCallback callback) override {
- return net::ERR_IO_PENDING;
- }
- int ReadIfReady(net::IOBuffer* buf,
- int buf_len,
- net::CompletionOnceCallback callback) override {
- return net::ERR_IO_PENDING;
- }
- int CancelReadIfReady() override { return net::OK; }
- int SetReceiveBufferSize(int32_t size) override { return net::OK; }
- int SetSendBufferSize(int32_t size) override { return net::OK; }
-
- // net::StreamSocket implementation.
- int Connect(net::CompletionOnceCallback callback) override { return net::OK; }
- void Disconnect() override {}
- bool IsConnected() const override { return true; }
- bool IsConnectedAndIdle() const override { return true; };
- int GetPeerAddress(net::IPEndPoint* address) const override {
- return net::OK;
- }
- int GetLocalAddress(net::IPEndPoint* address) const override {
- return net::OK;
- }
- const net::NetLogWithSource& NetLog() const override { return net_log_; }
- bool WasEverUsed() const override { return true; }
- bool WasAlpnNegotiated() const override { return false; }
- net::NextProto GetNegotiatedProtocol() const override {
- return net::kProtoUnknown;
- }
- bool GetSSLInfo(net::SSLInfo* ssl_info) override { return false; }
- void GetConnectionAttempts(net::ConnectionAttempts* out) const override {}
- void ClearConnectionAttempts() override {}
- void AddConnectionAttempts(const net::ConnectionAttempts& attempts) override {
- }
- int64_t GetTotalReceivedBytes() const override { return 0; }
- void ApplySocketTag(const net::SocketTag& tag) override {}
-
- private:
- net::NetLogWithSource net_log_;
- std::string actual_data_written_;
- // Whether Write() has been invoked before.
- bool write_invoked_ = false;
-};
-
class GCMSocketStreamTest : public testing::Test {
public:
GCMSocketStreamTest();
@@ -119,19 +54,21 @@
// Simulates a google::protobuf::io::CodedInputStream read.
base::StringPiece DoInputStreamRead(int bytes);
+
// Simulates a google::protobuf::io::CodedOutputStream write.
int DoOutputStreamWrite(const base::StringPiece& write_src);
+ // Simulates a google::protobuf::io::CodedOutputStream write, but do not call
+ // flush.
+ int DoOutputStreamWriteWithoutFlush(const base::StringPiece& write_src);
+
// Synchronous Refresh wrapper.
void WaitForData(int msg_size);
- base::MessageLoop* message_loop() { return &message_loop_; };
- net::StaticSocketDataProvider* data_provider() {
- return data_provider_.get();
- }
SocketInputStream* input_stream() { return socket_input_stream_.get(); }
SocketOutputStream* output_stream() { return socket_output_stream_.get(); }
- net::StreamSocket* socket() { return socket_.get(); }
+
+ network::mojom::ProxyResolvingSocketPtr mojo_socket_ptr_;
void set_socket_output_stream(std::unique_ptr<SocketOutputStream> stream) {
socket_output_stream_ = std::move(stream);
@@ -142,26 +79,42 @@
void ResetInputStream();
void ResetOutputStream();
- void ConnectCallback(int result);
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
// SocketStreams and their data providers.
ReadList mock_reads_;
WriteList mock_writes_;
std::unique_ptr<net::StaticSocketDataProvider> data_provider_;
+ std::unique_ptr<net::SSLSocketDataProvider> ssl_data_provider_;
std::unique_ptr<SocketInputStream> socket_input_stream_;
std::unique_ptr<SocketOutputStream> socket_output_stream_;
// net:: components.
- std::unique_ptr<net::StreamSocket> socket_;
- net::MockClientSocketFactory socket_factory_;
net::AddressList address_list_;
-
- base::MessageLoopForIO message_loop_;
+ std::unique_ptr<network::NetworkService> network_service_;
+ network::mojom::NetworkContextPtr network_context_ptr_;
+ net::MockClientSocketFactory socket_factory_;
+ net::TestURLRequestContext url_request_context_;
+ std::unique_ptr<network::NetworkContext> network_context_;
+ network::mojom::ProxyResolvingSocketFactoryPtr mojo_socket_factory_ptr_;
+ mojo::ScopedDataPipeConsumerHandle receive_pipe_handle_;
+ mojo::ScopedDataPipeProducerHandle send_pipe_handle_;
};
-GCMSocketStreamTest::GCMSocketStreamTest() {
+GCMSocketStreamTest::GCMSocketStreamTest()
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::IO),
+ network_service_(network::NetworkService::CreateForTesting()),
+ url_request_context_(true /* delay_initialization */) {
address_list_ = net::AddressList::CreateFromIPAddress(
net::IPAddress::IPv4Localhost(), 5228);
+ socket_factory_.set_enable_read_if_ready(true);
+ url_request_context_.set_client_socket_factory(&socket_factory_);
+ url_request_context_.Init();
+
+ network_context_ = std::make_unique<network::NetworkContext>(
+ network_service_.get(), mojo::MakeRequest(&network_context_ptr_),
+ &url_request_context_);
}
GCMSocketStreamTest::~GCMSocketStreamTest() {}
@@ -170,9 +123,12 @@
const WriteList& write_list) {
mock_reads_ = read_list;
mock_writes_ = write_list;
- data_provider_.reset(
- new net::StaticSocketDataProvider(mock_reads_, mock_writes_));
+ data_provider_ = std::make_unique<net::StaticSocketDataProvider>(
+ mock_reads_, mock_writes_);
+ ssl_data_provider_ =
+ std::make_unique<net::SSLSocketDataProvider>(net::SYNCHRONOUS, net::OK);
socket_factory_.AddSocketDataProvider(data_provider_.get());
+ socket_factory_.AddSSLSocketDataProvider(ssl_data_provider_.get());
OpenConnection();
ResetInputStream();
ResetOutputStream();
@@ -214,11 +170,23 @@
int GCMSocketStreamTest::DoOutputStreamWrite(
const base::StringPiece& write_src) {
+ int total_bytes_written = DoOutputStreamWriteWithoutFlush(write_src);
+ base::RunLoop run_loop;
+ if (socket_output_stream_->Flush(run_loop.QuitClosure()) ==
+ net::ERR_IO_PENDING) {
+ run_loop.Run();
+ }
+
+ return total_bytes_written;
+}
+
+int GCMSocketStreamTest::DoOutputStreamWriteWithoutFlush(
+ const base::StringPiece& write_src) {
DCHECK_EQ(socket_output_stream_->GetState(), SocketOutputStream::EMPTY);
int total_bytes_written = 0;
- void* buffer = NULL;
+ void* buffer = nullptr;
int size = 0;
- int bytes = write_src.size();
+ const int bytes = write_src.size();
do {
if (!socket_output_stream_->Next(&buffer, &size))
@@ -232,12 +200,6 @@
total_bytes_written += bytes_to_write;
} while (total_bytes_written < bytes);
- base::RunLoop run_loop;
- if (socket_output_stream_->Flush(run_loop.QuitClosure()) ==
- net::ERR_IO_PENDING) {
- run_loop.Run();
- }
-
return total_bytes_written;
}
@@ -255,33 +217,49 @@
}
void GCMSocketStreamTest::OpenConnection() {
- socket_ = socket_factory_.CreateTransportClientSocket(
- address_list_, NULL, NULL, net::NetLogSource());
- socket_->Connect(
- base::Bind(&GCMSocketStreamTest::ConnectCallback,
- base::Unretained(this)));
+ network_context_->CreateProxyResolvingSocketFactory(
+ mojo::MakeRequest(&mojo_socket_factory_ptr_));
+ base::RunLoop run_loop;
+ int net_error = net::ERR_FAILED;
+ const GURL kDestination("https://example.com");
+ mojo_socket_factory_ptr_->CreateProxyResolvingSocket(
+ kDestination, true /* use_tls */,
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
+ mojo::MakeRequest(&mojo_socket_ptr_),
+ base::BindLambdaForTesting(
+ [&](int result, const base::Optional<net::IPEndPoint>& local_addr,
+ const base::Optional<net::IPEndPoint>& peer_addr,
+ mojo::ScopedDataPipeConsumerHandle receive_pipe_handle,
+ mojo::ScopedDataPipeProducerHandle send_pipe_handle) {
+ net_error = result;
+ receive_pipe_handle_ = std::move(receive_pipe_handle);
+ send_pipe_handle_ = std::move(send_pipe_handle);
+ run_loop.Quit();
+ }));
+ run_loop.Run();
+
PumpLoop();
}
-void GCMSocketStreamTest::ConnectCallback(int result) {}
-
void GCMSocketStreamTest::ResetInputStream() {
- DCHECK(socket_.get());
- socket_input_stream_.reset(new SocketInputStream(socket_.get()));
+ DCHECK(mojo_socket_ptr_);
+ socket_input_stream_ =
+ std::make_unique<SocketInputStream>(std::move(receive_pipe_handle_));
}
void GCMSocketStreamTest::ResetOutputStream() {
- DCHECK(socket_.get());
- socket_output_stream_.reset(
- new SocketOutputStream(socket_.get(), TRAFFIC_ANNOTATION_FOR_TESTS));
+ DCHECK(mojo_socket_ptr_);
+ socket_output_stream_ =
+ std::make_unique<SocketOutputStream>(std::move(send_pipe_handle_));
}
// A read where all data is already available.
TEST_F(GCMSocketStreamTest, ReadDataSync) {
- BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS,
- kReadData,
- kReadDataSize)),
- WriteList());
+ ReadList read_list;
+ read_list.push_back(
+ net::MockRead(net::SYNCHRONOUS, kReadData, kReadDataSize));
+ read_list.push_back(net::MockRead(net::ASYNC, net::OK) /* EOF */);
+ BuildSocket(read_list, WriteList());
WaitForData(kReadDataSize);
ASSERT_EQ(std::string(kReadData, kReadDataSize),
@@ -301,6 +279,9 @@
net::MockRead(net::SYNCHRONOUS,
&kReadData[first_read_len],
second_read_len));
+ // Add an EOF.
+ read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::OK));
+
BuildSocket(read_list, WriteList());
WaitForData(kReadDataSize);
@@ -317,6 +298,7 @@
net::MockRead(net::ASYNC, kReadData, first_read_len));
read_list.push_back(
net::MockRead(net::ASYNC, &kReadData[first_read_len], second_read_len));
+ read_list.push_back(net::MockRead(net::ASYNC, net::OK) /* EOF */);
BuildSocket(read_list, WriteList());
WaitForData(kReadDataSize);
ASSERT_EQ(std::string(kReadData, kReadDataSize),
@@ -327,10 +309,13 @@
TEST_F(GCMSocketStreamTest, TwoReadsAtOnce) {
std::string long_data = std::string(kReadData, kReadDataSize) +
std::string(kReadData2, kReadData2Size);
- BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS,
- long_data.c_str(),
- long_data.size())),
- WriteList());
+ ReadList read_list;
+ read_list.push_back(
+ net::MockRead(net::SYNCHRONOUS, long_data.c_str(), long_data.size()));
+ // Add an EOF.
+ read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::OK));
+
+ BuildSocket(read_list, WriteList());
WaitForData(kReadDataSize);
ASSERT_EQ(std::string(kReadData, kReadDataSize),
@@ -346,10 +331,14 @@
TEST_F(GCMSocketStreamTest, TwoReadsAtOnceWithRebuild) {
std::string long_data = std::string(kReadData, kReadDataSize) +
std::string(kReadData2, kReadData2Size);
- BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS,
- long_data.c_str(),
- long_data.size())),
- WriteList());
+ ReadList read_list;
+
+ read_list.push_back(
+ net::MockRead(net::SYNCHRONOUS, long_data.c_str(), long_data.size()));
+ // Add an EOF.
+ read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::OK));
+
+ BuildSocket(read_list, WriteList());
WaitForData(kReadDataSize);
ASSERT_EQ(std::string(kReadData, kReadDataSize),
@@ -369,23 +358,23 @@
WaitForData(kReadDataSize);
ASSERT_EQ(SocketInputStream::CLOSED, input_stream()->GetState());
- ASSERT_EQ(result, input_stream()->last_error());
+ ASSERT_EQ(net::ERR_FAILED, input_stream()->last_error());
}
// Simulate a read after the connection is closed.
TEST_F(GCMSocketStreamTest, ReadDisconnected) {
- BuildSocket(ReadList(), WriteList());
- socket()->Disconnect();
+ BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING)),
+ WriteList());
+ mojo_socket_ptr_.reset();
WaitForData(kReadDataSize);
ASSERT_EQ(SocketInputStream::CLOSED, input_stream()->GetState());
- ASSERT_EQ(net::ERR_CONNECTION_CLOSED, input_stream()->last_error());
+ ASSERT_EQ(net::ERR_FAILED, input_stream()->last_error());
}
// Write a full message in one go.
TEST_F(GCMSocketStreamTest, WriteFull) {
- BuildSocket(ReadList(),
- WriteList(1, net::MockWrite(net::SYNCHRONOUS,
- kWriteData,
+ BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING)),
+ WriteList(1, net::MockWrite(net::SYNCHRONOUS, kWriteData,
kWriteDataSize)));
ASSERT_EQ(kWriteDataSize,
DoOutputStreamWrite(base::StringPiece(kWriteData,
@@ -401,7 +390,8 @@
write_list.push_back(net::MockWrite(net::SYNCHRONOUS,
kWriteData + kWriteDataSize / 2,
kWriteDataSize / 2));
- BuildSocket(ReadList(), write_list);
+ BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING)),
+ write_list);
ASSERT_EQ(kWriteDataSize,
DoOutputStreamWrite(base::StringPiece(kWriteData,
kWriteDataSize)));
@@ -409,13 +399,75 @@
// Regression test for crbug.com/866635.
TEST_F(GCMSocketStreamTest, WritePartialWithLengthChecking) {
- auto socket = std::make_unique<FirstWritePartialSocket>();
- auto socket_output_stream = std::make_unique<SocketOutputStream>(
- socket.get(), TRAFFIC_ANNOTATION_FOR_TESTS);
+ // Add a prefix data in front of kWriteData.
+ std::string prefix_data("xxxxx");
+ const size_t kPrefixDataSize = 5;
+ // |pipe| has a capacity that is one byte smaller than |prefix_data.size()| +
+ // |kWriteDataSize|. This is so that the first write is a partial write
+ // of |prefix_data|, and the second write is a complete write of kWriteData.
+ // The 1 byte shortage is to simulate the partial write.
+ mojo::DataPipe pipe(kWriteDataSize + prefix_data.size() - 1 /* size */);
+ mojo::ScopedDataPipeConsumerHandle consumer_handle =
+ std::move(pipe.consumer_handle);
+ mojo::ScopedDataPipeProducerHandle producer_handle =
+ std::move(pipe.producer_handle);
+
+ // Prepopulate |producer_handle| of |prefix_data|, now the pipe's capacity is
+ // less than |kWriteDataSize|.
+ uint32_t num_bytes = prefix_data.size();
+ MojoResult r = producer_handle->WriteData(prefix_data.data(), &num_bytes,
+ MOJO_WRITE_DATA_FLAG_NONE);
+ ASSERT_EQ(MOJO_RESULT_OK, r);
+ ASSERT_EQ(prefix_data.size(), num_bytes);
+
+ // Create a SocketOutputStream from the producer pipe.
+ auto socket_output_stream =
+ std::make_unique<SocketOutputStream>(std::move(producer_handle));
set_socket_output_stream(std::move(socket_output_stream));
- ASSERT_EQ(kWriteDataSize,
- DoOutputStreamWrite(base::StringPiece(kWriteData, kWriteDataSize)));
- EXPECT_EQ(kWriteData, socket->actual_data_written());
+
+ // Write but do not flush.
+ EXPECT_EQ(kWriteDataSize, DoOutputStreamWriteWithoutFlush(kWriteData));
+
+ base::RunLoop run_loop;
+ output_stream()->Flush(run_loop.QuitClosure());
+ // Flush should be able to flush exactly 5 bytes, because of the data pipe
+ // capacity.
+ base::RunLoop().RunUntilIdle();
+
+ std::string contents;
+ // Read prefix.
+ char buffer[kPrefixDataSize];
+ uint32_t read_size = sizeof(buffer);
+ ASSERT_EQ(MOJO_RESULT_OK, consumer_handle->ReadData(
+ buffer, &read_size, MOJO_READ_DATA_FLAG_NONE));
+ ASSERT_EQ(kPrefixDataSize, read_size);
+ contents += std::string(buffer, read_size);
+
+ base::RunLoop().RunUntilIdle();
+ // Flush now should complete.
+ run_loop.Run();
+
+ // Closes |producer_handle|.
+ set_socket_output_stream(nullptr);
+
+ // Read everything in |consumer_handle| now that |producer_handle| is closed
+ // to make sure data is as what we expected, and there is no trailing garbage
+ // data.
+ while (true) {
+ char buffer[5];
+ uint32_t read_size = sizeof(buffer);
+ MojoResult r =
+ consumer_handle->ReadData(buffer, &read_size, MOJO_READ_DATA_FLAG_NONE);
+ if (r == MOJO_RESULT_SHOULD_WAIT)
+ continue;
+ if (r != MOJO_RESULT_OK)
+ break;
+ ASSERT_EQ(MOJO_RESULT_OK, r);
+ contents += std::string(buffer, read_size);
+ }
+ std::string expected(prefix_data);
+ expected.append(kWriteData);
+ EXPECT_EQ(expected, contents);
}
// Write a message completely asynchronously (returns IO_PENDING before
@@ -428,7 +480,8 @@
write_list.push_back(net::MockWrite(net::SYNCHRONOUS,
kWriteData + kWriteDataSize / 2,
kWriteDataSize / 2));
- BuildSocket(ReadList(), write_list);
+ BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING)),
+ write_list);
ASSERT_EQ(kWriteDataSize,
DoOutputStreamWrite(base::StringPiece(kWriteData,
kWriteDataSize)));
@@ -436,11 +489,14 @@
// Write a message then read a message.
TEST_F(GCMSocketStreamTest, WriteThenRead) {
- BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS,
- kReadData,
- kReadDataSize)),
- WriteList(1, net::MockWrite(net::SYNCHRONOUS,
- kWriteData,
+ ReadList read_list;
+ read_list.push_back(
+ net::MockRead(net::SYNCHRONOUS, kReadData, kReadDataSize));
+ // Add an EOF.
+ read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::OK));
+
+ BuildSocket(read_list,
+ WriteList(1, net::MockWrite(net::SYNCHRONOUS, kWriteData,
kWriteDataSize)));
ASSERT_EQ(kWriteDataSize,
@@ -454,11 +510,14 @@
// Read a message then write a message.
TEST_F(GCMSocketStreamTest, ReadThenWrite) {
- BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS,
- kReadData,
- kReadDataSize)),
- WriteList(1, net::MockWrite(net::SYNCHRONOUS,
- kWriteData,
+ ReadList read_list;
+ read_list.push_back(
+ net::MockRead(net::SYNCHRONOUS, kReadData, kReadDataSize));
+ // Add an EOF.
+ read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::OK));
+
+ BuildSocket(read_list,
+ WriteList(1, net::MockWrite(net::SYNCHRONOUS, kWriteData,
kWriteDataSize)));
WaitForData(kReadDataSize);
@@ -473,20 +532,25 @@
// Simulate a write that gets aborted.
TEST_F(GCMSocketStreamTest, WriteError) {
int result = net::ERR_ABORTED;
- BuildSocket(ReadList(),
+ BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING)),
WriteList(1, net::MockWrite(net::SYNCHRONOUS, result)));
- DoOutputStreamWrite(base::StringPiece(kWriteData, kWriteDataSize));
+ // Mojo data pipe buffers data, so there is a delay before write error is
+ // observed.Continue writing if error is not observed.
+ while (output_stream()->GetState() != SocketOutputStream::CLOSED) {
+ DoOutputStreamWrite(base::StringPiece(kWriteData, kWriteDataSize));
+ }
ASSERT_EQ(SocketOutputStream::CLOSED, output_stream()->GetState());
- ASSERT_EQ(result, output_stream()->last_error());
+ ASSERT_EQ(net::ERR_FAILED, output_stream()->last_error());
}
// Simulate a write after the connection is closed.
TEST_F(GCMSocketStreamTest, WriteDisconnected) {
- BuildSocket(ReadList(), WriteList());
- socket()->Disconnect();
+ BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING)),
+ WriteList());
+ mojo_socket_ptr_.reset();
DoOutputStreamWrite(base::StringPiece(kWriteData, kWriteDataSize));
ASSERT_EQ(SocketOutputStream::CLOSED, output_stream()->GetState());
- ASSERT_EQ(net::ERR_CONNECTION_CLOSED, output_stream()->last_error());
+ ASSERT_EQ(net::ERR_FAILED, output_stream()->last_error());
}
} // namespace
diff --git a/google_apis/gcm/engine/connection_factory.h b/google_apis/gcm/engine/connection_factory.h
index c837814..fad6843 100644
--- a/google_apis/gcm/engine/connection_factory.h
+++ b/google_apis/gcm/engine/connection_factory.h
@@ -7,9 +7,11 @@
#include <string>
+#include "base/callback_forward.h"
#include "base/time/time.h"
#include "google_apis/gcm/base/gcm_export.h"
#include "google_apis/gcm/engine/connection_handler.h"
+#include "services/network/public/mojom/proxy_resolving_socket.mojom.h"
class GURL;
@@ -23,6 +25,9 @@
namespace gcm {
+using GetProxyResolvingFactoryCallback = base::RepeatingCallback<void(
+ network::mojom::ProxyResolvingSocketFactoryRequest)>;
+
// Factory for creating a ConnectionHandler and maintaining its connection.
// The factory retains ownership of the ConnectionHandler and will enforce
// backoff policies when attempting connections.
diff --git a/google_apis/gcm/engine/connection_factory_impl.cc b/google_apis/gcm/engine/connection_factory_impl.cc
index cde535e5..8ebea56e 100644
--- a/google_apis/gcm/engine/connection_factory_impl.cc
+++ b/google_apis/gcm/engine/connection_factory_impl.cc
@@ -23,8 +23,7 @@
#include "net/socket/client_socket_handle.h"
#include "net/socket/client_socket_pool_manager.h"
#include "net/ssl/ssl_config_service.h"
-#include "services/network/proxy_resolving_client_socket.h"
-#include "services/network/proxy_resolving_client_socket_factory.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
namespace gcm {
@@ -52,15 +51,13 @@
ConnectionFactoryImpl::ConnectionFactoryImpl(
const std::vector<GURL>& mcs_endpoints,
const net::BackoffEntry::Policy& backoff_policy,
- net::URLRequestContext* url_request_context,
+ GetProxyResolvingFactoryCallback get_socket_factory_callback,
GCMStatsRecorder* recorder)
: mcs_endpoints_(mcs_endpoints),
next_endpoint_(0),
last_successful_endpoint_(0),
backoff_policy_(backoff_policy),
- socket_factory_(
- std::make_unique<network::ProxyResolvingClientSocketFactory>(
- url_request_context)),
+ get_socket_factory_callback_(get_socket_factory_callback),
connecting_(false),
waiting_for_backoff_(false),
waiting_for_network_online_(false),
@@ -288,18 +285,6 @@
return mcs_endpoints_[next_endpoint_];
}
-net::IPEndPoint ConnectionFactoryImpl::GetPeerIP() {
- if (!socket_)
- return net::IPEndPoint();
-
- net::IPEndPoint ip_endpoint;
- int result = socket_->GetPeerAddress(&ip_endpoint);
- if (result != net::OK)
- return net::IPEndPoint();
-
- return ip_endpoint;
-}
-
void ConnectionFactoryImpl::ConnectImpl() {
event_tracker_.StartConnectionAttempt();
StartConnection();
@@ -316,21 +301,8 @@
connecting_ = true;
GURL current_endpoint = GetCurrentEndpoint();
recorder_->RecordConnectionInitiated(current_endpoint.host());
- socket_ = socket_factory_->CreateSocket(current_endpoint, true /*use_tls*/);
- int status = socket_->Connect(base::BindRepeating(
- &ConnectionFactoryImpl::OnConnectDone, weak_ptr_factory_.GetWeakPtr()));
- if (status != net::ERR_IO_PENDING)
- OnConnectDone(status);
-}
-void ConnectionFactoryImpl::InitHandler() {
- // May be null in tests.
- mcs_proto::LoginRequest login_request;
- if (!request_builder_.is_null()) {
- request_builder_.Run(&login_request);
- DCHECK(login_request.IsInitialized());
- event_tracker_.WriteToLoginRequest(&login_request);
- }
+ get_socket_factory_callback_.Run(mojo::MakeRequest(&socket_factory_));
net::NetworkTrafficAnnotationTag traffic_annotation =
net::DefineNetworkTrafficAnnotation("gcm_connection_factory", R"(
@@ -368,7 +340,27 @@
"but does not have any effect on other Google Cloud messages."
)");
- connection_handler_->Init(login_request, traffic_annotation, socket_.get());
+ socket_factory_->CreateProxyResolvingSocket(
+ current_endpoint, true /* use_tls */,
+ net::MutableNetworkTrafficAnnotationTag(traffic_annotation),
+ mojo::MakeRequest(&socket_),
+ base::BindOnce(&ConnectionFactoryImpl::OnConnectDone,
+ base::Unretained(this)));
+}
+
+void ConnectionFactoryImpl::InitHandler(
+ mojo::ScopedDataPipeConsumerHandle receive_stream,
+ mojo::ScopedDataPipeProducerHandle send_stream) {
+ mcs_proto::LoginRequest login_request;
+ // May be null in tests.
+ if (!request_builder_.is_null()) {
+ request_builder_.Run(&login_request);
+ DCHECK(login_request.IsInitialized());
+ event_tracker_.WriteToLoginRequest(&login_request);
+ }
+
+ connection_handler_->Init(login_request, std::move(receive_stream),
+ std::move(send_stream));
}
std::unique_ptr<net::BackoffEntry> ConnectionFactoryImpl::CreateBackoffEntry(
@@ -390,8 +382,20 @@
return base::TimeTicks::Now();
}
-void ConnectionFactoryImpl::OnConnectDone(int result) {
+void ConnectionFactoryImpl::OnConnectDone(
+ int result,
+ const base::Optional<net::IPEndPoint>& local_addr,
+ const base::Optional<net::IPEndPoint>& peer_addr,
+ mojo::ScopedDataPipeConsumerHandle receive_stream,
+ mojo::ScopedDataPipeProducerHandle send_stream) {
DCHECK_NE(net::ERR_IO_PENDING, result);
+ if (!connection_handler_) {
+ // If CloseSocket() is called while a connect is pending, this callback will
+ // be called with net::ERR_ABORTED. Checking |connection_handler_| serves as
+ // a proxy to checking whether CloseSocket() is called.
+ DCHECK_EQ(net::ERR_ABORTED, result);
+ return;
+ }
if (result != net::OK) {
LOG(ERROR) << "Failed to connect to MCS endpoint with error " << result;
UMA_HISTOGRAM_BOOLEAN("GCM.ConnectionSuccessRate", false);
@@ -426,7 +430,11 @@
connecting_ = false;
handshake_in_progress_ = true;
DVLOG(1) << "MCS endpoint socket connection success, starting login.";
- InitHandler();
+ // |peer_addr| is only non-null if result == net::OK and the connection is not
+ // through a proxy.
+ if (peer_addr)
+ peer_addr_ = peer_addr.value();
+ InitHandler(std::move(receive_stream), std::move(send_stream));
}
void ConnectionFactoryImpl::ConnectionHandlerCallback(int result) {
@@ -451,7 +459,7 @@
event_tracker_.ConnectionAttemptSucceeded();
if (listener_)
- listener_->OnConnected(GetCurrentEndpoint(), GetPeerIP());
+ listener_->OnConnected(GetCurrentEndpoint(), peer_addr_);
}
void ConnectionFactoryImpl::CloseSocket() {
@@ -460,9 +468,8 @@
if (connection_handler_)
connection_handler_->Reset();
- if (socket_)
- socket_->Disconnect();
- socket_ = nullptr;
+ socket_.reset();
+ peer_addr_ = net::IPEndPoint();
}
} // namespace gcm
diff --git a/google_apis/gcm/engine/connection_factory_impl.h b/google_apis/gcm/engine/connection_factory_impl.h
index 67c5412..4bd944c 100644
--- a/google_apis/gcm/engine/connection_factory_impl.h
+++ b/google_apis/gcm/engine/connection_factory_impl.h
@@ -9,26 +9,20 @@
#include <stddef.h>
+#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "google_apis/gcm/engine/connection_event_tracker.h"
#include "google_apis/gcm/engine/connection_handler.h"
#include "google_apis/gcm/protocol/mcs.pb.h"
+#include "mojo/public/cpp/system/data_pipe.h"
#include "net/base/backoff_entry.h"
#include "net/base/network_change_notifier.h"
#include "net/log/net_log_with_source.h"
+#include "services/network/public/mojom/proxy_resolving_socket.mojom.h"
#include "url/gurl.h"
-namespace network {
-class ProxyResolvingClientSocket;
-class ProxyResolvingClientSocketFactory;
-}
-
-namespace net {
-class URLRequestContext;
-}
-
namespace gcm {
class GCMStatsRecorder;
@@ -37,12 +31,12 @@
public ConnectionFactory,
public net::NetworkChangeNotifier::NetworkChangeObserver {
public:
- // The caller is responsible for making sure the ConnectionFactoryImpl is
- // destroyed before the |url_request_context|.
- ConnectionFactoryImpl(const std::vector<GURL>& mcs_endpoints,
- const net::BackoffEntry::Policy& backoff_policy,
- net::URLRequestContext* url_request_context,
- GCMStatsRecorder* recorder);
+ ConnectionFactoryImpl(
+ const std::vector<GURL>& mcs_endpoints,
+ const net::BackoffEntry::Policy& backoff_policy,
+ GetProxyResolvingFactoryCallback get_socket_factory_callback,
+ // need task runner here.
+ GCMStatsRecorder* recorder);
~ConnectionFactoryImpl() override;
// ConnectionFactory implementation.
@@ -67,10 +61,6 @@
// attempt will be made.
GURL GetCurrentEndpoint() const;
- // Returns the IPEndpoint to which the factory is currently connected. If no
- // connection is active, returns an empty IPEndpoint.
- net::IPEndPoint GetPeerIP();
-
protected:
// Initiate the connection to the GCM server.
// Virtual for testing.
@@ -78,7 +68,8 @@
// Helper method for initalizing the connection hander.
// Virtual for testing.
- virtual void InitHandler();
+ virtual void InitHandler(mojo::ScopedDataPipeConsumerHandle receive_stream,
+ mojo::ScopedDataPipeProducerHandle send_stream);
// Helper method for creating a backoff entry.
// Virtual for testing.
@@ -97,8 +88,12 @@
// Virtual for testing.
virtual base::TimeTicks NowTicks();
- // Callback for Socket connection completion.
- void OnConnectDone(int result);
+ // Callback for Socket connection completion. This is public for testing.
+ void OnConnectDone(int result,
+ const base::Optional<net::IPEndPoint>& local_addr,
+ const base::Optional<net::IPEndPoint>& peer_addr,
+ mojo::ScopedDataPipeConsumerHandle receive_stream,
+ mojo::ScopedDataPipeProducerHandle send_stream);
// ConnectionHandler callback for connection issues.
void ConnectionHandlerCallback(int result);
@@ -138,11 +133,15 @@
// The backoff policy to use.
const net::BackoffEntry::Policy backoff_policy_;
- // ---- net:: components for establishing connections. ----
+ // ---- network:: components for establishing connections. ----
// Socket factory for creating new GCM connections.
- std::unique_ptr<network::ProxyResolvingClientSocketFactory> socket_factory_;
+ GetProxyResolvingFactoryCallback get_socket_factory_callback_;
+ network::mojom::ProxyResolvingSocketFactoryPtr socket_factory_;
// The handle to the socket for the current connection, if one exists.
- std::unique_ptr<network::ProxyResolvingClientSocket> socket_;
+ network::mojom::ProxyResolvingSocketPtr socket_;
+ // Peer address of |socket_|.
+ net::IPEndPoint peer_addr_;
+
// Current backoff entry.
std::unique_ptr<net::BackoffEntry> backoff_entry_;
// Backoff entry from previous connection attempt. Updated on each login
diff --git a/google_apis/gcm/engine/connection_factory_impl_unittest.cc b/google_apis/gcm/engine/connection_factory_impl_unittest.cc
index a707f908..8440d03 100644
--- a/google_apis/gcm/engine/connection_factory_impl_unittest.cc
+++ b/google_apis/gcm/engine/connection_factory_impl_unittest.cc
@@ -9,7 +9,9 @@
#include <utility>
#include "base/message_loop/message_loop.h"
+#include "base/optional.h"
#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/threading/thread_task_runner_handle.h"
#include "google_apis/gcm/base/mcs_util.h"
@@ -18,6 +20,9 @@
#include "net/base/backoff_entry.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/url_request_test_util.h"
+#include "services/network/network_context.h"
+#include "services/network/network_service.h"
+#include "services/network/public/mojom/proxy_resolving_socket.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
class Policy;
@@ -86,15 +91,17 @@
// backoff policy.
class TestConnectionFactoryImpl : public ConnectionFactoryImpl {
public:
- TestConnectionFactoryImpl(net::URLRequestContext* request_context,
- const base::Closure& finished_callback);
+ TestConnectionFactoryImpl(
+ GetProxyResolvingFactoryCallback get_socket_factory_callback,
+ const base::Closure& finished_callback);
~TestConnectionFactoryImpl() override;
void InitializeFactory();
// Overridden stubs.
void StartConnection() override;
- void InitHandler() override;
+ void InitHandler(mojo::ScopedDataPipeConsumerHandle receive_stream,
+ mojo::ScopedDataPipeProducerHandle send_stream) override;
std::unique_ptr<net::BackoffEntry> CreateBackoffEntry(
const net::BackoffEntry::Policy* const policy) override;
std::unique_ptr<ConnectionHandler> CreateConnectionHandler(
@@ -139,14 +146,17 @@
FakeConnectionHandler* fake_handler_;
// Dummy GCM Stats recorder.
FakeGCMStatsRecorder dummy_recorder_;
+ // Dummy mojo pipes.
+ mojo::DataPipe receive_pipe_;
+ mojo::DataPipe send_pipe_;
};
TestConnectionFactoryImpl::TestConnectionFactoryImpl(
- net::URLRequestContext* request_context,
+ GetProxyResolvingFactoryCallback get_socket_factory_callback,
const base::Closure& finished_callback)
: ConnectionFactoryImpl(BuildEndpoints(),
net::BackoffEntry::Policy(),
- request_context,
+ get_socket_factory_callback,
&dummy_recorder_),
connect_result_(net::ERR_UNEXPECTED),
num_expected_attempts_(0),
@@ -169,8 +179,12 @@
ASSERT_GT(num_expected_attempts_, 0);
ASSERT_FALSE(GetConnectionHandler()->CanSendMessage());
std::unique_ptr<mcs_proto::LoginRequest> request(BuildLoginRequest(0, 0, ""));
- GetConnectionHandler()->Init(*request, TRAFFIC_ANNOTATION_FOR_TESTS, NULL);
- OnConnectDone(connect_result_);
+ GetConnectionHandler()->Init(*request,
+ std::move(receive_pipe_.consumer_handle),
+ std::move(send_pipe_.producer_handle));
+ OnConnectDone(connect_result_, net::IPEndPoint(), net::IPEndPoint(),
+ mojo::ScopedDataPipeConsumerHandle(),
+ mojo::ScopedDataPipeProducerHandle());
if (!NextRetryAttempt().is_null()) {
// Advance the time to the next retry time.
base::TimeDelta time_till_retry =
@@ -185,7 +199,9 @@
}
}
-void TestConnectionFactoryImpl::InitHandler() {
+void TestConnectionFactoryImpl::InitHandler(
+ mojo::ScopedDataPipeConsumerHandle receive_stream,
+ mojo::ScopedDataPipeProducerHandle send_stream) {
EXPECT_NE(connect_result_, net::ERR_UNEXPECTED);
if (!delay_login_)
ConnectionHandlerCallback(net::OK);
@@ -272,31 +288,44 @@
}
private:
+ void GetProxyResolvingSocketFactory(
+ network::mojom::ProxyResolvingSocketFactoryRequest request) {
+ network_context_->CreateProxyResolvingSocketFactory(std::move(request));
+ }
void ConnectionsComplete();
- base::MessageLoop message_loop_;
-
- // Dummy request context that is not used to make network requests, and is
- // added to make ProxyResolvingClientSocketFactory to not DCHECK on a null
- // context.
- net::TestURLRequestContext request_context_;
-
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
TestConnectionFactoryImpl factory_;
std::unique_ptr<base::RunLoop> run_loop_;
GURL connected_server_;
+ std::unique_ptr<network::NetworkService> network_service_;
+ network::mojom::NetworkContextPtr network_context_ptr_;
+ std::unique_ptr<network::NetworkContext> network_context_;
};
ConnectionFactoryImplTest::ConnectionFactoryImplTest()
- : factory_(&request_context_,
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::IO),
+ factory_(base::BindRepeating(
+ &ConnectionFactoryImplTest::GetProxyResolvingSocketFactory,
+ base::Unretained(this)),
base::Bind(&ConnectionFactoryImplTest::ConnectionsComplete,
base::Unretained(this))),
- run_loop_(new base::RunLoop()) {
+ run_loop_(new base::RunLoop()),
+ network_service_(network::NetworkService::CreateForTesting()) {
+ network::mojom::NetworkContextParamsPtr params =
+ network::mojom::NetworkContextParams::New();
+ // Use a fixed proxy config, to avoid dependencies on local network
+ // configuration.
+ params->initial_proxy_config = net::ProxyConfigWithAnnotation::CreateDirect();
+ network_context_ = std::make_unique<network::NetworkContext>(
+ network_service_.get(), mojo::MakeRequest(&network_context_ptr_),
+ std::move(params));
factory()->SetConnectionListener(this);
- factory()->Initialize(
- ConnectionFactory::BuildLoginRequestCallback(),
- ConnectionHandler::ProtoReceivedCallback(),
- ConnectionHandler::ProtoSentCallback());
+ factory()->Initialize(ConnectionFactory::BuildLoginRequestCallback(),
+ ConnectionHandler::ProtoReceivedCallback(),
+ ConnectionHandler::ProtoSentCallback());
}
ConnectionFactoryImplTest::~ConnectionFactoryImplTest() {}
diff --git a/google_apis/gcm/engine/connection_handler.h b/google_apis/gcm/engine/connection_handler.h
index ee110c11..857e657 100644
--- a/google_apis/gcm/engine/connection_handler.h
+++ b/google_apis/gcm/engine/connection_handler.h
@@ -9,7 +9,7 @@
#include "base/callback.h"
#include "google_apis/gcm/base/gcm_export.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "mojo/public/cpp/system/data_pipe.h"
namespace net{
class StreamSocket;
@@ -48,8 +48,8 @@
// Note: It is correct and expected to call Init more than once, as connection
// issues are encountered and new connections must be made.
virtual void Init(const mcs_proto::LoginRequest& login_request,
- const net::NetworkTrafficAnnotationTag& traffic_annotation,
- net::StreamSocket* socket) = 0;
+ mojo::ScopedDataPipeConsumerHandle receive_stream,
+ mojo::ScopedDataPipeProducerHandle send_stream) = 0;
// Resets the handler and any internal state. Should be called any time
// a connection reset happens externally to the handler.
diff --git a/google_apis/gcm/engine/connection_handler_impl.cc b/google_apis/gcm/engine/connection_handler_impl.cc
index 887a4bea..f6812988 100644
--- a/google_apis/gcm/engine/connection_handler_impl.cc
+++ b/google_apis/gcm/engine/connection_handler_impl.cc
@@ -50,7 +50,6 @@
const ProtoSentCallback& write_callback,
const ConnectionChangedCallback& connection_callback)
: read_timeout_(read_timeout),
- socket_(NULL),
handshake_complete_(false),
message_tag_(0),
message_size_(0),
@@ -66,8 +65,8 @@
void ConnectionHandlerImpl::Init(
const mcs_proto::LoginRequest& login_request,
- const net::NetworkTrafficAnnotationTag& traffic_annotation,
- net::StreamSocket* socket) {
+ mojo::ScopedDataPipeConsumerHandle receive_stream,
+ mojo::ScopedDataPipeProducerHandle send_stream) {
DCHECK(!read_callback_.is_null());
DCHECK(!write_callback_.is_null());
DCHECK(!connection_callback_.is_null());
@@ -78,9 +77,8 @@
handshake_complete_ = false;
message_tag_ = 0;
message_size_ = 0;
- socket_ = socket;
- input_stream_.reset(new SocketInputStream(socket_));
- output_stream_.reset(new SocketOutputStream(socket_, traffic_annotation));
+ input_stream_.reset(new SocketInputStream(std::move(receive_stream)));
+ output_stream_.reset(new SocketOutputStream(std::move(send_stream)));
Login(login_request);
}
@@ -481,9 +479,6 @@
void ConnectionHandlerImpl::CloseConnection() {
DVLOG(1) << "Closing connection.";
read_timeout_timer_.Stop();
- if (socket_)
- socket_->Disconnect();
- socket_ = NULL;
handshake_complete_ = false;
message_tag_ = 0;
message_size_ = 0;
diff --git a/google_apis/gcm/engine/connection_handler_impl.h b/google_apis/gcm/engine/connection_handler_impl.h
index 5cd1749..e88749cc 100644
--- a/google_apis/gcm/engine/connection_handler_impl.h
+++ b/google_apis/gcm/engine/connection_handler_impl.h
@@ -43,8 +43,8 @@
// ConnectionHandler implementation.
void Init(const mcs_proto::LoginRequest& login_request,
- const net::NetworkTrafficAnnotationTag& traffic_annotation,
- net::StreamSocket* socket) override;
+ mojo::ScopedDataPipeConsumerHandle receive_stream,
+ mojo::ScopedDataPipeProducerHandle send_stream) override;
void Reset() override;
bool CanSendMessage() const override;
void SendMessage(const google::protobuf::MessageLite& message) override;
@@ -103,8 +103,7 @@
const base::TimeDelta read_timeout_;
base::OneShotTimer read_timeout_timer_;
- // This connection's socket and the input/output streams attached to it.
- net::StreamSocket* socket_;
+ // This connection's input/output streams.
std::unique_ptr<SocketInputStream> input_stream_;
std::unique_ptr<SocketOutputStream> output_stream_;
diff --git a/google_apis/gcm/engine/connection_handler_impl_unittest.cc b/google_apis/gcm/engine/connection_handler_impl_unittest.cc
index ff7393a..cde7645 100644
--- a/google_apis/gcm/engine/connection_handler_impl_unittest.cc
+++ b/google_apis/gcm/engine/connection_handler_impl_unittest.cc
@@ -14,6 +14,8 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/scoped_task_environment.h"
#include "base/test/test_timeouts.h"
#include "google/protobuf/io/coded_stream.h"
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
@@ -28,6 +30,10 @@
#include "net/socket/stream_socket.h"
#include "net/test/gtest_util.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "net/url_request/url_request_test_util.h"
+#include "services/network/network_context.h"
+#include "services/network/network_service.h"
+#include "services/network/public/mojom/proxy_resolving_socket.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace gcm {
@@ -147,19 +153,14 @@
GCMConnectionHandlerImplTest();
~GCMConnectionHandlerImplTest() override;
- net::StreamSocket* BuildSocket(const ReadList& read_list,
- const WriteList& write_list);
+ void BuildSocket(const ReadList& read_list, const WriteList& write_list);
- // Pump |message_loop_|, resetting |run_loop_| after completion.
+ // Pump |run_loop_|, and reset |run_loop_| after completion.
void PumpLoop();
ConnectionHandlerImpl* connection_handler() {
return connection_handler_.get();
}
- base::MessageLoop* message_loop() { return &message_loop_; }
- net::StaticSocketDataProvider* data_provider() {
- return data_provider_.get();
- }
int last_error() const { return last_error_; }
// Initialize the connection handler, setting |dst_proto| as the destination
@@ -169,15 +170,16 @@
// Runs the message loop until a message is received.
void WaitForMessage();
+ network::mojom::ProxyResolvingSocketPtr mojo_socket_ptr_;
+
private:
void ReadContinuation(ScopedMessage* dst_proto, ScopedMessage new_proto);
void WriteContinuation();
void ConnectionContinuation(int error);
// SocketStreams and their data provider.
- ReadList mock_reads_;
- WriteList mock_writes_;
- std::unique_ptr<net::StaticSocketDataProvider> data_provider_;
+ std::vector<std::unique_ptr<net::StaticSocketDataProvider>> data_providers_;
+ std::vector<std::unique_ptr<net::SSLSocketDataProvider>> ssl_data_providers_;
// The connection handler being tested.
std::unique_ptr<ConnectionHandlerImpl> connection_handler_;
@@ -185,45 +187,71 @@
// The last connection error received.
int last_error_;
- // net:: components.
- std::unique_ptr<net::StreamSocket> socket_;
- net::MockClientSocketFactory socket_factory_;
net::AddressList address_list_;
-
- base::MessageLoopForIO message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
std::unique_ptr<base::RunLoop> run_loop_;
+ std::unique_ptr<network::NetworkService> network_service_;
+ network::mojom::NetworkContextPtr network_context_ptr_;
+ net::MockClientSocketFactory socket_factory_;
+ net::TestURLRequestContext url_request_context_;
+ std::unique_ptr<network::NetworkContext> network_context_;
+ network::mojom::ProxyResolvingSocketFactoryPtr mojo_socket_factory_ptr_;
+ mojo::ScopedDataPipeConsumerHandle receive_pipe_handle_;
+ mojo::ScopedDataPipeProducerHandle send_pipe_handle_;
};
GCMConnectionHandlerImplTest::GCMConnectionHandlerImplTest()
- : last_error_(0) {
+ : last_error_(0),
+ scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::IO),
+ network_service_(network::NetworkService::CreateForTesting()),
+ url_request_context_(true /* delay_initialization */) {
address_list_ = net::AddressList::CreateFromIPAddress(
net::IPAddress::IPv4Localhost(), kMCSPort);
+ socket_factory_.set_enable_read_if_ready(true);
+ url_request_context_.set_client_socket_factory(&socket_factory_);
+ url_request_context_.Init();
+
+ network_context_ = std::make_unique<network::NetworkContext>(
+ network_service_.get(), mojo::MakeRequest(&network_context_ptr_),
+ &url_request_context_);
}
GCMConnectionHandlerImplTest::~GCMConnectionHandlerImplTest() {
}
-net::StreamSocket* GCMConnectionHandlerImplTest::BuildSocket(
- const ReadList& read_list,
- const WriteList& write_list) {
- mock_reads_ = read_list;
- mock_writes_ = write_list;
- data_provider_ = std::make_unique<net::StaticSocketDataProvider>(
- mock_reads_, mock_writes_);
- socket_factory_.AddSocketDataProvider(data_provider_.get());
+void GCMConnectionHandlerImplTest::BuildSocket(const ReadList& read_list,
+ const WriteList& write_list) {
+ data_providers_.push_back(
+ std::make_unique<net::StaticSocketDataProvider>(read_list, write_list));
+ socket_factory_.AddSocketDataProvider(data_providers_.back().get());
+ ssl_data_providers_.push_back(
+ std::make_unique<net::SSLSocketDataProvider>(net::SYNCHRONOUS, net::OK));
+ socket_factory_.AddSSLSocketDataProvider(ssl_data_providers_.back().get());
+
run_loop_ = std::make_unique<base::RunLoop>();
- socket_ = socket_factory_.CreateTransportClientSocket(
- address_list_, NULL, NULL, net::NetLogSource());
- net::TestCompletionCallback callback;
- int rv = socket_->Connect(callback.callback());
- EXPECT_THAT(rv, net::test::IsError(net::ERR_IO_PENDING));
-
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, net::test::IsOk());
-
- EXPECT_TRUE(socket_->IsConnected());
- return socket_.get();
+ network_context_->CreateProxyResolvingSocketFactory(
+ mojo::MakeRequest(&mojo_socket_factory_ptr_));
+ base::RunLoop run_loop;
+ int net_error = net::ERR_FAILED;
+ const GURL kDestination("https://example.com");
+ mojo_socket_factory_ptr_->CreateProxyResolvingSocket(
+ kDestination, true /* use_tls */,
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
+ mojo::MakeRequest(&mojo_socket_ptr_),
+ base::BindLambdaForTesting(
+ [&](int result, const base::Optional<net::IPEndPoint>& local_addr,
+ const base::Optional<net::IPEndPoint>& peer_addr,
+ mojo::ScopedDataPipeConsumerHandle receive_pipe_handle,
+ mojo::ScopedDataPipeProducerHandle send_pipe_handle) {
+ net_error = result;
+ receive_pipe_handle_ = std::move(receive_pipe_handle);
+ send_pipe_handle_ = std::move(send_pipe_handle);
+ run_loop.Quit();
+ }));
+ run_loop.Run();
+ ASSERT_EQ(net::OK, net_error);
}
void GCMConnectionHandlerImplTest::PumpLoop() {
@@ -243,7 +271,8 @@
base::Unretained(this)));
EXPECT_FALSE(connection_handler()->CanSendMessage());
connection_handler_->Init(*BuildLoginRequest(kAuthId, kAuthToken, ""),
- TRAFFIC_ANNOTATION_FOR_TESTS, socket_.get());
+ std::move(receive_pipe_handle_),
+ std::move(send_pipe_handle_));
}
void GCMConnectionHandlerImplTest::ReadContinuation(
@@ -277,9 +306,10 @@
handshake_request.c_str(),
handshake_request.size()));
std::string handshake_response = EncodeHandshakeResponse();
- ReadList read_list(1, net::MockRead(net::ASYNC,
- handshake_response.c_str(),
- handshake_response.size()));
+ ReadList read_list;
+ read_list.push_back(net::MockRead(net::ASYNC, handshake_response.c_str(),
+ handshake_response.size()));
+ read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::OK) /* EOF */);
BuildSocket(read_list, write_list);
ScopedMessage received_message;
@@ -302,9 +332,10 @@
std::string handshake_response = EncodeHandshakeResponse();
// Overwrite the version byte.
handshake_response[0] = 37;
- ReadList read_list(1, net::MockRead(net::ASYNC,
- handshake_response.c_str(),
- handshake_response.size()));
+ ReadList read_list;
+ read_list.push_back(net::MockRead(net::ASYNC, handshake_response.c_str(),
+ handshake_response.size()));
+ read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::OK) /* EOF */);
BuildSocket(read_list, write_list);
ScopedMessage received_message;
@@ -381,10 +412,13 @@
// Build a new socket and reconnect, successfully this time.
std::string handshake_response = EncodeHandshakeResponse();
- read_list[0] = net::MockRead(net::ASYNC,
- handshake_response.c_str(),
- handshake_response.size());
- BuildSocket(read_list, write_list);
+ WriteList write_list2(1, net::MockWrite(net::ASYNC, handshake_request.c_str(),
+ handshake_request.size()));
+ ReadList read_list2;
+ read_list2.push_back(net::MockRead(net::ASYNC, handshake_response.c_str(),
+ handshake_response.size()));
+ read_list2.push_back(net::MockRead(net::SYNCHRONOUS, net::OK) /* EOF */);
+ BuildSocket(read_list2, write_list2);
Connect(&received_message);
EXPECT_FALSE(connection_handler()->CanSendMessage());
WaitForMessage(); // The login send.
@@ -413,6 +447,7 @@
read_list.push_back(net::MockRead(net::ASYNC,
data_message_pkt.c_str(),
data_message_pkt.size()));
+ read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::OK) /* EOF */);
BuildSocket(read_list, write_list);
ScopedMessage received_message;
@@ -447,6 +482,7 @@
read_list.push_back(net::MockRead(net::SYNCHRONOUS,
data_message_pkt.c_str(),
data_message_pkt.size()));
+ read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::OK) /* EOF */);
BuildSocket(read_list, write_list);
ScopedMessage received_message;
@@ -483,6 +519,7 @@
read_list.push_back(net::MockRead(net::ASYNC,
data_message_pkt.c_str(),
data_message_pkt.size()));
+ read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::OK) /* EOF */);
BuildSocket(read_list, write_list);
ScopedMessage received_message;
@@ -522,6 +559,7 @@
bytes_in_first_message,
data_message_pkt.size() -
bytes_in_first_message));
+ read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::OK) /* EOF */);
BuildSocket(read_list, write_list);
ScopedMessage received_message;
@@ -557,6 +595,7 @@
read_list.push_back(net::MockRead(net::SYNCHRONOUS,
data_message_pkt.c_str(),
data_message_pkt.size()));
+ read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::OK) /* EOF */);
BuildSocket(read_list, write_list);
ScopedMessage received_message;
@@ -631,6 +670,7 @@
read_list.push_back(net::MockRead(net::ASYNC,
data_message_pkt.c_str(),
data_message_pkt.size()));
+ read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::OK) /* EOF */);
BuildSocket(read_list, write_list);
ScopedMessage received_message;
@@ -692,14 +732,14 @@
handshake_response.c_str(),
handshake_response.size()));
read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING));
- net::StreamSocket* socket = BuildSocket(read_list, write_list);
+ BuildSocket(read_list, write_list);
ScopedMessage received_message;
Connect(&received_message);
WaitForMessage(); // The login send.
WaitForMessage(); // The login response.
EXPECT_TRUE(connection_handler()->CanSendMessage());
- socket->Disconnect();
+ mojo_socket_ptr_.reset();
mcs_proto::DataMessageStanza data_message;
data_message.set_from(kDataMsgFrom);
data_message.set_category(kDataMsgCategory);
@@ -707,7 +747,7 @@
EXPECT_FALSE(connection_handler()->CanSendMessage());
WaitForMessage(); // The message send. Should result in an error
EXPECT_FALSE(connection_handler()->CanSendMessage());
- EXPECT_EQ(net::ERR_CONNECTION_CLOSED, last_error());
+ EXPECT_EQ(net::ERR_FAILED, last_error());
}
// Receive a message with a custom data packet that is larger than the
@@ -732,6 +772,7 @@
read_list.push_back(net::MockRead(net::ASYNC,
data_message_pkt.c_str(),
data_message_pkt.size()));
+ read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::OK) /* EOF */);
BuildSocket(read_list, write_list);
ScopedMessage received_message;
@@ -769,6 +810,7 @@
read_list.push_back(net::MockRead(net::SYNCHRONOUS,
data_message_pkt.c_str(),
data_message_pkt.size()));
+ read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::OK) /* EOF */);
BuildSocket(read_list, write_list);
ScopedMessage received_message;
@@ -805,6 +847,7 @@
read_list.push_back(net::MockRead(net::ASYNC,
invalid_message_pkt.c_str(),
invalid_message_pkt.size()));
+ read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::OK) /* EOF */);
BuildSocket(read_list, write_list);
ScopedMessage received_message;
@@ -842,6 +885,7 @@
read_list.push_back(net::MockRead(net::ASYNC,
data_message_pkt.c_str() + 2,
data_message_pkt.size() - 2));
+ read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::OK) /* EOF */);
BuildSocket(read_list, write_list);
ScopedMessage received_message;
@@ -870,6 +914,7 @@
handshake_response.size()));
read_list.push_back(net::MockRead(net::ASYNC, invalid_message_pkt.c_str(),
invalid_message_pkt.size()));
+ read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::OK) /* EOF */);
BuildSocket(read_list, write_list);
ScopedMessage received_message;
@@ -900,6 +945,7 @@
handshake_response.size()));
read_list.push_back(net::MockRead(net::ASYNC, invalid_message_pkt.c_str(),
invalid_message_pkt.size()));
+ read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::OK) /* EOF */);
BuildSocket(read_list, write_list);
ScopedMessage received_message;
diff --git a/google_apis/gcm/engine/fake_connection_factory.cc b/google_apis/gcm/engine/fake_connection_factory.cc
index 4631e573..ee6df98 100644
--- a/google_apis/gcm/engine/fake_connection_factory.cc
+++ b/google_apis/gcm/engine/fake_connection_factory.cc
@@ -6,6 +6,7 @@
#include "google_apis/gcm/engine/fake_connection_handler.h"
#include "google_apis/gcm/protocol/mcs.pb.h"
+#include "mojo/public/cpp/system/data_pipe.h"
#include "net/socket/stream_socket.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
@@ -36,7 +37,8 @@
void FakeConnectionFactory::Connect() {
mcs_proto::LoginRequest login_request;
request_builder_.Run(&login_request);
- connection_handler_->Init(login_request, TRAFFIC_ANNOTATION_FOR_TESTS, NULL);
+ connection_handler_->Init(login_request, mojo::ScopedDataPipeConsumerHandle(),
+ mojo::ScopedDataPipeProducerHandle());
}
bool FakeConnectionFactory::IsEndpointReachable() const {
diff --git a/google_apis/gcm/engine/fake_connection_handler.cc b/google_apis/gcm/engine/fake_connection_handler.cc
index 34da9b1..4797f11 100644
--- a/google_apis/gcm/engine/fake_connection_handler.cc
+++ b/google_apis/gcm/engine/fake_connection_handler.cc
@@ -44,8 +44,8 @@
void FakeConnectionHandler::Init(
const mcs_proto::LoginRequest& login_request,
- const net::NetworkTrafficAnnotationTag& traffic_annotation,
- net::StreamSocket* socket) {
+ mojo::ScopedDataPipeConsumerHandle receive_stream,
+ mojo::ScopedDataPipeProducerHandle send_stream) {
ASSERT_GE(expected_outgoing_messages_.size(), 1U);
EXPECT_EQ(expected_outgoing_messages_.front().SerializeAsString(),
login_request.SerializeAsString());
diff --git a/google_apis/gcm/engine/fake_connection_handler.h b/google_apis/gcm/engine/fake_connection_handler.h
index 9afee54..70afb649 100644
--- a/google_apis/gcm/engine/fake_connection_handler.h
+++ b/google_apis/gcm/engine/fake_connection_handler.h
@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "google_apis/gcm/base/mcs_message.h"
#include "google_apis/gcm/engine/connection_handler.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "mojo/public/cpp/system/data_pipe.h"
namespace gcm {
@@ -25,8 +25,8 @@
// ConnectionHandler implementation.
void Init(const mcs_proto::LoginRequest& login_request,
- const net::NetworkTrafficAnnotationTag& traffic_annotation,
- net::StreamSocket* socket) override;
+ mojo::ScopedDataPipeConsumerHandle receive_stream,
+ mojo::ScopedDataPipeProducerHandle send_stream) override;
void Reset() override;
bool CanSendMessage() const override;
void SendMessage(const google::protobuf::MessageLite& message) override;
diff --git a/google_apis/gcm/tools/mcs_probe.cc b/google_apis/gcm/tools/mcs_probe.cc
index 00f56eea..e98bc74 100644
--- a/google_apis/gcm/tools/mcs_probe.cc
+++ b/google_apis/gcm/tools/mcs_probe.cc
@@ -59,7 +59,7 @@
#include "services/network/network_context.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
-#include "services/network/public/mojom/network_context.mojom.h"
+#include "services/network/public/mojom/proxy_resolving_socket.mojom.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#if defined(OS_MACOSX)
@@ -220,6 +220,8 @@
uint64_t secret() const { return secret_; }
private:
+ void RequestProxyResolvingSocketFactory(
+ network::mojom::ProxyResolvingSocketFactoryRequest request);
void CheckIn();
void InitializeNetworkState();
@@ -321,7 +323,9 @@
connection_factory_ = std::make_unique<ConnectionFactoryImpl>(
endpoints, kDefaultBackoffPolicy,
- url_request_context_getter_->GetURLRequestContext(), &recorder_);
+ base::BindRepeating(&MCSProbe::RequestProxyResolvingSocketFactory,
+ base::Unretained(this)),
+ &recorder_);
gcm_store_ = std::make_unique<GCMStoreImpl>(
gcm_store_path_, file_thread_.task_runner(),
std::make_unique<FakeEncryptor>());
@@ -417,6 +421,12 @@
LOG(INFO) << "MCS error happened";
}
+void MCSProbe::RequestProxyResolvingSocketFactory(
+ network::mojom::ProxyResolvingSocketFactoryRequest request) {
+ return network_context_->CreateProxyResolvingSocketFactory(
+ std::move(request));
+}
+
void MCSProbe::CheckIn() {
LOG(INFO) << "Check-in request initiated.";
checkin_proto::ChromeBuildProto chrome_build_proto;
diff --git a/ios/chrome/browser/application_context_impl.cc b/ios/chrome/browser/application_context_impl.cc
index 049c7c67..b7db100 100644
--- a/ios/chrome/browser/application_context_impl.cc
+++ b/ios/chrome/browser/application_context_impl.cc
@@ -57,6 +57,30 @@
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+namespace {
+
+// Requests a network::mojom::ProxyResolvingSocketFactory on the UI thread.
+// Note that this cannot be called on a thread that is not the UI thread.
+void RequestProxyResolvingSocketFactoryOnUIThread(
+ ApplicationContextImpl* app_context,
+ network::mojom::ProxyResolvingSocketFactoryRequest request) {
+ network::mojom::NetworkContext* network_context =
+ app_context->GetSystemNetworkContext();
+ network_context->CreateProxyResolvingSocketFactory(std::move(request));
+}
+
+// Wrapper on top of the method above. This does a PostTask to the UI thread.
+void RequestProxyResolvingSocketFactory(
+ ApplicationContextImpl* app_context,
+ network::mojom::ProxyResolvingSocketFactoryRequest request) {
+ web::WebThread::GetTaskRunnerForThread(web::WebThread::UI)
+ ->PostTask(FROM_HERE,
+ base::BindOnce(&RequestProxyResolvingSocketFactoryOnUIThread,
+ app_context, std::move(request)));
+}
+
+} // namespace
+
ApplicationContextImpl::ApplicationContextImpl(
base::SequencedTaskRunner* local_state_task_runner,
const base::CommandLine& command_line,
@@ -372,7 +396,11 @@
gcm_driver_ = gcm::CreateGCMDriverDesktop(
base::WrapUnique(new gcm::GCMClientFactory), GetLocalState(), store_path,
- GetSystemURLRequestContext(), GetSharedURLLoaderFactory(), ::GetChannel(),
+ // Because ApplicationContextImpl is destroyed after all WebThreads have
+ // been shut down, base::Unretained() is safe here.
+ base::BindRepeating(&RequestProxyResolvingSocketFactory,
+ base::Unretained(this)),
+ GetSharedURLLoaderFactory(), ::GetChannel(),
IOSChromeGCMProfileServiceFactory::GetProductCategoryForSubtypes(),
web::WebThread::GetTaskRunnerForThread(web::WebThread::UI),
web::WebThread::GetTaskRunnerForThread(web::WebThread::IO),
diff --git a/ios/chrome/browser/gcm/ios_chrome_gcm_profile_service_factory.cc b/ios/chrome/browser/gcm/ios_chrome_gcm_profile_service_factory.cc
index cf463c1..f9e8152 100644
--- a/ios/chrome/browser/gcm/ios_chrome_gcm_profile_service_factory.cc
+++ b/ios/chrome/browser/gcm/ios_chrome_gcm_profile_service_factory.cc
@@ -18,6 +18,35 @@
#include "ios/chrome/common/channel_info.h"
#include "ios/web/public/web_thread.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/mojom/proxy_resolving_socket.mojom.h"
+
+namespace {
+
+// Requests a ProxyResolvingSocketFactoryPtr on the UI thread. Note that a
+// WeakPtr of GCMProfileService is needed to detect when the KeyedService shuts
+// down, and avoid calling into |profile| which might have also been destroyed.
+void RequestProxyResolvingSocketFactoryOnUIThread(
+ web::BrowserState* context,
+ base::WeakPtr<gcm::GCMProfileService> service,
+ network::mojom::ProxyResolvingSocketFactoryRequest request) {
+ if (!service)
+ return;
+ context->GetProxyResolvingSocketFactory(std::move(request));
+}
+
+// A thread-safe wrapper to request a ProxyResolvingSocketFactoryPtr.
+void RequestProxyResolvingSocketFactory(
+ web::BrowserState* context,
+ base::WeakPtr<gcm::GCMProfileService> service,
+ network::mojom::ProxyResolvingSocketFactoryRequest request) {
+ web::WebThread::GetTaskRunnerForThread(web::WebThread::UI)
+ ->PostTask(
+ FROM_HERE,
+ base::BindOnce(&RequestProxyResolvingSocketFactoryOnUIThread, context,
+ std::move(service), std::move(request)));
+}
+
+} // namespace
// static
gcm::GCMProfileService* IOSChromeGCMProfileServiceFactory::GetForBrowserState(
@@ -64,6 +93,7 @@
return std::make_unique<gcm::GCMProfileService>(
browser_state->GetPrefs(), browser_state->GetStatePath(),
browser_state->GetRequestContext(),
+ base::BindRepeating(&RequestProxyResolvingSocketFactory, context),
browser_state->GetSharedURLLoaderFactory(), ::GetChannel(),
GetProductCategoryForSubtypes(),
IdentityManagerFactory::GetForBrowserState(browser_state),
diff --git a/ios/web/browser_state.mm b/ios/web/browser_state.mm
index 58d35374..bc97df0c 100644
--- a/ios/web/browser_state.mm
+++ b/ios/web/browser_state.mm
@@ -168,13 +168,7 @@
network::mojom::URLLoaderFactory* BrowserState::GetURLLoaderFactory() {
if (!url_loader_factory_) {
- DCHECK(!network_context_);
- DCHECK(!network_context_owner_);
-
- net::URLRequestContextGetter* request_context = GetRequestContext();
- DCHECK(request_context);
- network_context_owner_ = std::make_unique<NetworkContextOwner>(
- request_context, &network_context_);
+ CreateNetworkContext();
auto url_loader_factory_params =
network::mojom::URLLoaderFactoryParams::New();
url_loader_factory_params->process_id = network::mojom::kBrowserProcessId;
@@ -187,6 +181,14 @@
return url_loader_factory_.get();
}
+void BrowserState::GetProxyResolvingSocketFactory(
+ network::mojom::ProxyResolvingSocketFactoryRequest request) {
+ if (!network_context_owner_)
+ CreateNetworkContext();
+
+ network_context_->CreateProxyResolvingSocketFactory(std::move(request));
+}
+
scoped_refptr<network::SharedURLLoaderFactory>
BrowserState::GetSharedURLLoaderFactory() {
return shared_url_loader_factory_;
@@ -200,6 +202,16 @@
return url_data_manager_ios_backend_;
}
+void BrowserState::CreateNetworkContext() {
+ DCHECK(!network_context_);
+ DCHECK(!network_context_owner_);
+
+ net::URLRequestContextGetter* request_context = GetRequestContext();
+ DCHECK(request_context);
+ network_context_owner_ =
+ std::make_unique<NetworkContextOwner>(request_context, &network_context_);
+}
+
// static
BrowserState* BrowserState::FromSupportsUserData(
base::SupportsUserData* supports_user_data) {
diff --git a/ios/web/public/browser_state.h b/ios/web/public/browser_state.h
index b5ff40b..d00d7dd9 100644
--- a/ios/web/public/browser_state.h
+++ b/ios/web/public/browser_state.h
@@ -9,6 +9,7 @@
#include "base/supports_user_data.h"
#include "services/network/public/mojom/network_service.mojom.h"
+#include "services/network/public/mojom/proxy_resolving_socket.mojom.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "services/service_manager/embedder/embedded_service_info.h"
@@ -66,6 +67,10 @@
// Returns a URLLoaderFactory that is backed by GetRequestContext.
network::mojom::URLLoaderFactory* GetURLLoaderFactory();
+ // Binds a ProxyResolvingSocketFactory request to NetworkContext.
+ void GetProxyResolvingSocketFactory(
+ network::mojom::ProxyResolvingSocketFactoryRequest request);
+
// Like URLLoaderFactory, but wrapped inside SharedURLLoaderFactory
scoped_refptr<network::SharedURLLoaderFactory> GetSharedURLLoaderFactory();
@@ -115,6 +120,8 @@
// Not intended for usage outside of //web.
URLDataManagerIOSBackend* GetURLDataManagerIOSBackendOnIOThread();
+ void CreateNetworkContext();
+
network::mojom::URLLoaderFactoryPtr url_loader_factory_;
scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
shared_url_loader_factory_;
diff --git a/ios/web_view/internal/sync/web_view_gcm_profile_service_factory.mm b/ios/web_view/internal/sync/web_view_gcm_profile_service_factory.mm
index baa19f8..27134ab5 100644
--- a/ios/web_view/internal/sync/web_view_gcm_profile_service_factory.mm
+++ b/ios/web_view/internal/sync/web_view_gcm_profile_service_factory.mm
@@ -16,6 +16,7 @@
#include "ios/web_view/internal/signin/web_view_identity_manager_factory.h"
#include "ios/web_view/internal/web_view_browser_state.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/mojom/proxy_resolving_socket.mojom.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
@@ -23,6 +24,34 @@
namespace ios_web_view {
+namespace {
+
+// Requests a ProxyResolvingSocketFactoryPtr on the UI thread. Note that a
+// WeakPtr of GCMProfileService is needed to detect when the KeyedService shuts
+// down, and avoid calling into |profile| which might have also been destroyed.
+void RequestProxyResolvingSocketFactoryOnUIThread(
+ web::BrowserState* context,
+ base::WeakPtr<gcm::GCMProfileService> service,
+ network::mojom::ProxyResolvingSocketFactoryRequest request) {
+ if (!service)
+ return;
+ context->GetProxyResolvingSocketFactory(std::move(request));
+}
+
+// A thread-safe wrapper to request a ProxyResolvingSocketFactoryPtr.
+void RequestProxyResolvingSocketFactory(
+ web::BrowserState* context,
+ base::WeakPtr<gcm::GCMProfileService> service,
+ network::mojom::ProxyResolvingSocketFactoryRequest request) {
+ web::WebThread::GetTaskRunnerForThread(web::WebThread::UI)
+ ->PostTask(
+ FROM_HERE,
+ base::BindOnce(&RequestProxyResolvingSocketFactoryOnUIThread, context,
+ std::move(service), std::move(request)));
+}
+
+} // namespace
+
// static
gcm::GCMProfileService* WebViewGCMProfileServiceFactory::GetForBrowserState(
WebViewBrowserState* browser_state) {
@@ -64,6 +93,7 @@
return std::make_unique<gcm::GCMProfileService>(
browser_state->GetPrefs(), browser_state->GetStatePath(),
browser_state->GetRequestContext(),
+ base::BindRepeating(&RequestProxyResolvingSocketFactory, context),
browser_state->GetSharedURLLoaderFactory(),
version_info::Channel::UNKNOWN, GetProductCategoryForSubtypes(),
WebViewIdentityManagerFactory::GetForBrowserState(browser_state),
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index 1667eee..5be76220 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -814,6 +814,14 @@
return rv;
}
+int SSLClientSocketImpl::CancelReadIfReady() {
+ int result = transport_->socket()->CancelReadIfReady();
+ // Cancel |user_read_callback_|, because caller does not expect the callback
+ // to be invoked after they have canceled the ReadIfReady.
+ user_read_callback_.Reset();
+ return result;
+}
+
int SSLClientSocketImpl::Write(
IOBuffer* buf,
int buf_len,
diff --git a/net/socket/ssl_client_socket_impl.h b/net/socket/ssl_client_socket_impl.h
index 150a479..4648ab72 100644
--- a/net/socket/ssl_client_socket_impl.h
+++ b/net/socket/ssl_client_socket_impl.h
@@ -125,6 +125,7 @@
int ReadIfReady(IOBuffer* buf,
int buf_len,
CompletionOnceCallback callback) override;
+ int CancelReadIfReady() override;
int Write(IOBuffer* buf,
int buf_len,
CompletionOnceCallback callback,
diff --git a/services/network/proxy_resolving_socket_mojo.cc b/services/network/proxy_resolving_socket_mojo.cc
index c9c0542..040dc35e7 100644
--- a/services/network/proxy_resolving_socket_mojo.cc
+++ b/services/network/proxy_resolving_socket_mojo.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/logging.h"
+#include "base/optional.h"
#include "net/base/net_errors.h"
#include "services/network/socket_data_pump.h"
@@ -17,7 +18,16 @@
const net::NetworkTrafficAnnotationTag& traffic_annotation)
: socket_(std::move(socket)), traffic_annotation_(traffic_annotation) {}
-ProxyResolvingSocketMojo::~ProxyResolvingSocketMojo() {}
+ProxyResolvingSocketMojo::~ProxyResolvingSocketMojo() {
+ if (connect_callback_) {
+ // If |this| is destroyed when connect hasn't completed, tell the consumer
+ // that request has been aborted.
+ std::move(connect_callback_)
+ .Run(net::ERR_ABORTED, base::nullopt, base::nullopt,
+ mojo::ScopedDataPipeConsumerHandle(),
+ mojo::ScopedDataPipeProducerHandle());
+ }
+}
void ProxyResolvingSocketMojo::Connect(
mojom::ProxyResolvingSocketFactory::CreateProxyResolvingSocketCallback
@@ -34,18 +44,6 @@
OnConnectCompleted(result);
}
-void ProxyResolvingSocketMojo::GetPeerAddress(GetPeerAddressCallback callback) {
- DCHECK(socket_);
-
- net::IPEndPoint peer_addr;
- int result = socket_->GetPeerAddress(&peer_addr);
- if (result != net::OK) {
- std::move(callback).Run(result, base::nullopt);
- return;
- }
- std::move(callback).Run(result, peer_addr);
-}
-
void ProxyResolvingSocketMojo::OnConnectCompleted(int result) {
DCHECK(!connect_callback_.is_null());
DCHECK(!socket_data_pump_);
@@ -54,9 +52,16 @@
if (result == net::OK)
result = socket_->GetLocalAddress(&local_addr);
+ net::IPEndPoint peer_addr;
+ // If |socket_| is connected through a proxy, GetPeerAddress returns
+ // net::ERR_NAME_NOT_RESOLVED.
+ bool get_peer_address_success =
+ result == net::OK && (socket_->GetPeerAddress(&peer_addr) == net::OK);
+
if (result != net::OK) {
std::move(connect_callback_)
- .Run(result, base::nullopt, mojo::ScopedDataPipeConsumerHandle(),
+ .Run(result, base::nullopt, base::nullopt,
+ mojo::ScopedDataPipeConsumerHandle(),
mojo::ScopedDataPipeProducerHandle());
return;
}
@@ -67,7 +72,11 @@
std::move(receive_pipe.producer_handle),
std::move(send_pipe.consumer_handle), traffic_annotation_);
std::move(connect_callback_)
- .Run(net::OK, local_addr, std::move(receive_pipe.consumer_handle),
+ .Run(net::OK, local_addr,
+ get_peer_address_success
+ ? base::make_optional<net::IPEndPoint>(peer_addr)
+ : base::nullopt,
+ std::move(receive_pipe.consumer_handle),
std::move(send_pipe.producer_handle));
}
diff --git a/services/network/proxy_resolving_socket_mojo.h b/services/network/proxy_resolving_socket_mojo.h
index 7b127c5..d90a569 100644
--- a/services/network/proxy_resolving_socket_mojo.h
+++ b/services/network/proxy_resolving_socket_mojo.h
@@ -29,9 +29,6 @@
mojom::ProxyResolvingSocketFactory::CreateProxyResolvingSocketCallback
callback);
- // mojom::ProxyResolvingSocket implementation.
- void GetPeerAddress(GetPeerAddressCallback callback) override;
-
private:
void OnConnectCompleted(int net_result);
diff --git a/services/network/proxy_resolving_socket_mojo_unittest.cc b/services/network/proxy_resolving_socket_mojo_unittest.cc
index 018a55c..aa8c795 100644
--- a/services/network/proxy_resolving_socket_mojo_unittest.cc
+++ b/services/network/proxy_resolving_socket_mojo_unittest.cc
@@ -6,11 +6,13 @@
#include <utility>
#include <vector>
+#include "base/containers/span.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/test/bind_test_util.h"
#include "base/test/scoped_task_environment.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/dns/mock_host_resolver.h"
@@ -46,21 +48,23 @@
} // namespace
-class ProxyResolvingSocketTest : public testing::Test,
- public ::testing::WithParamInterface<bool> {
+class ProxyResolvingSocketTestBase {
public:
- ProxyResolvingSocketTest()
- : use_tls_(GetParam()),
+ ProxyResolvingSocketTestBase(bool use_tls)
+ : use_tls_(use_tls),
scoped_task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
- ~ProxyResolvingSocketTest() override {}
+ ~ProxyResolvingSocketTestBase() {}
void Init(const std::string& pac_result) {
- // |factory_| depends on |context_with_proxy_|, which will be
- // re-initialized. Reset it first, since |context_with_proxy_| must
- // outlive |factory_|.
- factory_.reset();
+ // Init() can be called multiple times in a test. Reset the members for each
+ // invocation. |context_with_proxy_| must outlive |factory_impl_|, which
+ // uses the URLRequestContet.
+ factory_binding_ = nullptr;
+ factory_impl_ = nullptr;
+ factory_ptr_.reset();
+ context_with_proxy_ = nullptr;
mock_client_socket_factory_ =
std::make_unique<net::MockClientSocketFactory>();
@@ -70,8 +74,12 @@
context_with_proxy_->set_client_socket_factory(
mock_client_socket_factory_.get());
context_with_proxy_->Init();
- factory_ = std::make_unique<ProxyResolvingSocketFactoryMojo>(
+
+ factory_impl_ = std::make_unique<ProxyResolvingSocketFactoryMojo>(
context_with_proxy_.get());
+ factory_binding_ =
+ std::make_unique<mojo::Binding<mojom::ProxyResolvingSocketFactory>>(
+ factory_impl_.get(), mojo::MakeRequest(&factory_ptr_));
}
// Reads |num_bytes| from |handle| or reads until an error occurs. Returns the
@@ -97,22 +105,26 @@
int CreateSocketSync(
mojom::ProxyResolvingSocketRequest request,
+ net::IPEndPoint* peer_addr_out,
const GURL& url,
mojo::ScopedDataPipeConsumerHandle* receive_pipe_handle_out,
mojo::ScopedDataPipeProducerHandle* send_pipe_handle_out) {
base::RunLoop run_loop;
int net_error = net::ERR_FAILED;
- factory_->CreateProxyResolvingSocket(
+ factory_ptr_->CreateProxyResolvingSocket(
url, use_tls_,
net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
std::move(request),
base::BindLambdaForTesting(
[&](int result, const base::Optional<net::IPEndPoint>& local_addr,
+ const base::Optional<net::IPEndPoint>& peer_addr,
mojo::ScopedDataPipeConsumerHandle receive_pipe_handle,
mojo::ScopedDataPipeProducerHandle send_pipe_handle) {
net_error = result;
if (net_error == net::OK)
EXPECT_NE(0, local_addr.value().port());
+ if (peer_addr_out && peer_addr)
+ *peer_addr_out = peer_addr.value();
*receive_pipe_handle_out = std::move(receive_pipe_handle);
*send_pipe_handle_out = std::move(send_pipe_handle);
run_loop.Quit();
@@ -127,13 +139,29 @@
bool use_tls() const { return use_tls_; }
+ mojom::ProxyResolvingSocketFactory* factory() { return factory_ptr_.get(); }
+
private:
const bool use_tls_;
base::test::ScopedTaskEnvironment scoped_task_environment_;
std::unique_ptr<net::MockClientSocketFactory> mock_client_socket_factory_;
std::unique_ptr<TestURLRequestContextWithProxy> context_with_proxy_;
- std::unique_ptr<mojom::ProxyResolvingSocketFactory> factory_;
+ mojom::ProxyResolvingSocketFactoryPtr factory_ptr_;
+ std::unique_ptr<mojo::Binding<mojom::ProxyResolvingSocketFactory>>
+ factory_binding_;
+ std::unique_ptr<ProxyResolvingSocketFactoryMojo> factory_impl_;
+ DISALLOW_COPY_AND_ASSIGN(ProxyResolvingSocketTestBase);
+};
+
+class ProxyResolvingSocketTest : public ProxyResolvingSocketTestBase,
+ public testing::TestWithParam<bool> {
+ public:
+ ProxyResolvingSocketTest() : ProxyResolvingSocketTestBase(GetParam()) {}
+
+ ~ProxyResolvingSocketTest() override {}
+
+ private:
DISALLOW_COPY_AND_ASSIGN(ProxyResolvingSocketTest);
};
@@ -174,27 +202,18 @@
mojom::ProxyResolvingSocketPtr socket;
mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
- EXPECT_EQ(net::OK,
- CreateSocketSync(mojo::MakeRequest(&socket), kDestination,
- &client_socket_receive_handle,
- &client_socket_send_handle));
net::IPEndPoint actual_remote_addr;
- int net_error = net::ERR_FAILED;
- base::RunLoop run_loop;
- socket->GetPeerAddress(base::BindLambdaForTesting(
- [&](int result, const base::Optional<net::IPEndPoint>& peer_addr) {
- net_error = result;
- if (net_error == net::OK)
- actual_remote_addr = peer_addr.value();
- run_loop.Quit();
- }));
- run_loop.Run();
+ EXPECT_EQ(net::OK,
+ CreateSocketSync(mojo::MakeRequest(&socket), &actual_remote_addr,
+ kDestination, &client_socket_receive_handle,
+ &client_socket_send_handle));
+ // Consume all read data.
+ base::RunLoop().RunUntilIdle();
if (!is_direct) {
- EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, net_error);
+ EXPECT_EQ(net::IPEndPoint(), actual_remote_addr);
EXPECT_FALSE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
} else {
- EXPECT_EQ(net::OK, net_error);
EXPECT_EQ(remote_addr.ToString(), actual_remote_addr.ToString());
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_FALSE(socket_data.AllWriteDataConsumed());
@@ -229,8 +248,8 @@
mojom::ProxyResolvingSocketPtr socket;
mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
- int status = CreateSocketSync(mojo::MakeRequest(&socket), kDestination,
- &client_socket_receive_handle,
+ int status = CreateSocketSync(mojo::MakeRequest(&socket), nullptr,
+ kDestination, &client_socket_receive_handle,
&client_socket_send_handle);
if (test.is_direct) {
EXPECT_EQ(net::ERR_FAILED, status);
@@ -273,9 +292,10 @@
mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
const GURL kDestination("http://example.com");
- EXPECT_EQ(net::OK, CreateSocketSync(mojo::MakeRequest(&socket), kDestination,
- &client_socket_receive_handle,
- &client_socket_send_handle));
+ EXPECT_EQ(net::OK,
+ CreateSocketSync(mojo::MakeRequest(&socket), nullptr, kDestination,
+ &client_socket_receive_handle,
+ &client_socket_send_handle));
// Loop kNumIterations times to test that writes can follow reads, and reads
// can follow writes.
for (int j = 0; j < kNumIterations; ++j) {
@@ -296,4 +316,47 @@
EXPECT_EQ(use_tls(), ssl_data.ConnectDataConsumed());
}
+// Tests that exercise logic related to mojo.
+class ProxyResolvingSocketMojoTest : public ProxyResolvingSocketTestBase,
+ public testing::Test {
+ public:
+ ProxyResolvingSocketMojoTest() : ProxyResolvingSocketTestBase(false) {}
+
+ ~ProxyResolvingSocketMojoTest() override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ProxyResolvingSocketMojoTest);
+};
+
+// Tests that when ProxyResolvingSocketPtr is destroyed but not the
+// ProxyResolvingSocketFactory, the connect callback is not dropped.
+// Regression test for https://crbug.com/862608.
+TEST_F(ProxyResolvingSocketMojoTest, SocketDestroyedBeforeConnectCompletes) {
+ Init("DIRECT");
+ std::vector<net::MockRead> reads;
+ std::vector<net::MockWrite> writes;
+
+ net::StaticSocketDataProvider data_provider(reads, writes);
+ data_provider.set_connect_data(net::MockConnect(net::ASYNC, net::OK));
+ mock_client_socket_factory()->AddSocketDataProvider(&data_provider);
+ const GURL kDestination("http://example.com");
+ mojom::ProxyResolvingSocketPtr socket;
+ base::RunLoop run_loop;
+ int net_error = net::OK;
+ factory()->CreateProxyResolvingSocket(
+ kDestination, false,
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
+ mojo::MakeRequest(&socket),
+ base::BindLambdaForTesting(
+ [&](int result, const base::Optional<net::IPEndPoint>& local_addr,
+ const base::Optional<net::IPEndPoint>& peer_addr,
+ mojo::ScopedDataPipeConsumerHandle receive_pipe_handle,
+ mojo::ScopedDataPipeProducerHandle send_pipe_handle) {
+ net_error = result;
+ }));
+ socket.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(net::ERR_ABORTED, net_error);
+}
+
} // namespace network
diff --git a/services/network/public/mojom/proxy_resolving_socket.mojom b/services/network/public/mojom/proxy_resolving_socket.mojom
index 18ceb08..59cd312b 100644
--- a/services/network/public/mojom/proxy_resolving_socket.mojom
+++ b/services/network/public/mojom/proxy_resolving_socket.mojom
@@ -12,13 +12,6 @@
// and Reads are through the data pipes supplied upon construction. Consumer
// can close the socket by destroying the interface pointer.
interface ProxyResolvingSocket{
- // Gets the peer address. On success, |net_error| is
- // net::OK and |peer_addr| contains the peer address. On failure,
- // |peer_addr| is null and |net_error| is a net error code. If socket is
- // connected to a proxy, |net_error| will be net::ERR_NAME_NOT_RESOLVED, and
- // |peer_addr| will be empty.
- GetPeerAddress() => (int32 net_error, net.interfaces.IPEndPoint? peer_addr);
-
// TODO(xunjieli): Add methods to configure the socket connection and allow
// consumers to specify whether they want to disconnect or return the socket
// to socket pools.
@@ -33,7 +26,12 @@
// connection will be established on top of a TCP connection. On success,
// |result| is net::OK. Caller is to use |send_stream| to send data and
// |receive_stream| to receive data over the connection. On failure, |result|
- // is a network error code.
+ // is a network error code. |local_addr| contains the local address of the
+ // socket. |peer_addr| contains the peer address. If socket is connected to a
+ // proxy, |peer_addr| will be null.
+ //
+ // If socket is closed before the callback can be completed, the callback will
+ // be invoked with net::ERR_ABORTED.
//
// Any sockets that are created but are yet to be destroyed will be destroyed
// when the implementation of this factory goes away.
@@ -42,6 +40,7 @@
ProxyResolvingSocket& socket)
=> (int32 result,
net.interfaces.IPEndPoint? local_addr,
+ net.interfaces.IPEndPoint? peer_addr,
handle<data_pipe_consumer>? receive_stream,
handle<data_pipe_producer>? send_stream);
};