1 // Copyright (c) 2011 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 "webkit/glue/websocketstreamhandle_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 "third_party/WebKit/Source/WebKit/chromium/public/WebData.h" 16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebURL.h" 17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSocketStreamHandleClient.h" 18 #include "webkit/glue/websocketstreamhandle_bridge.h" 19 #include "webkit/glue/websocketstreamhandle_delegate.h" 20 21 namespace webkit_glue { 22 23 // WebSocketStreamHandleImpl::Context ----------------------------------------- 24 25 class WebSocketStreamHandleImpl::Context 26 : public base::RefCounted<Context>, 27 public WebSocketStreamHandleDelegate { 28 public: 29 explicit Context(WebSocketStreamHandleImpl* handle); 30 31 WebKit::WebSocketStreamHandleClient* client() const { return client_; } 32 void set_client(WebKit::WebSocketStreamHandleClient* client) { 33 client_ = client; 34 } 35 36 void Connect(const WebKit::WebURL& url); 37 bool Send(const WebKit::WebData& data); 38 void Close(); 39 40 // Must be called before |handle_| or |client_| is deleted. 41 // Once detached, it never calls |client_| back. 42 void Detach(); 43 44 // WebSocketStreamHandleDelegate methods: 45 virtual void DidOpenStream(WebKit::WebSocketStreamHandle*, int); 46 virtual void DidSendData(WebKit::WebSocketStreamHandle*, int); 47 virtual void DidReceiveData( 48 WebKit::WebSocketStreamHandle*, const char*, int); 49 virtual void DidClose(WebKit::WebSocketStreamHandle*); 50 51 private: 52 friend class base::RefCounted<Context>; 53 ~Context() { 54 DCHECK(!handle_); 55 DCHECK(!client_); 56 DCHECK(!bridge_); 57 } 58 59 WebSocketStreamHandleImpl* handle_; 60 WebKit::WebSocketStreamHandleClient* client_; 61 // |bridge_| is alive from Connect to DidClose, so Context must be alive 62 // in the time period. 63 scoped_refptr<WebSocketStreamHandleBridge> bridge_; 64 65 DISALLOW_COPY_AND_ASSIGN(Context); 66 }; 67 68 WebSocketStreamHandleImpl::Context::Context(WebSocketStreamHandleImpl* handle) 69 : handle_(handle), 70 client_(NULL), 71 bridge_(NULL) { 72 } 73 74 void WebSocketStreamHandleImpl::Context::Connect(const WebKit::WebURL& url) { 75 VLOG(1) << "Connect url=" << url; 76 DCHECK(!bridge_); 77 bridge_ = WebSocketStreamHandleBridge::Create(handle_, this); 78 AddRef(); // Will be released by DidClose(). 79 bridge_->Connect(url); 80 } 81 82 bool WebSocketStreamHandleImpl::Context::Send(const WebKit::WebData& data) { 83 VLOG(1) << "Send data.size=" << data.size(); 84 DCHECK(bridge_); 85 return bridge_->Send( 86 std::vector<char>(data.data(), data.data() + data.size())); 87 } 88 89 void WebSocketStreamHandleImpl::Context::Close() { 90 VLOG(1) << "Close"; 91 if (bridge_) 92 bridge_->Close(); 93 } 94 95 void WebSocketStreamHandleImpl::Context::Detach() { 96 handle_ = NULL; 97 client_ = NULL; 98 // If Connect was called, |bridge_| is not NULL, so that this Context closes 99 // the |bridge_| here. Then |bridge_| will call back DidClose, and will 100 // be released by itself. 101 // Otherwise, |bridge_| is NULL. 102 if (bridge_) 103 bridge_->Close(); 104 } 105 106 void WebSocketStreamHandleImpl::Context::DidOpenStream( 107 WebKit::WebSocketStreamHandle* web_handle, int max_amount_send_allowed) { 108 VLOG(1) << "DidOpen"; 109 if (client_) 110 client_->didOpenStream(handle_, max_amount_send_allowed); 111 } 112 113 void WebSocketStreamHandleImpl::Context::DidSendData( 114 WebKit::WebSocketStreamHandle* web_handle, int amount_sent) { 115 if (client_) 116 client_->didSendData(handle_, amount_sent); 117 } 118 119 void WebSocketStreamHandleImpl::Context::DidReceiveData( 120 WebKit::WebSocketStreamHandle* web_handle, const char* data, int size) { 121 if (client_) 122 client_->didReceiveData(handle_, WebKit::WebData(data, size)); 123 } 124 125 void WebSocketStreamHandleImpl::Context::DidClose( 126 WebKit::WebSocketStreamHandle* web_handle) { 127 VLOG(1) << "DidClose"; 128 bridge_ = NULL; 129 WebSocketStreamHandleImpl* handle = handle_; 130 handle_ = NULL; 131 if (client_) { 132 WebKit::WebSocketStreamHandleClient* client = client_; 133 client_ = NULL; 134 client->didClose(handle); 135 } 136 Release(); 137 } 138 139 // WebSocketStreamHandleImpl ------------------------------------------------ 140 141 WebSocketStreamHandleImpl::WebSocketStreamHandleImpl() 142 : ALLOW_THIS_IN_INITIALIZER_LIST(context_(new Context(this))) { 143 } 144 145 WebSocketStreamHandleImpl::~WebSocketStreamHandleImpl() { 146 // We won't receive any events from |context_|. 147 // |context_| is ref counted, and will be released when it received 148 // DidClose. 149 context_->Detach(); 150 } 151 152 void WebSocketStreamHandleImpl::connect( 153 const WebKit::WebURL& url, WebKit::WebSocketStreamHandleClient* client) { 154 VLOG(1) << "connect url=" << url; 155 DCHECK(!context_->client()); 156 context_->set_client(client); 157 158 context_->Connect(url); 159 } 160 161 bool WebSocketStreamHandleImpl::send(const WebKit::WebData& data) { 162 return context_->Send(data); 163 } 164 165 void WebSocketStreamHandleImpl::close() { 166 context_->Close(); 167 } 168 169 } // namespace webkit_glue 170