// Copyright (c) 2012 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. // An implementation of WebSocketStreamHandle. #include "webkit/glue/websocketstreamhandle_impl.h" #include #include "base/compiler_specific.h" #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebData.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebSocketStreamHandleClient.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebURL.h" #include "webkit/glue/webkitplatformsupport_impl.h" #include "webkit/glue/websocketstreamhandle_bridge.h" #include "webkit/glue/websocketstreamhandle_delegate.h" using WebKit::WebData; using WebKit::WebSocketStreamHandle; using WebKit::WebSocketStreamHandleClient; using WebKit::WebURL; namespace webkit_glue { // WebSocketStreamHandleImpl::Context ----------------------------------------- class WebSocketStreamHandleImpl::Context : public base::RefCounted, public WebSocketStreamHandleDelegate { public: explicit Context(WebSocketStreamHandleImpl* handle); WebSocketStreamHandleClient* client() const { return client_; } void set_client(WebSocketStreamHandleClient* client) { client_ = client; } void Connect(const WebURL& url, WebKitPlatformSupportImpl* platform); bool Send(const WebData& data); void Close(); // Must be called before |handle_| or |client_| is deleted. // Once detached, it never calls |client_| back. void Detach(); // WebSocketStreamHandleDelegate methods: virtual void DidOpenStream(WebSocketStreamHandle*, int) OVERRIDE; virtual void DidSendData(WebSocketStreamHandle*, int) OVERRIDE; virtual void DidReceiveData(WebSocketStreamHandle*, const char*, int) OVERRIDE; virtual void DidClose(WebSocketStreamHandle*) OVERRIDE; private: friend class base::RefCounted; virtual ~Context() { DCHECK(!handle_); DCHECK(!client_); DCHECK(!bridge_); } WebSocketStreamHandleImpl* handle_; WebSocketStreamHandleClient* client_; // |bridge_| is alive from Connect to DidClose, so Context must be alive // in the time period. scoped_refptr bridge_; DISALLOW_COPY_AND_ASSIGN(Context); }; WebSocketStreamHandleImpl::Context::Context(WebSocketStreamHandleImpl* handle) : handle_(handle), client_(NULL), bridge_(NULL) { } void WebSocketStreamHandleImpl::Context::Connect( const WebURL& url, WebKitPlatformSupportImpl* platform) { VLOG(1) << "Connect url=" << url; DCHECK(!bridge_); bridge_ = platform->CreateWebSocketBridge(handle_, this); AddRef(); // Will be released by DidClose(). bridge_->Connect(url); } bool WebSocketStreamHandleImpl::Context::Send(const WebData& data) { VLOG(1) << "Send data.size=" << data.size(); DCHECK(bridge_); return bridge_->Send( std::vector(data.data(), data.data() + data.size())); } void WebSocketStreamHandleImpl::Context::Close() { VLOG(1) << "Close"; if (bridge_) bridge_->Close(); } void WebSocketStreamHandleImpl::Context::Detach() { handle_ = NULL; client_ = NULL; // If Connect was called, |bridge_| is not NULL, so that this Context closes // the |bridge_| here. Then |bridge_| will call back DidClose, and will // be released by itself. // Otherwise, |bridge_| is NULL. if (bridge_) bridge_->Close(); } void WebSocketStreamHandleImpl::Context::DidOpenStream( WebSocketStreamHandle* web_handle, int max_amount_send_allowed) { VLOG(1) << "DidOpen"; if (client_) client_->didOpenStream(handle_, max_amount_send_allowed); } void WebSocketStreamHandleImpl::Context::DidSendData( WebSocketStreamHandle* web_handle, int amount_sent) { if (client_) client_->didSendData(handle_, amount_sent); } void WebSocketStreamHandleImpl::Context::DidReceiveData( WebSocketStreamHandle* web_handle, const char* data, int size) { if (client_) client_->didReceiveData(handle_, WebData(data, size)); } void WebSocketStreamHandleImpl::Context::DidClose( WebSocketStreamHandle* web_handle) { VLOG(1) << "DidClose"; bridge_ = NULL; WebSocketStreamHandleImpl* handle = handle_; handle_ = NULL; if (client_) { WebSocketStreamHandleClient* client = client_; client_ = NULL; client->didClose(handle); } Release(); } // WebSocketStreamHandleImpl ------------------------------------------------ WebSocketStreamHandleImpl::WebSocketStreamHandleImpl( WebKitPlatformSupportImpl* platform) : ALLOW_THIS_IN_INITIALIZER_LIST(context_(new Context(this))), platform_(platform) { } WebSocketStreamHandleImpl::~WebSocketStreamHandleImpl() { // We won't receive any events from |context_|. // |context_| is ref counted, and will be released when it received // DidClose. context_->Detach(); } void WebSocketStreamHandleImpl::connect( const WebURL& url, WebSocketStreamHandleClient* client) { VLOG(1) << "connect url=" << url; DCHECK(!context_->client()); context_->set_client(client); context_->Connect(url, platform_); } bool WebSocketStreamHandleImpl::send(const WebData& data) { return context_->Send(data); } void WebSocketStreamHandleImpl::close() { context_->Close(); } } // namespace webkit_glue