summaryrefslogtreecommitdiffstats
path: root/content/renderer
diff options
context:
space:
mode:
authorjiayl@chromium.org <jiayl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-20 03:42:57 +0000
committerjiayl@chromium.org <jiayl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-20 03:42:57 +0000
commit921480f6d54a82a3819d308ed32548a3afba676b (patch)
treefe99793a80634f89eaef8cd6fc15d6ff7850e394 /content/renderer
parentd2cf063e9e649cf4741725196451821d4d6d266a (diff)
downloadchromium_src-921480f6d54a82a3819d308ed32548a3afba676b.zip
chromium_src-921480f6d54a82a3819d308ed32548a3afba676b.tar.gz
chromium_src-921480f6d54a82a3819d308ed32548a3afba676b.tar.bz2
Creates a WebRTCIdentityService instance per peer connection and passes it to libjingle.
Also adds a per renderer object WebRTCIdentityProxy to queue the pending requests and makes sure only one outstanding request at a time for a renderer. The requests are queued on the renderer side instead of the browser side to avoid a potential memory exhaustion attack by an evil renderer. Removes request_id from the IPC as it's unnecessary now. Renames WebRTCIdentityServiceHost to WebRTCIdentityProxyHost and adds unittest. BUG= Review URL: https://chromiumcodereview.appspot.com/19392004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@212728 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/renderer')
-rw-r--r--content/renderer/media/media_stream_dependency_factory.cc14
-rw-r--r--content/renderer/media/peer_connection_identity_service.cc59
-rw-r--r--content/renderer/media/peer_connection_identity_service.h49
-rw-r--r--content/renderer/media/webrtc_identity_service.cc136
-rw-r--r--content/renderer/media/webrtc_identity_service.h86
-rw-r--r--content/renderer/media/webrtc_identity_service_unittest.cc210
-rw-r--r--content/renderer/render_thread_impl.cc3
-rw-r--r--content/renderer/render_thread_impl.h9
8 files changed, 500 insertions, 66 deletions
diff --git a/content/renderer/media/media_stream_dependency_factory.cc b/content/renderer/media/media_stream_dependency_factory.cc
index f15f103..27a0b2a 100644
--- a/content/renderer/media/media_stream_dependency_factory.cc
+++ b/content/renderer/media/media_stream_dependency_factory.cc
@@ -11,6 +11,7 @@
#include "base/synchronization/waitable_event.h"
#include "content/public/common/content_switches.h"
#include "content/renderer/media/media_stream_source_extra_data.h"
+#include "content/renderer/media/peer_connection_identity_service.h"
#include "content/renderer/media/rtc_media_constraints.h"
#include "content/renderer/media/rtc_peer_connection_handler.h"
#include "content/renderer/media/rtc_video_capturer.h"
@@ -567,9 +568,16 @@ MediaStreamDependencyFactory::CreatePeerConnection(
network_manager_,
socket_factory_.get(),
web_frame);
- return pc_factory_->CreatePeerConnection(
- ice_servers, constraints, pa_factory.get(), NULL, observer)
- .get();
+
+ PeerConnectionIdentityService* identity_service =
+ new PeerConnectionIdentityService(GURL(web_frame->document().url().spec())
+ .GetOrigin());
+
+ return pc_factory_->CreatePeerConnection(ice_servers,
+ constraints,
+ pa_factory.get(),
+ identity_service,
+ observer).get();
}
scoped_refptr<webrtc::MediaStreamInterface>
diff --git a/content/renderer/media/peer_connection_identity_service.cc b/content/renderer/media/peer_connection_identity_service.cc
new file mode 100644
index 0000000..f7bc856
--- /dev/null
+++ b/content/renderer/media/peer_connection_identity_service.cc
@@ -0,0 +1,59 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/media/peer_connection_identity_service.h"
+
+#include "content/renderer/media/webrtc_identity_service.h"
+#include "content/renderer/render_thread_impl.h"
+
+namespace content {
+
+PeerConnectionIdentityService::PeerConnectionIdentityService(const GURL& origin)
+ : origin_(origin), pending_observer_(NULL), pending_request_id_(0) {}
+
+PeerConnectionIdentityService::~PeerConnectionIdentityService() {
+ if (pending_observer_)
+ RenderThreadImpl::current()->get_webrtc_identity_service()
+ ->CancelRequest(pending_request_id_);
+}
+
+bool PeerConnectionIdentityService::RequestIdentity(
+ const std::string& identity_name,
+ const std::string& common_name,
+ webrtc::DTLSIdentityRequestObserver* observer) {
+ DCHECK(observer);
+ if (pending_observer_)
+ return false;
+
+ pending_observer_ = observer;
+ pending_request_id_ = RenderThreadImpl::current()
+ ->get_webrtc_identity_service()->RequestIdentity(
+ origin_,
+ identity_name,
+ common_name,
+ base::Bind(&PeerConnectionIdentityService::OnIdentityReady,
+ base::Unretained(this)),
+ base::Bind(&PeerConnectionIdentityService::OnRequestFailed,
+ base::Unretained(this)));
+ return true;
+}
+
+void PeerConnectionIdentityService::OnIdentityReady(
+ const std::string& certificate,
+ const std::string& private_key) {
+ pending_observer_->OnSuccess(certificate, private_key);
+ ResetPendingRequest();
+}
+
+void PeerConnectionIdentityService::OnRequestFailed(int error) {
+ pending_observer_->OnFailure(error);
+ ResetPendingRequest();
+}
+
+void PeerConnectionIdentityService::ResetPendingRequest() {
+ pending_observer_ = NULL;
+ pending_request_id_ = 0;
+}
+
+} // namespace content
diff --git a/content/renderer/media/peer_connection_identity_service.h b/content/renderer/media/peer_connection_identity_service.h
new file mode 100644
index 0000000..a5092e3
--- /dev/null
+++ b/content/renderer/media/peer_connection_identity_service.h
@@ -0,0 +1,49 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_MEDIA_PEER_CONNECTION_IDENTITY_SERVICE_H_
+#define CONTENT_RENDERER_MEDIA_PEER_CONNECTION_IDENTITY_SERVICE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "content/public/renderer/render_process_observer.h"
+#include "third_party/libjingle/source/talk/app/webrtc/peerconnectioninterface.h"
+#include "url/gurl.h"
+
+namespace content {
+
+// This class is associated with a peer connection and handles WebRTC DTLS
+// identity requests by delegating to the per-renderer WebRTCIdentityProxy.
+class PeerConnectionIdentityService
+ : public webrtc::DTLSIdentityServiceInterface {
+ public:
+ explicit PeerConnectionIdentityService(const GURL& origin);
+ virtual ~PeerConnectionIdentityService();
+
+ // webrtc::DTLSIdentityServiceInterface implementation.
+ virtual bool RequestIdentity(
+ const std::string& identity_name,
+ const std::string& common_name,
+ webrtc::DTLSIdentityRequestObserver* observer) OVERRIDE;
+
+ private:
+ void OnIdentityReady(const std::string& certificate,
+ const std::string& private_key);
+ void OnRequestFailed(int error);
+
+ void ResetPendingRequest();
+
+ // The origin of the DTLS connection.
+ GURL origin_;
+ talk_base::scoped_refptr<webrtc::DTLSIdentityRequestObserver>
+ pending_observer_;
+ int pending_request_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(PeerConnectionIdentityService);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_MEDIA_PEER_CONNECTION_IDENTITY_SERVICE_H_
diff --git a/content/renderer/media/webrtc_identity_service.cc b/content/renderer/media/webrtc_identity_service.cc
index 7042c93..7e9e540 100644
--- a/content/renderer/media/webrtc_identity_service.cc
+++ b/content/renderer/media/webrtc_identity_service.cc
@@ -4,50 +4,89 @@
#include "content/renderer/media/webrtc_identity_service.h"
-#include "base/atomic_sequence_num.h"
#include "content/common/media/webrtc_identity_messages.h"
#include "content/public/renderer/render_thread.h"
+#include "net/base/net_errors.h"
namespace content {
-WebRTCIdentityService::WebRTCIdentityService(const GURL& origin)
- : origin_(origin), pending_observer_(NULL), pending_request_id_(0) {
- RenderThread::Get()->AddObserver(this);
+WebRTCIdentityService::RequestInfo::RequestInfo(
+ int request_id,
+ const GURL& origin,
+ const std::string& identity_name,
+ const std::string& common_name,
+ const SuccessCallback& success_callback,
+ const FailureCallback& failure_callback)
+ : request_id(request_id),
+ origin(origin),
+ identity_name(identity_name),
+ common_name(common_name),
+ success_callback(success_callback),
+ failure_callback(failure_callback) {}
+
+WebRTCIdentityService::RequestInfo::~RequestInfo() {}
+
+WebRTCIdentityService::WebRTCIdentityService() : next_request_id_(1) {
+ // RenderThread::Get() could be NULL in unit tests.
+ if (RenderThread::Get())
+ RenderThread::Get()->AddObserver(this);
}
WebRTCIdentityService::~WebRTCIdentityService() {
- RenderThread::Get()->RemoveObserver(this);
- if (pending_observer_) {
- RenderThread::Get()->Send(
- new WebRTCIdentityMsg_CancelRequest(pending_request_id_));
+ // RenderThread::Get() could be NULL in unit tests.
+ if (RenderThread::Get()) {
+ RenderThread::Get()->RemoveObserver(this);
+
+ if (!pending_requests_.empty()) {
+ RenderThread::Get()->Send(new WebRTCIdentityMsg_CancelRequest());
+ }
}
}
-bool WebRTCIdentityService::RequestIdentity(
+int WebRTCIdentityService::RequestIdentity(
+ const GURL& origin,
const std::string& identity_name,
const std::string& common_name,
- webrtc::DTLSIdentityRequestObserver* observer) {
- // Static because the request id needs to be unique per renderer process
- // across WebRTCIdentityService instances.
- static base::AtomicSequenceNumber s_next_request_id;
-
- DCHECK(observer);
- if (pending_observer_)
- return false;
-
- pending_observer_ = observer;
- pending_request_id_ = s_next_request_id.GetNext();
- RenderThread::Get()->Send(new WebRTCIdentityMsg_RequestIdentity(
- pending_request_id_, origin_, identity_name, common_name));
- return true;
+ const SuccessCallback& success_callback,
+ const FailureCallback& failure_callback) {
+ int request_id = next_request_id_++;
+
+ RequestInfo request_info(request_id,
+ origin,
+ identity_name,
+ common_name,
+ success_callback,
+ failure_callback);
+
+ pending_requests_.push_back(request_info);
+ if (pending_requests_.size() == 1)
+ SendRequest(request_info);
+
+ return request_id;
+}
+
+void WebRTCIdentityService::CancelRequest(int request_id) {
+ std::deque<RequestInfo>::iterator it;
+ for (it = pending_requests_.begin(); it != pending_requests_.end(); ++it) {
+ if (it->request_id != request_id)
+ continue;
+ if (it != pending_requests_.begin()) {
+ pending_requests_.erase(it);
+ } else {
+ Send(new WebRTCIdentityMsg_CancelRequest());
+ OnOutstandingRequestReturned();
+ }
+ break;
+ }
+}
+
+bool WebRTCIdentityService::Send(IPC::Message* message) {
+ // Unit tests should override this method to avoid null-ptr-deref.
+ return RenderThread::Get()->Send(message);
}
bool WebRTCIdentityService::OnControlMessageReceived(
const IPC::Message& message) {
- if (!pending_observer_)
- return false;
-
- int old_pending_request_id = pending_request_id_;
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(WebRTCIdentityService, message)
IPC_MESSAGE_HANDLER(WebRTCIdentityHostMsg_IdentityReady, OnIdentityReady)
@@ -55,28 +94,39 @@ bool WebRTCIdentityService::OnControlMessageReceived(
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
- if (pending_request_id_ == old_pending_request_id)
- handled = false;
-
return handled;
}
-void WebRTCIdentityService::OnIdentityReady(int request_id,
- const std::string& certificate,
+void WebRTCIdentityService::OnIdentityReady(const std::string& certificate,
const std::string& private_key) {
- if (request_id != pending_request_id_)
- return;
- pending_observer_->OnSuccess(certificate, private_key);
- pending_observer_ = NULL;
- pending_request_id_ = 0;
+ DCHECK(!pending_requests_.empty());
+ pending_requests_.front().success_callback.Run(certificate, private_key);
+ OnOutstandingRequestReturned();
+}
+
+void WebRTCIdentityService::OnRequestFailed(int error) {
+ DCHECK(!pending_requests_.empty());
+ pending_requests_.front().failure_callback.Run(error);
+ OnOutstandingRequestReturned();
}
-void WebRTCIdentityService::OnRequestFailed(int request_id, int error) {
- if (request_id != pending_request_id_)
- return;
- pending_observer_->OnFailure(error);
- pending_observer_ = NULL;
- pending_request_id_ = 0;
+void WebRTCIdentityService::SendRequest(const RequestInfo& request_info) {
+ if (!Send(new WebRTCIdentityMsg_RequestIdentity(request_info.origin,
+ request_info.identity_name,
+ request_info.common_name))) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&WebRTCIdentityService::OnRequestFailed,
+ base::Unretained(this),
+ net::ERR_UNEXPECTED));
+ }
+}
+
+void WebRTCIdentityService::OnOutstandingRequestReturned() {
+ pending_requests_.pop_front();
+
+ if (!pending_requests_.empty())
+ SendRequest(pending_requests_.front());
}
} // namespace content
diff --git a/content/renderer/media/webrtc_identity_service.h b/content/renderer/media/webrtc_identity_service.h
index 7ff18ba..3e6efa5 100644
--- a/content/renderer/media/webrtc_identity_service.h
+++ b/content/renderer/media/webrtc_identity_service.h
@@ -5,44 +5,90 @@
#ifndef CONTENT_RENDERER_MEDIA_WEBRTC_IDENTITY_SERVICE_H_
#define CONTENT_RENDERER_MEDIA_WEBRTC_IDENTITY_SERVICE_H_
+#include <deque>
#include <string>
#include "base/basictypes.h"
+#include "base/callback.h"
+#include "content/common/content_export.h"
#include "content/public/renderer/render_process_observer.h"
-#include "third_party/libjingle/source/talk/app/webrtc/peerconnectioninterface.h"
#include "url/gurl.h"
namespace content {
// This class handles WebRTC DTLS identity requests by sending IPC messages to
-// the browser process.
-class WebRTCIdentityService : public webrtc::DTLSIdentityServiceInterface,
- public RenderProcessObserver {
+// the browser process. Only one request is sent to the browser at a time; other
+// requests are queued and have to wait for the outstanding request to complete.
+class CONTENT_EXPORT WebRTCIdentityService : public RenderProcessObserver {
public:
- explicit WebRTCIdentityService(const GURL& origin);
+ typedef base::Callback<
+ void(const std::string& certificate, const std::string& private_key)>
+ SuccessCallback;
+
+ typedef base::Callback<void(int error)> FailureCallback;
+
+ WebRTCIdentityService();
virtual ~WebRTCIdentityService();
- // WebRTCIdentityServiceInterface implementation.
- virtual bool RequestIdentity(const std::string& identity_name,
- const std::string& common_name,
- webrtc::DTLSIdentityRequestObserver* observer)
- OVERRIDE;
+ // Sends an identity request.
+ //
+ // |origin| is the origin of the caller;
+ // |identity_name| and |common_name| have the same meaning as in
+ // webrtc::DTLSIdentityServiceInterface::RequestIdentity;
+ // |success_callback| is the callback if the identity is successfully
+ // returned;
+ // |failure_callback| is the callback if the identity request fails.
+ //
+ // The request id is returned. It's unique within the renderer and can be used
+ // to cancel the request.
+ int RequestIdentity(const GURL& origin,
+ const std::string& identity_name,
+ const std::string& common_name,
+ const SuccessCallback& success_callback,
+ const FailureCallback& failure_callback);
- private:
- // RenderProcessObserver implementation.
+ // Cancels a previous request and the callbacks will not be called.
+ // If the |request_id| is not associated with the
+ // outstanding request or any queued request, this method does nothing.
+ //
+ // |request_id| is the request id returned from RequestIdentity.
+ void CancelRequest(int request_id);
+
+ protected:
+ // For unittest to override.
+ virtual bool Send(IPC::Message* message);
+ // RenderProcessObserver implementation. Protected for testing.
virtual bool OnControlMessageReceived(const IPC::Message& message) OVERRIDE;
- void OnIdentityReady(int request_id,
- const std::string& certificate,
+ private:
+ struct RequestInfo {
+ RequestInfo(int request_id,
+ const GURL& origin,
+ const std::string& identity_name,
+ const std::string& common_name,
+ const SuccessCallback& success_callback,
+ const FailureCallback& failure_callback);
+ ~RequestInfo();
+
+ int request_id;
+ GURL origin;
+ std::string identity_name;
+ std::string common_name;
+ SuccessCallback success_callback;
+ FailureCallback failure_callback;
+ };
+
+ // IPC message handlers.
+ void OnIdentityReady(const std::string& certificate,
const std::string& private_key);
+ void OnRequestFailed(int error);
+
+ void SendRequest(const RequestInfo& request_id);
+ void OnOutstandingRequestReturned();
- void OnRequestFailed(int request_id, int error);
+ std::deque<RequestInfo> pending_requests_;
+ int next_request_id_;
- // The origin of the DTLS connection.
- GURL origin_;
- talk_base::scoped_refptr<webrtc::DTLSIdentityRequestObserver>
- pending_observer_;
- int pending_request_id_;
DISALLOW_COPY_AND_ASSIGN(WebRTCIdentityService);
};
diff --git a/content/renderer/media/webrtc_identity_service_unittest.cc b/content/renderer/media/webrtc_identity_service_unittest.cc
new file mode 100644
index 0000000..d6bd169
--- /dev/null
+++ b/content/renderer/media/webrtc_identity_service_unittest.cc
@@ -0,0 +1,210 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <deque>
+
+#include "content/common/media/webrtc_identity_messages.h"
+#include "content/renderer/media/webrtc_identity_service.h"
+#include "ipc/ipc_message.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+static const char FAKE_ORIGIN[] = "http://fake.com";
+static const char FAKE_IDENTITY_NAME[] = "fake identity";
+static const char FAKE_COMMON_NAME[] = "fake common name";
+static const char FAKE_CERTIFICATE[] = "fake cert";
+static const char FAKE_PRIVATE_KEY[] = "fake private key";
+static const int FAKE_ERROR = 100;
+
+class WebRTCIdentityServiceForTest : public WebRTCIdentityService {
+ public:
+ virtual bool Send(IPC::Message* message) OVERRIDE {
+ messages_.push_back(*message);
+ delete message;
+ return true;
+ }
+
+ virtual bool OnControlMessageReceived(const IPC::Message& message) OVERRIDE {
+ return WebRTCIdentityService::OnControlMessageReceived(message);
+ }
+
+ IPC::Message GetLastMessage() { return messages_.back(); }
+
+ int GetNumberOfMessages() { return messages_.size(); }
+
+ void ClearMessages() { messages_.clear(); }
+
+ private:
+ std::deque<IPC::Message> messages_;
+};
+
+class WebRTCIdentityServiceTest : public ::testing::Test {
+ public:
+ WebRTCIdentityServiceTest()
+ : service_(new WebRTCIdentityServiceForTest()), last_error_(0) {}
+
+ protected:
+ void OnIdentityReady(const std::string& cert, const std::string& key) {
+ last_certificate_ = cert;
+ last_private_key_ = key;
+ }
+
+ void OnRequestFailed(int error) { last_error_ = error; }
+
+ void ResetRequestResult() {
+ last_certificate_ = "";
+ last_private_key_ = "";
+ last_error_ = 0;
+ }
+
+ int RequestIdentity() {
+ return service_->RequestIdentity(
+ GURL(FAKE_ORIGIN),
+ FAKE_IDENTITY_NAME,
+ FAKE_COMMON_NAME,
+ base::Bind(&WebRTCIdentityServiceTest::OnIdentityReady,
+ base::Unretained(this)),
+ base::Bind(&WebRTCIdentityServiceTest::OnRequestFailed,
+ base::Unretained(this)));
+ }
+
+ scoped_ptr<WebRTCIdentityServiceForTest> service_;
+ std::string last_certificate_;
+ std::string last_private_key_;
+ int last_error_;
+};
+
+} // namespace
+
+TEST_F(WebRTCIdentityServiceTest, TestSendRequest) {
+ RequestIdentity();
+
+ IPC::Message ipc = service_->GetLastMessage();
+ EXPECT_EQ(ipc.type(), WebRTCIdentityMsg_RequestIdentity::ID);
+}
+
+TEST_F(WebRTCIdentityServiceTest, TestSuccessCallback) {
+ RequestIdentity();
+
+ service_->OnControlMessageReceived(
+ WebRTCIdentityHostMsg_IdentityReady(FAKE_CERTIFICATE, FAKE_PRIVATE_KEY));
+ EXPECT_EQ(FAKE_CERTIFICATE, last_certificate_);
+ EXPECT_EQ(FAKE_PRIVATE_KEY, last_private_key_);
+}
+
+TEST_F(WebRTCIdentityServiceTest, TestFailureCallback) {
+ RequestIdentity();
+
+ service_->OnControlMessageReceived(
+ WebRTCIdentityHostMsg_RequestFailed(FAKE_ERROR));
+ EXPECT_EQ(FAKE_ERROR, last_error_);
+}
+
+TEST_F(WebRTCIdentityServiceTest, TestCancelRequest) {
+ int request_id = RequestIdentity();
+ service_->ClearMessages();
+
+ service_->CancelRequest(request_id);
+
+ IPC::Message ipc = service_->GetLastMessage();
+ EXPECT_EQ(ipc.type(), WebRTCIdentityMsg_CancelRequest::ID);
+}
+
+TEST_F(WebRTCIdentityServiceTest, TestQueuedRequestSentAfterSuccess) {
+ RequestIdentity();
+ RequestIdentity();
+ EXPECT_EQ(1, service_->GetNumberOfMessages());
+ service_->ClearMessages();
+
+ service_->OnControlMessageReceived(
+ WebRTCIdentityHostMsg_IdentityReady(FAKE_CERTIFICATE, FAKE_PRIVATE_KEY));
+
+ IPC::Message ipc = service_->GetLastMessage();
+ EXPECT_EQ(ipc.type(), WebRTCIdentityMsg_RequestIdentity::ID);
+}
+
+TEST_F(WebRTCIdentityServiceTest, TestQueuedRequestSentAfterFailure) {
+ RequestIdentity();
+ RequestIdentity();
+ EXPECT_EQ(1, service_->GetNumberOfMessages());
+ service_->ClearMessages();
+
+ service_->OnControlMessageReceived(
+ WebRTCIdentityHostMsg_RequestFailed(FAKE_ERROR));
+
+ IPC::Message ipc = service_->GetLastMessage();
+ EXPECT_EQ(ipc.type(), WebRTCIdentityMsg_RequestIdentity::ID);
+}
+
+TEST_F(WebRTCIdentityServiceTest, TestQueuedRequestSentAfterCancelOutstanding) {
+ int outstand_request_id = RequestIdentity();
+ RequestIdentity();
+
+ EXPECT_EQ(1, service_->GetNumberOfMessages());
+ service_->ClearMessages();
+
+ service_->CancelRequest(outstand_request_id);
+
+ // Should have two messages sent: one for cancelling the outstanding request,
+ // one for requesting the queued request.
+ EXPECT_EQ(2, service_->GetNumberOfMessages());
+ IPC::Message ipc = service_->GetLastMessage();
+ EXPECT_EQ(ipc.type(), WebRTCIdentityMsg_RequestIdentity::ID);
+}
+
+TEST_F(WebRTCIdentityServiceTest, TestCancelQueuedRequest) {
+ RequestIdentity();
+ int queued_request_id = RequestIdentity();
+ EXPECT_EQ(1, service_->GetNumberOfMessages());
+ service_->ClearMessages();
+
+ service_->CancelRequest(queued_request_id);
+
+ // Verifies that the queued request is not sent after the outstanding request
+ // returns.
+ service_->OnControlMessageReceived(
+ WebRTCIdentityHostMsg_IdentityReady(FAKE_CERTIFICATE, FAKE_PRIVATE_KEY));
+
+ EXPECT_EQ(0, service_->GetNumberOfMessages());
+}
+
+TEST_F(WebRTCIdentityServiceTest, TestQueuedRequestSuccessCallback) {
+ RequestIdentity();
+ RequestIdentity();
+
+ // Completes the outstanding request.
+ service_->OnControlMessageReceived(
+ WebRTCIdentityHostMsg_IdentityReady(FAKE_CERTIFICATE, FAKE_PRIVATE_KEY));
+ EXPECT_EQ(FAKE_CERTIFICATE, last_certificate_);
+ EXPECT_EQ(FAKE_PRIVATE_KEY, last_private_key_);
+
+ ResetRequestResult();
+
+ service_->OnControlMessageReceived(
+ WebRTCIdentityHostMsg_IdentityReady(FAKE_CERTIFICATE, FAKE_PRIVATE_KEY));
+ EXPECT_EQ(FAKE_CERTIFICATE, last_certificate_);
+ EXPECT_EQ(FAKE_PRIVATE_KEY, last_private_key_);
+}
+
+TEST_F(WebRTCIdentityServiceTest, TestQueuedRequestFailureCallback) {
+ RequestIdentity();
+ RequestIdentity();
+
+ // Completes the outstanding request.
+ service_->OnControlMessageReceived(
+ WebRTCIdentityHostMsg_IdentityReady(FAKE_CERTIFICATE, FAKE_PRIVATE_KEY));
+ EXPECT_EQ(FAKE_CERTIFICATE, last_certificate_);
+ EXPECT_EQ(FAKE_PRIVATE_KEY, last_private_key_);
+
+ ResetRequestResult();
+
+ service_->OnControlMessageReceived(
+ WebRTCIdentityHostMsg_RequestFailed(FAKE_ERROR));
+ EXPECT_EQ(FAKE_ERROR, last_error_);
+}
+
+} // namespace content
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 18218a7..3ce5a94 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -72,6 +72,7 @@
#include "content/renderer/media/renderer_gpu_video_decoder_factories.h"
#include "content/renderer/media/video_capture_impl_manager.h"
#include "content/renderer/media/video_capture_message_filter.h"
+#include "content/renderer/media/webrtc_identity_service.h"
#include "content/renderer/memory_benchmarking_extension.h"
#include "content/renderer/p2p/socket_dispatcher.h"
#include "content/renderer/plugin_channel_host.h"
@@ -376,6 +377,8 @@ void RenderThreadImpl::Init() {
p2p_socket_dispatcher_ =
new P2PSocketDispatcher(GetIOMessageLoopProxy().get());
AddFilter(p2p_socket_dispatcher_.get());
+
+ webrtc_identity_service_.reset(new WebRTCIdentityService());
#endif // defined(ENABLE_WEBRTC)
vc_manager_ = new VideoCaptureImplManager();
AddFilter(vc_manager_->video_capture_message_filter());
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index 561fcf6..54d60698 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -90,6 +90,7 @@ class RenderProcessObserver;
class VideoCaptureImplManager;
class WebDatabaseObserverImpl;
class WebGraphicsContext3DCommandBufferImpl;
+class WebRTCIdentityService;
// The RenderThreadImpl class represents a background thread where RenderView
// instances live. The RenderThread supports an API that is used by its
@@ -287,6 +288,12 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
void PreCacheFontCharacters(const LOGFONT& log_font, const string16& str);
#endif
+#if defined(ENABLE_WEBRTC)
+ WebRTCIdentityService* get_webrtc_identity_service() {
+ return webrtc_identity_service_.get();
+ }
+#endif
+
// For producing custom V8 histograms. Custom histograms are produced if all
// RenderViews share the same host, and the host is in the pre-specified set
// of hosts we want to produce custom diagrams for. The name for a custom
@@ -477,6 +484,8 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
scoped_ptr<base::MemoryPressureListener> memory_pressure_listener_;
+ scoped_ptr<WebRTCIdentityService> webrtc_identity_service_;
+
DISALLOW_COPY_AND_ASSIGN(RenderThreadImpl);
};