| // Copyright (c) 2011 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 <vector> |
| |
| #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/WebKit/chromium/public/WebData.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebURL.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebSocketStreamHandleClient.h" |
| #include "webkit/glue/websocketstreamhandle_bridge.h" |
| #include "webkit/glue/websocketstreamhandle_delegate.h" |
| |
| namespace webkit_glue { |
| |
| // WebSocketStreamHandleImpl::Context ----------------------------------------- |
| |
| class WebSocketStreamHandleImpl::Context |
| : public base::RefCounted<Context>, |
| public WebSocketStreamHandleDelegate { |
| public: |
| explicit Context(WebSocketStreamHandleImpl* handle); |
| |
| WebKit::WebSocketStreamHandleClient* client() const { return client_; } |
| void set_client(WebKit::WebSocketStreamHandleClient* client) { |
| client_ = client; |
| } |
| |
| void Connect(const WebKit::WebURL& url); |
| bool Send(const WebKit::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(WebKit::WebSocketStreamHandle*, int); |
| virtual void DidSendData(WebKit::WebSocketStreamHandle*, int); |
| virtual void DidReceiveData( |
| WebKit::WebSocketStreamHandle*, const char*, int); |
| virtual void DidClose(WebKit::WebSocketStreamHandle*); |
| |
| private: |
| friend class base::RefCounted<Context>; |
| ~Context() { |
| DCHECK(!handle_); |
| DCHECK(!client_); |
| DCHECK(!bridge_); |
| } |
| |
| WebSocketStreamHandleImpl* handle_; |
| WebKit::WebSocketStreamHandleClient* client_; |
| // |bridge_| is alive from Connect to DidClose, so Context must be alive |
| // in the time period. |
| scoped_refptr<WebSocketStreamHandleBridge> bridge_; |
| |
| DISALLOW_COPY_AND_ASSIGN(Context); |
| }; |
| |
| WebSocketStreamHandleImpl::Context::Context(WebSocketStreamHandleImpl* handle) |
| : handle_(handle), |
| client_(NULL), |
| bridge_(NULL) { |
| } |
| |
| void WebSocketStreamHandleImpl::Context::Connect(const WebKit::WebURL& url) { |
| VLOG(1) << "Connect url=" << url; |
| DCHECK(!bridge_); |
| bridge_ = WebSocketStreamHandleBridge::Create(handle_, this); |
| AddRef(); // Will be released by DidClose(). |
| bridge_->Connect(url); |
| } |
| |
| bool WebSocketStreamHandleImpl::Context::Send(const WebKit::WebData& data) { |
| VLOG(1) << "Send data.size=" << data.size(); |
| DCHECK(bridge_); |
| return bridge_->Send( |
| std::vector<char>(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( |
| WebKit::WebSocketStreamHandle* web_handle, int max_amount_send_allowed) { |
| VLOG(1) << "DidOpen"; |
| if (client_) |
| client_->didOpenStream(handle_, max_amount_send_allowed); |
| } |
| |
| void WebSocketStreamHandleImpl::Context::DidSendData( |
| WebKit::WebSocketStreamHandle* web_handle, int amount_sent) { |
| if (client_) |
| client_->didSendData(handle_, amount_sent); |
| } |
| |
| void WebSocketStreamHandleImpl::Context::DidReceiveData( |
| WebKit::WebSocketStreamHandle* web_handle, const char* data, int size) { |
| if (client_) |
| client_->didReceiveData(handle_, WebKit::WebData(data, size)); |
| } |
| |
| void WebSocketStreamHandleImpl::Context::DidClose( |
| WebKit::WebSocketStreamHandle* web_handle) { |
| VLOG(1) << "DidClose"; |
| bridge_ = NULL; |
| WebSocketStreamHandleImpl* handle = handle_; |
| handle_ = NULL; |
| if (client_) { |
| WebKit::WebSocketStreamHandleClient* client = client_; |
| client_ = NULL; |
| client->didClose(handle); |
| } |
| Release(); |
| } |
| |
| // WebSocketStreamHandleImpl ------------------------------------------------ |
| |
| WebSocketStreamHandleImpl::WebSocketStreamHandleImpl() |
| : ALLOW_THIS_IN_INITIALIZER_LIST(context_(new Context(this))) { |
| } |
| |
| 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 WebKit::WebURL& url, WebKit::WebSocketStreamHandleClient* client) { |
| VLOG(1) << "connect url=" << url; |
| DCHECK(!context_->client()); |
| context_->set_client(client); |
| |
| context_->Connect(url); |
| } |
| |
| bool WebSocketStreamHandleImpl::send(const WebKit::WebData& data) { |
| return context_->Send(data); |
| } |
| |
| void WebSocketStreamHandleImpl::close() { |
| context_->Close(); |
| } |
| |
| } // namespace webkit_glue |