12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/test/chromedriver/net/sync_websocket_impl.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/callback.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/location.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/single_thread_task_runner.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/synchronization/waitable_event.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/net_errors.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/url_request/url_request_context_getter.h"
147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SyncWebSocketImpl::SyncWebSocketImpl(
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net::URLRequestContextGetter* context_getter)
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : core_(new Core(context_getter)) {}
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SyncWebSocketImpl::~SyncWebSocketImpl() {}
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SyncWebSocketImpl::IsConnected() {
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return core_->IsConnected();
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SyncWebSocketImpl::Connect(const GURL& url) {
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return core_->Connect(url);
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SyncWebSocketImpl::Send(const std::string& message) {
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return core_->Send(message);
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)SyncWebSocket::StatusCode SyncWebSocketImpl::ReceiveNextMessage(
35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    std::string* message, const base::TimeDelta& timeout) {
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return core_->ReceiveNextMessage(message, timeout);
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SyncWebSocketImpl::HasNextMessage() {
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return core_->HasNextMessage();
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SyncWebSocketImpl::Core::Core(net::URLRequestContextGetter* context_getter)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : context_getter_(context_getter),
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      is_connected_(false),
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      on_update_event_(&lock_) {}
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SyncWebSocketImpl::Core::IsConnected() {
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AutoLock lock(lock_);
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return is_connected_;
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SyncWebSocketImpl::Core::Connect(const GURL& url) {
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool success = false;
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::WaitableEvent event(false, false);
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  context_getter_->GetNetworkTaskRunner()->PostTask(
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&SyncWebSocketImpl::Core::ConnectOnIO,
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 this, url, &success, &event));
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  event.Wait();
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return success;
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SyncWebSocketImpl::Core::Send(const std::string& message) {
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool success = false;
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::WaitableEvent event(false, false);
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  context_getter_->GetNetworkTaskRunner()->PostTask(
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&SyncWebSocketImpl::Core::SendOnIO,
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 this, message, &success, &event));
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  event.Wait();
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return success;
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
75424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)SyncWebSocket::StatusCode SyncWebSocketImpl::Core::ReceiveNextMessage(
76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    std::string* message,
77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const base::TimeDelta& timeout) {
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AutoLock lock(lock_);
79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::TimeTicks deadline = base::TimeTicks::Now() + timeout;
80424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  base::TimeDelta next_wait = timeout;
81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  while (received_queue_.empty() && is_connected_) {
82424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (next_wait <= base::TimeDelta())
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return SyncWebSocket::kTimeout;
84424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    on_update_event_.TimedWait(next_wait);
85424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    next_wait = deadline - base::TimeTicks::Now();
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!is_connected_)
88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return SyncWebSocket::kDisconnected;
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *message = received_queue_.front();
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  received_queue_.pop_front();
91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return SyncWebSocket::kOk;
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SyncWebSocketImpl::Core::HasNextMessage() {
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AutoLock lock(lock_);
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !received_queue_.empty();
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncWebSocketImpl::Core::OnMessageReceived(const std::string& message) {
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AutoLock lock(lock_);
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  received_queue_.push_back(message);
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  on_update_event_.Signal();
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncWebSocketImpl::Core::OnClose() {
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AutoLock lock(lock_);
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  is_connected_ = false;
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  on_update_event_.Signal();
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SyncWebSocketImpl::Core::~Core() { }
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncWebSocketImpl::Core::ConnectOnIO(
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& url,
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool* success,
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::WaitableEvent* event) {
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::AutoLock lock(lock_);
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    received_queue_.clear();
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  socket_.reset(new WebSocket(url, this));
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  socket_->Connect(base::Bind(
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &SyncWebSocketImpl::Core::OnConnectCompletedOnIO,
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this, success, event));
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncWebSocketImpl::Core::OnConnectCompletedOnIO(
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool* success,
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::WaitableEvent* event,
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int error) {
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *success = (error == net::OK);
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (*success) {
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::AutoLock lock(lock_);
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    is_connected_ = true;
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  event->Signal();
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncWebSocketImpl::Core::SendOnIO(
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& message,
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool* success,
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::WaitableEvent* event) {
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *success = socket_->Send(message);
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  event->Signal();
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncWebSocketImpl::Core::OnDestruct() const {
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<base::SingleThreadTaskRunner> network_task_runner =
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      context_getter_->GetNetworkTaskRunner();
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (network_task_runner->BelongsToCurrentThread())
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delete this;
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    network_task_runner->DeleteSoon(FROM_HERE, this);
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
155