• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/test/chromedriver/net/sync_websocket_impl.h"
6 
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/location.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/synchronization/waitable_event.h"
12 #include "net/base/net_errors.h"
13 #include "net/url_request/url_request_context_getter.h"
14 #include "url/gurl.h"
15 
SyncWebSocketImpl(net::URLRequestContextGetter * context_getter)16 SyncWebSocketImpl::SyncWebSocketImpl(
17     net::URLRequestContextGetter* context_getter)
18     : core_(new Core(context_getter)) {}
19 
~SyncWebSocketImpl()20 SyncWebSocketImpl::~SyncWebSocketImpl() {}
21 
IsConnected()22 bool SyncWebSocketImpl::IsConnected() {
23   return core_->IsConnected();
24 }
25 
Connect(const GURL & url)26 bool SyncWebSocketImpl::Connect(const GURL& url) {
27   return core_->Connect(url);
28 }
29 
Send(const std::string & message)30 bool SyncWebSocketImpl::Send(const std::string& message) {
31   return core_->Send(message);
32 }
33 
ReceiveNextMessage(std::string * message,const base::TimeDelta & timeout)34 SyncWebSocket::StatusCode SyncWebSocketImpl::ReceiveNextMessage(
35     std::string* message, const base::TimeDelta& timeout) {
36   return core_->ReceiveNextMessage(message, timeout);
37 }
38 
HasNextMessage()39 bool SyncWebSocketImpl::HasNextMessage() {
40   return core_->HasNextMessage();
41 }
42 
Core(net::URLRequestContextGetter * context_getter)43 SyncWebSocketImpl::Core::Core(net::URLRequestContextGetter* context_getter)
44     : context_getter_(context_getter),
45       is_connected_(false),
46       on_update_event_(&lock_) {}
47 
IsConnected()48 bool SyncWebSocketImpl::Core::IsConnected() {
49   base::AutoLock lock(lock_);
50   return is_connected_;
51 }
52 
Connect(const GURL & url)53 bool SyncWebSocketImpl::Core::Connect(const GURL& url) {
54   bool success = false;
55   base::WaitableEvent event(false, false);
56   context_getter_->GetNetworkTaskRunner()->PostTask(
57       FROM_HERE,
58       base::Bind(&SyncWebSocketImpl::Core::ConnectOnIO,
59                  this, url, &success, &event));
60   event.Wait();
61   return success;
62 }
63 
Send(const std::string & message)64 bool SyncWebSocketImpl::Core::Send(const std::string& message) {
65   bool success = false;
66   base::WaitableEvent event(false, false);
67   context_getter_->GetNetworkTaskRunner()->PostTask(
68       FROM_HERE,
69       base::Bind(&SyncWebSocketImpl::Core::SendOnIO,
70                  this, message, &success, &event));
71   event.Wait();
72   return success;
73 }
74 
ReceiveNextMessage(std::string * message,const base::TimeDelta & timeout)75 SyncWebSocket::StatusCode SyncWebSocketImpl::Core::ReceiveNextMessage(
76     std::string* message,
77     const base::TimeDelta& timeout) {
78   base::AutoLock lock(lock_);
79   base::TimeTicks deadline = base::TimeTicks::Now() + timeout;
80   base::TimeDelta next_wait = timeout;
81   while (received_queue_.empty() && is_connected_) {
82     if (next_wait <= base::TimeDelta())
83       return SyncWebSocket::kTimeout;
84     on_update_event_.TimedWait(next_wait);
85     next_wait = deadline - base::TimeTicks::Now();
86   }
87   if (!is_connected_)
88     return SyncWebSocket::kDisconnected;
89   *message = received_queue_.front();
90   received_queue_.pop_front();
91   return SyncWebSocket::kOk;
92 }
93 
HasNextMessage()94 bool SyncWebSocketImpl::Core::HasNextMessage() {
95   base::AutoLock lock(lock_);
96   return !received_queue_.empty();
97 }
98 
OnMessageReceived(const std::string & message)99 void SyncWebSocketImpl::Core::OnMessageReceived(const std::string& message) {
100   base::AutoLock lock(lock_);
101   received_queue_.push_back(message);
102   on_update_event_.Signal();
103 }
104 
OnClose()105 void SyncWebSocketImpl::Core::OnClose() {
106   base::AutoLock lock(lock_);
107   is_connected_ = false;
108   on_update_event_.Signal();
109 }
110 
~Core()111 SyncWebSocketImpl::Core::~Core() { }
112 
ConnectOnIO(const GURL & url,bool * success,base::WaitableEvent * event)113 void SyncWebSocketImpl::Core::ConnectOnIO(
114     const GURL& url,
115     bool* success,
116     base::WaitableEvent* event) {
117   {
118     base::AutoLock lock(lock_);
119     received_queue_.clear();
120   }
121   socket_.reset(new WebSocket(url, this));
122   socket_->Connect(base::Bind(
123       &SyncWebSocketImpl::Core::OnConnectCompletedOnIO,
124       this, success, event));
125 }
126 
OnConnectCompletedOnIO(bool * success,base::WaitableEvent * event,int error)127 void SyncWebSocketImpl::Core::OnConnectCompletedOnIO(
128     bool* success,
129     base::WaitableEvent* event,
130     int error) {
131   *success = (error == net::OK);
132   if (*success) {
133     base::AutoLock lock(lock_);
134     is_connected_ = true;
135   }
136   event->Signal();
137 }
138 
SendOnIO(const std::string & message,bool * success,base::WaitableEvent * event)139 void SyncWebSocketImpl::Core::SendOnIO(
140     const std::string& message,
141     bool* success,
142     base::WaitableEvent* event) {
143   *success = socket_->Send(message);
144   event->Signal();
145 }
146 
OnDestruct() const147 void SyncWebSocketImpl::Core::OnDestruct() const {
148   scoped_refptr<base::SingleThreadTaskRunner> network_task_runner =
149       context_getter_->GetNetworkTaskRunner();
150   if (network_task_runner->BelongsToCurrentThread())
151     delete this;
152   else
153     network_task_runner->DeleteSoon(FROM_HERE, this);
154 }
155