1// Copyright 2014 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// An implementation of WebSocketStreamHandle. 6 7#include "content/child/web_socket_stream_handle_impl.h" 8 9#include <vector> 10 11#include "base/compiler_specific.h" 12#include "base/logging.h" 13#include "base/memory/ref_counted.h" 14#include "base/memory/scoped_ptr.h" 15#include "base/strings/string16.h" 16#include "content/child/child_thread.h" 17#include "content/child/socket_stream_dispatcher.h" 18#include "content/child/web_socket_stream_handle_bridge.h" 19#include "content/child/web_socket_stream_handle_delegate.h" 20#include "third_party/WebKit/public/platform/WebData.h" 21#include "third_party/WebKit/public/platform/WebSocketStreamError.h" 22#include "third_party/WebKit/public/platform/WebSocketStreamHandleClient.h" 23#include "third_party/WebKit/public/platform/WebURL.h" 24 25using blink::WebData; 26using blink::WebSocketStreamError; 27using blink::WebSocketStreamHandle; 28using blink::WebSocketStreamHandleClient; 29using blink::WebURL; 30 31namespace content { 32 33// WebSocketStreamHandleImpl::Context ----------------------------------------- 34 35class WebSocketStreamHandleImpl::Context 36 : public base::RefCounted<Context>, 37 public WebSocketStreamHandleDelegate { 38 public: 39 explicit Context(WebSocketStreamHandleImpl* handle); 40 41 WebSocketStreamHandleClient* client() const { return client_; } 42 void set_client(WebSocketStreamHandleClient* client) { 43 client_ = client; 44 } 45 46 void Connect(const WebURL& url); 47 bool Send(const WebData& data); 48 void Close(); 49 50 // Must be called before |handle_| or |client_| is deleted. 51 // Once detached, it never calls |client_| back. 52 void Detach(); 53 54 // WebSocketStreamHandleDelegate methods: 55 virtual void DidOpenStream(WebSocketStreamHandle*, int) OVERRIDE; 56 virtual void DidSendData(WebSocketStreamHandle*, int) OVERRIDE; 57 virtual void DidReceiveData(WebSocketStreamHandle*, 58 const char*, 59 int) OVERRIDE; 60 virtual void DidClose(WebSocketStreamHandle*) OVERRIDE; 61 virtual void DidFail(WebSocketStreamHandle*, 62 int, 63 const base::string16&) OVERRIDE; 64 65 private: 66 friend class base::RefCounted<Context>; 67 virtual ~Context() { 68 DCHECK(!handle_); 69 DCHECK(!client_); 70 DCHECK(!bridge_.get()); 71 } 72 73 WebSocketStreamHandleImpl* handle_; 74 WebSocketStreamHandleClient* client_; 75 // |bridge_| is alive from Connect to DidClose, so Context must be alive 76 // in the time period. 77 scoped_refptr<WebSocketStreamHandleBridge> bridge_; 78 79 DISALLOW_COPY_AND_ASSIGN(Context); 80}; 81 82WebSocketStreamHandleImpl::Context::Context(WebSocketStreamHandleImpl* handle) 83 : handle_(handle), 84 client_(NULL) { 85} 86 87void WebSocketStreamHandleImpl::Context::Connect(const WebURL& url) { 88 VLOG(1) << "Connect url=" << url; 89 DCHECK(!bridge_.get()); 90 91 SocketStreamDispatcher* dispatcher = 92 ChildThread::current()->socket_stream_dispatcher(); 93 bridge_ = dispatcher->CreateBridge(handle_, this); 94 95 AddRef(); // Will be released by DidClose(). 96 bridge_->Connect(url); 97} 98 99bool WebSocketStreamHandleImpl::Context::Send(const WebData& data) { 100 VLOG(1) << "Send data.size=" << data.size(); 101 DCHECK(bridge_.get()); 102 return bridge_->Send( 103 std::vector<char>(data.data(), data.data() + data.size())); 104} 105 106void WebSocketStreamHandleImpl::Context::Close() { 107 VLOG(1) << "Close"; 108 if (bridge_.get()) 109 bridge_->Close(); 110} 111 112void WebSocketStreamHandleImpl::Context::Detach() { 113 handle_ = NULL; 114 client_ = NULL; 115 // If Connect was called, |bridge_| is not NULL, so that this Context closes 116 // the |bridge_| here. Then |bridge_| will call back DidClose, and will 117 // be released by itself. 118 // Otherwise, |bridge_| is NULL. 119 if (bridge_.get()) 120 bridge_->Close(); 121} 122 123void WebSocketStreamHandleImpl::Context::DidOpenStream( 124 WebSocketStreamHandle* web_handle, int max_amount_send_allowed) { 125 VLOG(1) << "DidOpen"; 126 if (client_) 127 client_->didOpenStream(handle_, max_amount_send_allowed); 128} 129 130void WebSocketStreamHandleImpl::Context::DidSendData( 131 WebSocketStreamHandle* web_handle, int amount_sent) { 132 if (client_) 133 client_->didSendData(handle_, amount_sent); 134} 135 136void WebSocketStreamHandleImpl::Context::DidReceiveData( 137 WebSocketStreamHandle* web_handle, const char* data, int size) { 138 if (client_) 139 client_->didReceiveData(handle_, WebData(data, size)); 140} 141 142void WebSocketStreamHandleImpl::Context::DidClose( 143 WebSocketStreamHandle* web_handle) { 144 VLOG(1) << "DidClose"; 145 bridge_ = NULL; 146 WebSocketStreamHandleImpl* handle = handle_; 147 handle_ = NULL; 148 if (client_) { 149 WebSocketStreamHandleClient* client = client_; 150 client_ = NULL; 151 client->didClose(handle); 152 } 153 Release(); 154} 155 156void WebSocketStreamHandleImpl::Context::DidFail( 157 WebSocketStreamHandle* web_handle, 158 int error_code, 159 const base::string16& error_msg) { 160 VLOG(1) << "DidFail"; 161 if (client_) { 162 client_->didFail( 163 handle_, 164 WebSocketStreamError(error_code, error_msg)); 165 } 166} 167 168// WebSocketStreamHandleImpl ------------------------------------------------ 169 170WebSocketStreamHandleImpl::WebSocketStreamHandleImpl() 171 : context_(new Context(this)) { 172} 173 174WebSocketStreamHandleImpl::~WebSocketStreamHandleImpl() { 175 // We won't receive any events from |context_|. 176 // |context_| is ref counted, and will be released when it received 177 // DidClose. 178 context_->Detach(); 179} 180 181void WebSocketStreamHandleImpl::connect( 182 const WebURL& url, WebSocketStreamHandleClient* client) { 183 VLOG(1) << "connect url=" << url; 184 DCHECK(!context_->client()); 185 context_->set_client(client); 186 187 context_->Connect(url); 188} 189 190bool WebSocketStreamHandleImpl::send(const WebData& data) { 191 return context_->Send(data); 192} 193 194void WebSocketStreamHandleImpl::close() { 195 context_->Close(); 196} 197 198} // namespace content 199