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 16 SyncWebSocketImpl::SyncWebSocketImpl( 17 net::URLRequestContextGetter* context_getter) 18 : core_(new Core(context_getter)) {} 19 20 SyncWebSocketImpl::~SyncWebSocketImpl() {} 21 22 bool SyncWebSocketImpl::IsConnected() { 23 return core_->IsConnected(); 24 } 25 26 bool SyncWebSocketImpl::Connect(const GURL& url) { 27 return core_->Connect(url); 28 } 29 30 bool SyncWebSocketImpl::Send(const std::string& message) { 31 return core_->Send(message); 32 } 33 34 SyncWebSocket::StatusCode SyncWebSocketImpl::ReceiveNextMessage( 35 std::string* message, const base::TimeDelta& timeout) { 36 return core_->ReceiveNextMessage(message, timeout); 37 } 38 39 bool SyncWebSocketImpl::HasNextMessage() { 40 return core_->HasNextMessage(); 41 } 42 43 SyncWebSocketImpl::Core::Core(net::URLRequestContextGetter* context_getter) 44 : context_getter_(context_getter), 45 is_connected_(false), 46 on_update_event_(&lock_) {} 47 48 bool SyncWebSocketImpl::Core::IsConnected() { 49 base::AutoLock lock(lock_); 50 return is_connected_; 51 } 52 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 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 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 94 bool SyncWebSocketImpl::Core::HasNextMessage() { 95 base::AutoLock lock(lock_); 96 return !received_queue_.empty(); 97 } 98 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 105 void SyncWebSocketImpl::Core::OnClose() { 106 base::AutoLock lock(lock_); 107 is_connected_ = false; 108 on_update_event_.Signal(); 109 } 110 111 SyncWebSocketImpl::Core::~Core() { } 112 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 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 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 147 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