1/* 2 * Copyright (C) 2011 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32#if ENABLE(WEB_SOCKETS) 33#include "ThreadableWebSocketChannelClientWrapper.h" 34 35#include "CrossThreadTask.h" 36#include "ScriptExecutionContext.h" 37#include "WebSocketChannelClient.h" 38#include <wtf/PassRefPtr.h> 39#include <wtf/RefPtr.h> 40#include <wtf/text/StringView.h> 41 42namespace WebCore { 43 44ThreadableWebSocketChannelClientWrapper::ThreadableWebSocketChannelClientWrapper(ScriptExecutionContext* context, WebSocketChannelClient* client) 45 : m_context(context) 46 , m_client(client) 47 , m_peer(0) 48 , m_failedWebSocketChannelCreation(false) 49 , m_syncMethodDone(true) 50 , m_sendRequestResult(ThreadableWebSocketChannel::SendFail) 51 , m_bufferedAmount(0) 52 , m_suspended(false) 53{ 54} 55 56PassRefPtr<ThreadableWebSocketChannelClientWrapper> ThreadableWebSocketChannelClientWrapper::create(ScriptExecutionContext* context, WebSocketChannelClient* client) 57{ 58 return adoptRef(new ThreadableWebSocketChannelClientWrapper(context, client)); 59} 60 61void ThreadableWebSocketChannelClientWrapper::clearSyncMethodDone() 62{ 63 m_syncMethodDone = false; 64} 65 66void ThreadableWebSocketChannelClientWrapper::setSyncMethodDone() 67{ 68 m_syncMethodDone = true; 69} 70 71bool ThreadableWebSocketChannelClientWrapper::syncMethodDone() const 72{ 73 return m_syncMethodDone; 74} 75 76WorkerThreadableWebSocketChannel::Peer* ThreadableWebSocketChannelClientWrapper::peer() const 77{ 78 return m_peer; 79} 80 81void ThreadableWebSocketChannelClientWrapper::didCreateWebSocketChannel(WorkerThreadableWebSocketChannel::Peer* peer) 82{ 83 m_peer = peer; 84 m_syncMethodDone = true; 85} 86 87void ThreadableWebSocketChannelClientWrapper::clearPeer() 88{ 89 m_peer = 0; 90} 91 92bool ThreadableWebSocketChannelClientWrapper::failedWebSocketChannelCreation() const 93{ 94 return m_failedWebSocketChannelCreation; 95} 96 97void ThreadableWebSocketChannelClientWrapper::setFailedWebSocketChannelCreation() 98{ 99 m_failedWebSocketChannelCreation = true; 100} 101 102String ThreadableWebSocketChannelClientWrapper::subprotocol() const 103{ 104 if (m_subprotocol.isEmpty()) 105 return emptyString(); 106 return String(m_subprotocol); 107} 108 109void ThreadableWebSocketChannelClientWrapper::setSubprotocol(const String& subprotocol) 110{ 111 unsigned length = subprotocol.length(); 112 m_subprotocol.resize(length); 113 StringView(subprotocol).getCharactersWithUpconvert(m_subprotocol.data()); 114} 115 116String ThreadableWebSocketChannelClientWrapper::extensions() const 117{ 118 if (m_extensions.isEmpty()) 119 return emptyString(); 120 return String(m_extensions); 121} 122 123void ThreadableWebSocketChannelClientWrapper::setExtensions(const String& extensions) 124{ 125 unsigned length = extensions.length(); 126 m_extensions.resize(length); 127 StringView(extensions).getCharactersWithUpconvert(m_extensions.data()); 128} 129 130ThreadableWebSocketChannel::SendResult ThreadableWebSocketChannelClientWrapper::sendRequestResult() const 131{ 132 return m_sendRequestResult; 133} 134 135void ThreadableWebSocketChannelClientWrapper::setSendRequestResult(ThreadableWebSocketChannel::SendResult sendRequestResult) 136{ 137 m_sendRequestResult = sendRequestResult; 138 m_syncMethodDone = true; 139} 140 141unsigned long ThreadableWebSocketChannelClientWrapper::bufferedAmount() const 142{ 143 return m_bufferedAmount; 144} 145 146void ThreadableWebSocketChannelClientWrapper::setBufferedAmount(unsigned long bufferedAmount) 147{ 148 m_bufferedAmount = bufferedAmount; 149 m_syncMethodDone = true; 150} 151 152void ThreadableWebSocketChannelClientWrapper::clearClient() 153{ 154 m_client = 0; 155} 156 157void ThreadableWebSocketChannelClientWrapper::didConnect() 158{ 159 m_pendingTasks.append(std::make_unique<CrossThreadTask>(&didConnectCallback, this)); 160 if (!m_suspended) 161 processPendingTasks(); 162} 163 164void ThreadableWebSocketChannelClientWrapper::didReceiveMessage(const String& message) 165{ 166 m_pendingTasks.append(std::make_unique<CrossThreadTask>(&didReceiveMessageCallback, this, message)); 167 if (!m_suspended) 168 processPendingTasks(); 169} 170 171void ThreadableWebSocketChannelClientWrapper::didReceiveBinaryData(PassOwnPtr<Vector<char>> binaryData) 172{ 173 m_pendingTasks.append(std::make_unique<CrossThreadTask>(&didReceiveBinaryDataCallback, this, binaryData)); 174 if (!m_suspended) 175 processPendingTasks(); 176} 177 178void ThreadableWebSocketChannelClientWrapper::didUpdateBufferedAmount(unsigned long bufferedAmount) 179{ 180 m_pendingTasks.append(std::make_unique<CrossThreadTask>(&didUpdateBufferedAmountCallback, this, bufferedAmount)); 181 if (!m_suspended) 182 processPendingTasks(); 183} 184 185void ThreadableWebSocketChannelClientWrapper::didStartClosingHandshake() 186{ 187 m_pendingTasks.append(std::make_unique<CrossThreadTask>(&didStartClosingHandshakeCallback, this)); 188 if (!m_suspended) 189 processPendingTasks(); 190} 191 192void ThreadableWebSocketChannelClientWrapper::didClose(unsigned long unhandledBufferedAmount, WebSocketChannelClient::ClosingHandshakeCompletionStatus closingHandshakeCompletion, unsigned short code, const String& reason) 193{ 194 m_pendingTasks.append(std::make_unique<CrossThreadTask>(&didCloseCallback, this, unhandledBufferedAmount, closingHandshakeCompletion, code, reason)); 195 if (!m_suspended) 196 processPendingTasks(); 197} 198 199void ThreadableWebSocketChannelClientWrapper::didReceiveMessageError() 200{ 201 m_pendingTasks.append(std::make_unique<CrossThreadTask>(&didReceiveMessageErrorCallback, this)); 202 if (!m_suspended) 203 processPendingTasks(); 204} 205 206void ThreadableWebSocketChannelClientWrapper::suspend() 207{ 208 m_suspended = true; 209} 210 211void ThreadableWebSocketChannelClientWrapper::resume() 212{ 213 m_suspended = false; 214 processPendingTasks(); 215} 216 217void ThreadableWebSocketChannelClientWrapper::processPendingTasksCallback(ScriptExecutionContext& context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> wrapper) 218{ 219 ASSERT_UNUSED(context, context.isWorkerGlobalScope()); 220 wrapper->processPendingTasks(); 221} 222 223void ThreadableWebSocketChannelClientWrapper::processPendingTasks() 224{ 225 if (m_suspended) 226 return; 227 if (!m_syncMethodDone) { 228 // When a synchronous operation is in progress (i.e. the execution stack contains 229 // WorkerThreadableWebSocketChannel::waitForMethodCompletion()), we cannot invoke callbacks in this run loop. 230 m_context->postTask(CrossThreadTask(&ThreadableWebSocketChannelClientWrapper::processPendingTasksCallback, this)); 231 return; 232 } 233 234 Vector<std::unique_ptr<ScriptExecutionContext::Task>> pendingTasks = WTF::move(m_pendingTasks); 235 for (auto& task : pendingTasks) 236 task->performTask(*m_context); 237} 238 239void ThreadableWebSocketChannelClientWrapper::didConnectCallback(ScriptExecutionContext& context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> wrapper) 240{ 241 UNUSED_PARAM(context); 242 if (wrapper->m_client) 243 wrapper->m_client->didConnect(); 244} 245 246void ThreadableWebSocketChannelClientWrapper::didReceiveMessageCallback(ScriptExecutionContext& context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> wrapper, const String& message) 247{ 248 UNUSED_PARAM(context); 249 if (wrapper->m_client) 250 wrapper->m_client->didReceiveMessage(message); 251} 252 253void ThreadableWebSocketChannelClientWrapper::didReceiveBinaryDataCallback(ScriptExecutionContext& context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> wrapper, PassOwnPtr<Vector<char>> binaryData) 254{ 255 UNUSED_PARAM(context); 256 if (wrapper->m_client) 257 wrapper->m_client->didReceiveBinaryData(binaryData); 258} 259 260void ThreadableWebSocketChannelClientWrapper::didUpdateBufferedAmountCallback(ScriptExecutionContext& context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> wrapper, unsigned long bufferedAmount) 261{ 262 UNUSED_PARAM(context); 263 if (wrapper->m_client) 264 wrapper->m_client->didUpdateBufferedAmount(bufferedAmount); 265} 266 267void ThreadableWebSocketChannelClientWrapper::didStartClosingHandshakeCallback(ScriptExecutionContext& context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> wrapper) 268{ 269 UNUSED_PARAM(context); 270 if (wrapper->m_client) 271 wrapper->m_client->didStartClosingHandshake(); 272} 273 274void ThreadableWebSocketChannelClientWrapper::didCloseCallback(ScriptExecutionContext& context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> wrapper, unsigned long unhandledBufferedAmount, WebSocketChannelClient::ClosingHandshakeCompletionStatus closingHandshakeCompletion, unsigned short code, const String& reason) 275{ 276 UNUSED_PARAM(context); 277 if (wrapper->m_client) 278 wrapper->m_client->didClose(unhandledBufferedAmount, closingHandshakeCompletion, code, reason); 279} 280 281void ThreadableWebSocketChannelClientWrapper::didReceiveMessageErrorCallback(ScriptExecutionContext& context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> wrapper) 282{ 283 UNUSED_PARAM(context); 284 if (wrapper->m_client) 285 wrapper->m_client->didReceiveMessageError(); 286} 287 288} // namespace WebCore 289 290#endif 291