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 #include "modules/websockets/ThreadableWebSocketChannelClientWrapper.h" 33 34 #include "core/dom/CrossThreadTask.h" 35 #include "core/dom/ScriptExecutionContext.h" 36 #include "core/platform/CrossThreadCopier.h" 37 #include "modules/websockets/WebSocketChannel.h" 38 #include "modules/websockets/WebSocketChannelClient.h" 39 #include "wtf/PassRefPtr.h" 40 #include "wtf/RefPtr.h" 41 42 namespace WebCore { 43 44 ThreadableWebSocketChannelClientWrapper::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(WebSocketChannel::SendFail) 51 , m_bufferedAmount(0) 52 , m_suspended(false) 53 { 54 } 55 56 PassRefPtr<ThreadableWebSocketChannelClientWrapper> ThreadableWebSocketChannelClientWrapper::create(ScriptExecutionContext* context, WebSocketChannelClient* client) 57 { 58 return adoptRef(new ThreadableWebSocketChannelClientWrapper(context, client)); 59 } 60 61 void ThreadableWebSocketChannelClientWrapper::clearSyncMethodDone() 62 { 63 m_syncMethodDone = false; 64 } 65 66 void ThreadableWebSocketChannelClientWrapper::setSyncMethodDone() 67 { 68 m_syncMethodDone = true; 69 } 70 71 bool ThreadableWebSocketChannelClientWrapper::syncMethodDone() const 72 { 73 return m_syncMethodDone; 74 } 75 76 WorkerThreadableWebSocketChannel::Peer* ThreadableWebSocketChannelClientWrapper::peer() const 77 { 78 return m_peer; 79 } 80 81 void ThreadableWebSocketChannelClientWrapper::didCreateWebSocketChannel(WorkerThreadableWebSocketChannel::Peer* peer) 82 { 83 m_peer = peer; 84 m_syncMethodDone = true; 85 } 86 87 void ThreadableWebSocketChannelClientWrapper::clearPeer() 88 { 89 m_peer = 0; 90 } 91 92 bool ThreadableWebSocketChannelClientWrapper::failedWebSocketChannelCreation() const 93 { 94 return m_failedWebSocketChannelCreation; 95 } 96 97 void ThreadableWebSocketChannelClientWrapper::setFailedWebSocketChannelCreation() 98 { 99 m_failedWebSocketChannelCreation = true; 100 } 101 102 String ThreadableWebSocketChannelClientWrapper::subprotocol() const 103 { 104 if (m_subprotocol.isEmpty()) 105 return emptyString(); 106 return String(m_subprotocol); 107 } 108 109 void ThreadableWebSocketChannelClientWrapper::setSubprotocol(const String& subprotocol) 110 { 111 m_subprotocol.clear(); 112 append(m_subprotocol, subprotocol); 113 } 114 115 String ThreadableWebSocketChannelClientWrapper::extensions() const 116 { 117 if (m_extensions.isEmpty()) 118 return emptyString(); 119 return String(m_extensions); 120 } 121 122 void ThreadableWebSocketChannelClientWrapper::setExtensions(const String& extensions) 123 { 124 m_extensions.clear(); 125 append(m_extensions, extensions); 126 } 127 128 WebSocketChannel::SendResult ThreadableWebSocketChannelClientWrapper::sendRequestResult() const 129 { 130 return m_sendRequestResult; 131 } 132 133 void ThreadableWebSocketChannelClientWrapper::setSendRequestResult(WebSocketChannel::SendResult sendRequestResult) 134 { 135 m_sendRequestResult = sendRequestResult; 136 m_syncMethodDone = true; 137 } 138 139 unsigned long ThreadableWebSocketChannelClientWrapper::bufferedAmount() const 140 { 141 return m_bufferedAmount; 142 } 143 144 void ThreadableWebSocketChannelClientWrapper::setBufferedAmount(unsigned long bufferedAmount) 145 { 146 m_bufferedAmount = bufferedAmount; 147 m_syncMethodDone = true; 148 } 149 150 void ThreadableWebSocketChannelClientWrapper::clearClient() 151 { 152 m_client = 0; 153 } 154 155 void ThreadableWebSocketChannelClientWrapper::didConnect() 156 { 157 m_pendingTasks.append(createCallbackTask(&didConnectCallback, this)); 158 if (!m_suspended) 159 processPendingTasks(); 160 } 161 162 void ThreadableWebSocketChannelClientWrapper::didReceiveMessage(const String& message) 163 { 164 m_pendingTasks.append(createCallbackTask(&didReceiveMessageCallback, this, message)); 165 if (!m_suspended) 166 processPendingTasks(); 167 } 168 169 void ThreadableWebSocketChannelClientWrapper::didReceiveBinaryData(PassOwnPtr<Vector<char> > binaryData) 170 { 171 m_pendingTasks.append(createCallbackTask(&didReceiveBinaryDataCallback, this, binaryData)); 172 if (!m_suspended) 173 processPendingTasks(); 174 } 175 176 void ThreadableWebSocketChannelClientWrapper::didUpdateBufferedAmount(unsigned long bufferedAmount) 177 { 178 m_pendingTasks.append(createCallbackTask(&didUpdateBufferedAmountCallback, this, bufferedAmount)); 179 if (!m_suspended) 180 processPendingTasks(); 181 } 182 183 void ThreadableWebSocketChannelClientWrapper::didStartClosingHandshake() 184 { 185 m_pendingTasks.append(createCallbackTask(&didStartClosingHandshakeCallback, this)); 186 if (!m_suspended) 187 processPendingTasks(); 188 } 189 190 void ThreadableWebSocketChannelClientWrapper::didClose(unsigned long unhandledBufferedAmount, WebSocketChannelClient::ClosingHandshakeCompletionStatus closingHandshakeCompletion, unsigned short code, const String& reason) 191 { 192 m_pendingTasks.append(createCallbackTask(&didCloseCallback, this, unhandledBufferedAmount, closingHandshakeCompletion, code, reason)); 193 if (!m_suspended) 194 processPendingTasks(); 195 } 196 197 void ThreadableWebSocketChannelClientWrapper::didReceiveMessageError() 198 { 199 m_pendingTasks.append(createCallbackTask(&didReceiveMessageErrorCallback, this)); 200 if (!m_suspended) 201 processPendingTasks(); 202 } 203 204 void ThreadableWebSocketChannelClientWrapper::suspend() 205 { 206 m_suspended = true; 207 } 208 209 void ThreadableWebSocketChannelClientWrapper::resume() 210 { 211 m_suspended = false; 212 processPendingTasks(); 213 } 214 215 void ThreadableWebSocketChannelClientWrapper::processPendingTasksCallback(ScriptExecutionContext* context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> wrapper) 216 { 217 ASSERT_UNUSED(context, context->isWorkerGlobalScope()); 218 wrapper->processPendingTasks(); 219 } 220 221 void ThreadableWebSocketChannelClientWrapper::processPendingTasks() 222 { 223 if (m_suspended) 224 return; 225 if (!m_syncMethodDone) { 226 // When a synchronous operation is in progress (i.e. the execution stack contains 227 // WorkerThreadableWebSocketChannel::waitForMethodCompletion()), we cannot invoke callbacks in this run loop. 228 m_context->postTask(createCallbackTask(&ThreadableWebSocketChannelClientWrapper::processPendingTasksCallback, this)); 229 return; 230 } 231 Vector<OwnPtr<ScriptExecutionContext::Task> > tasks; 232 tasks.swap(m_pendingTasks); 233 for (Vector<OwnPtr<ScriptExecutionContext::Task> >::const_iterator iter = tasks.begin(); iter != tasks.end(); ++iter) 234 (*iter)->performTask(0); 235 } 236 237 void ThreadableWebSocketChannelClientWrapper::didConnectCallback(ScriptExecutionContext* context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> wrapper) 238 { 239 ASSERT_UNUSED(context, !context); 240 if (wrapper->m_client) 241 wrapper->m_client->didConnect(); 242 } 243 244 void ThreadableWebSocketChannelClientWrapper::didReceiveMessageCallback(ScriptExecutionContext* context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> wrapper, const String& message) 245 { 246 ASSERT_UNUSED(context, !context); 247 if (wrapper->m_client) 248 wrapper->m_client->didReceiveMessage(message); 249 } 250 251 void ThreadableWebSocketChannelClientWrapper::didReceiveBinaryDataCallback(ScriptExecutionContext* context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> wrapper, PassOwnPtr<Vector<char> > binaryData) 252 { 253 ASSERT_UNUSED(context, !context); 254 if (wrapper->m_client) 255 wrapper->m_client->didReceiveBinaryData(binaryData); 256 } 257 258 void ThreadableWebSocketChannelClientWrapper::didUpdateBufferedAmountCallback(ScriptExecutionContext* context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> wrapper, unsigned long bufferedAmount) 259 { 260 ASSERT_UNUSED(context, !context); 261 if (wrapper->m_client) 262 wrapper->m_client->didUpdateBufferedAmount(bufferedAmount); 263 } 264 265 void ThreadableWebSocketChannelClientWrapper::didStartClosingHandshakeCallback(ScriptExecutionContext* context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> wrapper) 266 { 267 ASSERT_UNUSED(context, !context); 268 if (wrapper->m_client) 269 wrapper->m_client->didStartClosingHandshake(); 270 } 271 272 void ThreadableWebSocketChannelClientWrapper::didCloseCallback(ScriptExecutionContext* context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> wrapper, unsigned long unhandledBufferedAmount, WebSocketChannelClient::ClosingHandshakeCompletionStatus closingHandshakeCompletion, unsigned short code, const String& reason) 273 { 274 ASSERT_UNUSED(context, !context); 275 if (wrapper->m_client) 276 wrapper->m_client->didClose(unhandledBufferedAmount, closingHandshakeCompletion, code, reason); 277 } 278 279 void ThreadableWebSocketChannelClientWrapper::didReceiveMessageErrorCallback(ScriptExecutionContext* context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> wrapper) 280 { 281 ASSERT_UNUSED(context, !context); 282 if (wrapper->m_client) 283 wrapper->m_client->didReceiveMessageError(); 284 } 285 286 } // namespace WebCore 287