| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 #include "webkit/support/simple_socket_stream_bridge.h" | |
| 6 | |
| 7 #include <vector> | |
| 8 | |
| 9 #include "base/atomicops.h" | |
| 10 #include "base/bind.h" | |
| 11 #include "base/memory/ref_counted.h" | |
| 12 #include "base/message_loop.h" | |
| 13 #include "base/strings/utf_string_conversions.h" | |
| 14 #include "googleurl/src/gurl.h" | |
| 15 #include "net/socket_stream/socket_stream_job.h" | |
| 16 #include "net/url_request/url_request_context.h" | |
| 17 #include "net/websockets/websocket_job.h" | |
| 18 #include "third_party/WebKit/public/platform/WebSocketStreamHandle.h" | |
| 19 #include "webkit/glue/websocketstreamhandle_bridge.h" | |
| 20 #include "webkit/glue/websocketstreamhandle_delegate.h" | |
| 21 | |
| 22 using webkit_glue::WebSocketStreamHandleBridge; | |
| 23 | |
| 24 const int kNoSocketId = 0; | |
| 25 | |
| 26 namespace { | |
| 27 | |
| 28 base::MessageLoop* g_io_thread; | |
| 29 net::URLRequestContext* g_request_context; | |
| 30 | |
| 31 class WebSocketStreamHandleBridgeImpl | |
| 32 : public WebSocketStreamHandleBridge, | |
| 33 public net::SocketStream::Delegate { | |
| 34 public: | |
| 35 WebSocketStreamHandleBridgeImpl( | |
| 36 WebKit::WebSocketStreamHandle* handle, | |
| 37 webkit_glue::WebSocketStreamHandleDelegate* delegate); | |
| 38 | |
| 39 // WebSocketStreamHandleBridge methods. | |
| 40 virtual void Connect(const GURL& url) OVERRIDE; | |
| 41 virtual bool Send(const std::vector<char>& data) OVERRIDE; | |
| 42 virtual void Close() OVERRIDE; | |
| 43 | |
| 44 // net::SocketStream::Delegate methods. | |
| 45 virtual void OnConnected(net::SocketStream* req, | |
| 46 int max_pending_send_allowed) OVERRIDE; | |
| 47 virtual void OnSentData(net::SocketStream* req, | |
| 48 int amount_sent) OVERRIDE; | |
| 49 virtual void OnReceivedData(net::SocketStream* req, | |
| 50 const char* data, int len) OVERRIDE; | |
| 51 virtual void OnClose(net::SocketStream* req) OVERRIDE; | |
| 52 virtual void OnError(const net::SocketStream* req, int error_code) OVERRIDE; | |
| 53 | |
| 54 private: | |
| 55 virtual ~WebSocketStreamHandleBridgeImpl(); | |
| 56 | |
| 57 // Runs on |g_io_thread|; | |
| 58 void DoConnect(const GURL& url); | |
| 59 void DoSend(std::vector<char>* data); | |
| 60 void DoClose(); | |
| 61 | |
| 62 // Runs on |message_loop_|; | |
| 63 void DoOnConnected(int max_amount_send_allowed); | |
| 64 void DoOnSentData(int amount_sent); | |
| 65 void DoOnReceivedData(std::vector<char>* data); | |
| 66 void DoOnClose(); | |
| 67 void DoOnError(int error_code, const char* error_msg); | |
| 68 | |
| 69 int socket_id_; | |
| 70 base::MessageLoop* message_loop_; | |
| 71 WebKit::WebSocketStreamHandle* handle_; | |
| 72 webkit_glue::WebSocketStreamHandleDelegate* delegate_; | |
| 73 | |
| 74 scoped_refptr<net::SocketStreamJob> socket_; | |
| 75 // Number of pending tasks to handle net::SocketStream::Delegate methods. | |
| 76 base::subtle::Atomic32 num_pending_tasks_; | |
| 77 | |
| 78 DISALLOW_COPY_AND_ASSIGN(WebSocketStreamHandleBridgeImpl); | |
| 79 }; | |
| 80 | |
| 81 WebSocketStreamHandleBridgeImpl::WebSocketStreamHandleBridgeImpl( | |
| 82 WebKit::WebSocketStreamHandle* handle, | |
| 83 webkit_glue::WebSocketStreamHandleDelegate* delegate) | |
| 84 : socket_id_(kNoSocketId), | |
| 85 message_loop_(base::MessageLoop::current()), | |
| 86 handle_(handle), | |
| 87 delegate_(delegate), | |
| 88 num_pending_tasks_(0) { | |
| 89 net::WebSocketJob::EnsureInit(); | |
| 90 } | |
| 91 | |
| 92 WebSocketStreamHandleBridgeImpl::~WebSocketStreamHandleBridgeImpl() { | |
| 93 DCHECK_EQ(socket_id_, kNoSocketId); | |
| 94 } | |
| 95 | |
| 96 void WebSocketStreamHandleBridgeImpl::Connect(const GURL& url) { | |
| 97 DCHECK(g_io_thread); | |
| 98 AddRef(); // Released in DoOnClose(). | |
| 99 g_io_thread->PostTask( | |
| 100 FROM_HERE, | |
| 101 base::Bind(&WebSocketStreamHandleBridgeImpl::DoConnect, this, url)); | |
| 102 if (delegate_) | |
| 103 delegate_->WillOpenStream(handle_, url); | |
| 104 } | |
| 105 | |
| 106 bool WebSocketStreamHandleBridgeImpl::Send( | |
| 107 const std::vector<char>& data) { | |
| 108 DCHECK(g_io_thread); | |
| 109 g_io_thread->PostTask( | |
| 110 FROM_HERE, | |
| 111 base::Bind(&WebSocketStreamHandleBridgeImpl::DoSend, this, | |
| 112 new std::vector<char>(data))); | |
| 113 return true; | |
| 114 } | |
| 115 | |
| 116 void WebSocketStreamHandleBridgeImpl::Close() { | |
| 117 DCHECK(g_io_thread); | |
| 118 g_io_thread->PostTask( | |
| 119 FROM_HERE, | |
| 120 base::Bind(&WebSocketStreamHandleBridgeImpl::DoClose, this)); | |
| 121 } | |
| 122 | |
| 123 void WebSocketStreamHandleBridgeImpl::OnConnected( | |
| 124 net::SocketStream* socket, int max_pending_send_allowed) { | |
| 125 base::subtle::NoBarrier_AtomicIncrement(&num_pending_tasks_, 1); | |
| 126 message_loop_->PostTask( | |
| 127 FROM_HERE, | |
| 128 base::Bind(&WebSocketStreamHandleBridgeImpl::DoOnConnected, this, | |
| 129 max_pending_send_allowed)); | |
| 130 } | |
| 131 | |
| 132 void WebSocketStreamHandleBridgeImpl::OnSentData( | |
| 133 net::SocketStream* socket, int amount_sent) { | |
| 134 base::subtle::NoBarrier_AtomicIncrement(&num_pending_tasks_, 1); | |
| 135 message_loop_->PostTask( | |
| 136 FROM_HERE, | |
| 137 base::Bind(&WebSocketStreamHandleBridgeImpl::DoOnSentData, this, | |
| 138 amount_sent)); | |
| 139 } | |
| 140 | |
| 141 void WebSocketStreamHandleBridgeImpl::OnReceivedData( | |
| 142 net::SocketStream* socket, const char* data, int len) { | |
| 143 base::subtle::NoBarrier_AtomicIncrement(&num_pending_tasks_, 1); | |
| 144 message_loop_->PostTask( | |
| 145 FROM_HERE, | |
| 146 base::Bind(&WebSocketStreamHandleBridgeImpl::DoOnReceivedData, this, | |
| 147 new std::vector<char>(data, data + len))); | |
| 148 } | |
| 149 | |
| 150 void WebSocketStreamHandleBridgeImpl::OnClose(net::SocketStream* socket) { | |
| 151 base::subtle::NoBarrier_AtomicIncrement(&num_pending_tasks_, 1); | |
| 152 // Release socket_ on IO thread. | |
| 153 socket_ = NULL; | |
| 154 socket_id_ = kNoSocketId; | |
| 155 message_loop_->PostTask( | |
| 156 FROM_HERE, | |
| 157 base::Bind(&WebSocketStreamHandleBridgeImpl::DoOnClose, this)); | |
| 158 } | |
| 159 | |
| 160 void WebSocketStreamHandleBridgeImpl::OnError( | |
| 161 const net::SocketStream* socket, int error_code) { | |
| 162 base::subtle::NoBarrier_AtomicIncrement(&num_pending_tasks_, 1); | |
| 163 message_loop_->PostTask( | |
| 164 FROM_HERE, | |
| 165 base::Bind(&WebSocketStreamHandleBridgeImpl::DoOnError, this, | |
| 166 error_code, net::ErrorToString(error_code))); | |
| 167 } | |
| 168 | |
| 169 void WebSocketStreamHandleBridgeImpl::DoConnect(const GURL& url) { | |
| 170 DCHECK(base::MessageLoop::current() == g_io_thread); | |
| 171 socket_ = net::SocketStreamJob::CreateSocketStreamJob( | |
| 172 url, this, g_request_context->transport_security_state(), | |
| 173 g_request_context->ssl_config_service()); | |
| 174 socket_->set_context(g_request_context); | |
| 175 socket_->Connect(); | |
| 176 } | |
| 177 | |
| 178 void WebSocketStreamHandleBridgeImpl::DoSend(std::vector<char>* data) { | |
| 179 DCHECK(base::MessageLoop::current() == g_io_thread); | |
| 180 scoped_ptr<std::vector<char> > scoped_data(data); | |
| 181 if (!socket_.get()) | |
| 182 return; | |
| 183 if (!socket_->SendData(&(data->at(0)), data->size())) | |
| 184 socket_->Close(); | |
| 185 } | |
| 186 | |
| 187 void WebSocketStreamHandleBridgeImpl::DoClose() { | |
| 188 DCHECK(base::MessageLoop::current() == g_io_thread); | |
| 189 if (!socket_.get()) | |
| 190 return; | |
| 191 socket_->Close(); | |
| 192 } | |
| 193 | |
| 194 void WebSocketStreamHandleBridgeImpl::DoOnConnected( | |
| 195 int max_pending_send_allowed) { | |
| 196 DCHECK(base::MessageLoop::current() == message_loop_); | |
| 197 base::subtle::NoBarrier_AtomicIncrement(&num_pending_tasks_, -1); | |
| 198 if (delegate_) | |
| 199 delegate_->DidOpenStream(handle_, max_pending_send_allowed); | |
| 200 } | |
| 201 | |
| 202 void WebSocketStreamHandleBridgeImpl::DoOnSentData(int amount_sent) { | |
| 203 DCHECK(base::MessageLoop::current() == message_loop_); | |
| 204 base::subtle::NoBarrier_AtomicIncrement(&num_pending_tasks_, -1); | |
| 205 if (delegate_) | |
| 206 delegate_->DidSendData(handle_, amount_sent); | |
| 207 } | |
| 208 | |
| 209 void WebSocketStreamHandleBridgeImpl::DoOnReceivedData( | |
| 210 std::vector<char>* data) { | |
| 211 DCHECK(base::MessageLoop::current() == message_loop_); | |
| 212 base::subtle::NoBarrier_AtomicIncrement(&num_pending_tasks_, -1); | |
| 213 scoped_ptr<std::vector<char> > scoped_data(data); | |
| 214 if (delegate_) | |
| 215 delegate_->DidReceiveData(handle_, &(data->at(0)), data->size()); | |
| 216 } | |
| 217 | |
| 218 void WebSocketStreamHandleBridgeImpl::DoOnClose() { | |
| 219 DCHECK(base::MessageLoop::current() == message_loop_); | |
| 220 base::subtle::NoBarrier_AtomicIncrement(&num_pending_tasks_, -1); | |
| 221 // Don't handle OnClose if there are pending tasks. | |
| 222 DCHECK_EQ(num_pending_tasks_, 0); | |
| 223 DCHECK(!socket_.get()); | |
| 224 DCHECK_EQ(socket_id_, kNoSocketId); | |
| 225 webkit_glue::WebSocketStreamHandleDelegate* delegate = delegate_; | |
| 226 delegate_ = NULL; | |
| 227 if (delegate) | |
| 228 delegate->DidClose(handle_); | |
| 229 Release(); | |
| 230 } | |
| 231 | |
| 232 void WebSocketStreamHandleBridgeImpl::DoOnError( | |
| 233 int error_code, const char* error_msg) { | |
| 234 DCHECK(base::MessageLoop::current() == message_loop_); | |
| 235 base::subtle::NoBarrier_AtomicIncrement(&num_pending_tasks_, -1); | |
| 236 if (delegate_) | |
| 237 delegate_->DidFail(handle_, error_code, ASCIIToUTF16(error_msg)); | |
| 238 } | |
| 239 | |
| 240 } // namespace | |
| 241 | |
| 242 /* static */ | |
| 243 void SimpleSocketStreamBridge::InitializeOnIOThread( | |
| 244 net::URLRequestContext* request_context) { | |
| 245 g_io_thread = base::MessageLoop::current(); | |
| 246 g_request_context = request_context; | |
| 247 } | |
| 248 | |
| 249 void SimpleSocketStreamBridge::Cleanup() { | |
| 250 g_io_thread = NULL; | |
| 251 g_request_context = NULL; | |
| 252 } | |
| 253 | |
| 254 /* static */ | |
| 255 webkit_glue::WebSocketStreamHandleBridge* SimpleSocketStreamBridge::Create( | |
| 256 WebKit::WebSocketStreamHandle* handle, | |
| 257 webkit_glue::WebSocketStreamHandleDelegate* delegate) { | |
| 258 return new WebSocketStreamHandleBridgeImpl(handle, delegate); | |
| 259 } | |
| OLD | NEW |