initial import
[vuplus_webkit] / Source / WebCore / websockets / WorkerThreadableWebSocketChannel.cpp
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
33 #if ENABLE(WEB_SOCKETS) && ENABLE(WORKERS)
34
35 #include "WorkerThreadableWebSocketChannel.h"
36
37 #include "ArrayBuffer.h"
38 #include "Blob.h"
39 #include "CrossThreadTask.h"
40 #include "PlatformString.h"
41 #include "ScriptExecutionContext.h"
42 #include "ThreadableWebSocketChannelClientWrapper.h"
43 #include "WebSocketChannel.h"
44 #include "WebSocketChannelClient.h"
45 #include "WorkerContext.h"
46 #include "WorkerLoaderProxy.h"
47 #include "WorkerRunLoop.h"
48 #include "WorkerThread.h"
49 #include <wtf/MainThread.h>
50 #include <wtf/PassRefPtr.h>
51
52 namespace WebCore {
53
54 WorkerThreadableWebSocketChannel::WorkerThreadableWebSocketChannel(WorkerContext* context, WebSocketChannelClient* client, const String& taskMode)
55     : m_workerContext(context)
56     , m_workerClientWrapper(ThreadableWebSocketChannelClientWrapper::create(client))
57     , m_bridge(Bridge::create(m_workerClientWrapper, m_workerContext, taskMode))
58 {
59 }
60
61 WorkerThreadableWebSocketChannel::~WorkerThreadableWebSocketChannel()
62 {
63     if (m_bridge)
64         m_bridge->disconnect();
65 }
66
67 bool WorkerThreadableWebSocketChannel::useHixie76Protocol()
68 {
69     ASSERT(m_workerClientWrapper);
70     return m_workerClientWrapper->useHixie76Protocol();
71 }
72
73 void WorkerThreadableWebSocketChannel::connect(const KURL& url, const String& protocol)
74 {
75     if (m_bridge)
76         m_bridge->connect(url, protocol);
77 }
78
79 String WorkerThreadableWebSocketChannel::subprotocol()
80 {
81     ASSERT(m_workerClientWrapper);
82     return m_workerClientWrapper->subprotocol();
83 }
84
85 bool WorkerThreadableWebSocketChannel::send(const String& message)
86 {
87     if (!m_bridge)
88         return false;
89     return m_bridge->send(message);
90 }
91
92 bool WorkerThreadableWebSocketChannel::send(const ArrayBuffer& binaryData)
93 {
94     if (!m_bridge)
95         return false;
96     return m_bridge->send(binaryData);
97 }
98
99 bool WorkerThreadableWebSocketChannel::send(const Blob& binaryData)
100 {
101     if (!m_bridge)
102         return false;
103     return m_bridge->send(binaryData);
104 }
105
106 unsigned long WorkerThreadableWebSocketChannel::bufferedAmount() const
107 {
108     if (!m_bridge)
109         return 0;
110     return m_bridge->bufferedAmount();
111 }
112
113 void WorkerThreadableWebSocketChannel::close(int code, const String& reason)
114 {
115     if (m_bridge)
116         m_bridge->close(code, reason);
117 }
118
119 void WorkerThreadableWebSocketChannel::fail(const String& reason)
120 {
121     if (m_bridge)
122         m_bridge->fail(reason);
123 }
124
125 void WorkerThreadableWebSocketChannel::disconnect()
126 {
127     m_bridge->disconnect();
128     m_bridge.clear();
129 }
130
131 void WorkerThreadableWebSocketChannel::suspend()
132 {
133     m_workerClientWrapper->suspend();
134     if (m_bridge)
135         m_bridge->suspend();
136 }
137
138 void WorkerThreadableWebSocketChannel::resume()
139 {
140     m_workerClientWrapper->resume();
141     if (m_bridge)
142         m_bridge->resume();
143 }
144
145 WorkerThreadableWebSocketChannel::Peer::Peer(PassRefPtr<ThreadableWebSocketChannelClientWrapper> clientWrapper, WorkerLoaderProxy& loaderProxy, ScriptExecutionContext* context, const String& taskMode)
146     : m_workerClientWrapper(clientWrapper)
147     , m_loaderProxy(loaderProxy)
148     , m_mainWebSocketChannel(WebSocketChannel::create(context, this))
149     , m_taskMode(taskMode)
150 {
151     ASSERT(isMainThread());
152 }
153
154 WorkerThreadableWebSocketChannel::Peer::~Peer()
155 {
156     ASSERT(isMainThread());
157     if (m_mainWebSocketChannel)
158         m_mainWebSocketChannel->disconnect();
159 }
160
161 bool WorkerThreadableWebSocketChannel::Peer::useHixie76Protocol()
162 {
163     ASSERT(isMainThread());
164     ASSERT(m_mainWebSocketChannel);
165     return m_mainWebSocketChannel->useHixie76Protocol();
166 }
167
168 void WorkerThreadableWebSocketChannel::Peer::connect(const KURL& url, const String& protocol)
169 {
170     ASSERT(isMainThread());
171     if (!m_mainWebSocketChannel)
172         return;
173     m_mainWebSocketChannel->connect(url, protocol);
174 }
175
176 static void workerContextDidSend(ScriptExecutionContext* context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, bool sendRequestResult)
177 {
178     ASSERT_UNUSED(context, context->isWorkerContext());
179     workerClientWrapper->setSendRequestResult(sendRequestResult);
180 }
181
182 void WorkerThreadableWebSocketChannel::Peer::send(const String& message)
183 {
184     ASSERT(isMainThread());
185     if (!m_mainWebSocketChannel || !m_workerClientWrapper)
186         return;
187     bool sendRequestResult = m_mainWebSocketChannel->send(message);
188     m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidSend, m_workerClientWrapper, sendRequestResult), m_taskMode);
189 }
190
191 void WorkerThreadableWebSocketChannel::Peer::send(const ArrayBuffer& binaryData)
192 {
193     ASSERT(isMainThread());
194     if (!m_mainWebSocketChannel || !m_workerClientWrapper)
195         return;
196     bool sendRequestResult = m_mainWebSocketChannel->send(binaryData);
197     m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidSend, m_workerClientWrapper, sendRequestResult), m_taskMode);
198 }
199
200 void WorkerThreadableWebSocketChannel::Peer::send(const Blob& binaryData)
201 {
202     ASSERT(isMainThread());
203     if (!m_mainWebSocketChannel || !m_workerClientWrapper)
204         return;
205     bool sendRequestResult = m_mainWebSocketChannel->send(binaryData);
206     m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidSend, m_workerClientWrapper, sendRequestResult), m_taskMode);
207 }
208
209 static void workerContextDidGetBufferedAmount(ScriptExecutionContext* context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, unsigned long bufferedAmount)
210 {
211     ASSERT_UNUSED(context, context->isWorkerContext());
212     workerClientWrapper->setBufferedAmount(bufferedAmount);
213 }
214
215 void WorkerThreadableWebSocketChannel::Peer::bufferedAmount()
216 {
217     ASSERT(isMainThread());
218     if (!m_mainWebSocketChannel || !m_workerClientWrapper)
219         return;
220     unsigned long bufferedAmount = m_mainWebSocketChannel->bufferedAmount();
221     m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidGetBufferedAmount, m_workerClientWrapper, bufferedAmount), m_taskMode);
222 }
223
224 void WorkerThreadableWebSocketChannel::Peer::close(int code, const String& reason)
225 {
226     ASSERT(isMainThread());
227     if (!m_mainWebSocketChannel)
228         return;
229     m_mainWebSocketChannel->close(code, reason);
230 }
231
232 void WorkerThreadableWebSocketChannel::Peer::fail(const String& reason)
233 {
234     ASSERT(isMainThread());
235     if (!m_mainWebSocketChannel)
236         return;
237     m_mainWebSocketChannel->fail(reason);
238 }
239
240 void WorkerThreadableWebSocketChannel::Peer::disconnect()
241 {
242     ASSERT(isMainThread());
243     if (!m_mainWebSocketChannel)
244         return;
245     m_mainWebSocketChannel->disconnect();
246     m_mainWebSocketChannel = 0;
247 }
248
249 void WorkerThreadableWebSocketChannel::Peer::suspend()
250 {
251     ASSERT(isMainThread());
252     if (!m_mainWebSocketChannel)
253         return;
254     m_mainWebSocketChannel->suspend();
255 }
256
257 void WorkerThreadableWebSocketChannel::Peer::resume()
258 {
259     ASSERT(isMainThread());
260     if (!m_mainWebSocketChannel)
261         return;
262     m_mainWebSocketChannel->resume();
263 }
264
265 static void workerContextDidConnect(ScriptExecutionContext* context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, const String& subprotocol)
266 {
267     ASSERT_UNUSED(context, context->isWorkerContext());
268     workerClientWrapper->setSubprotocol(subprotocol);
269     workerClientWrapper->didConnect();
270 }
271
272 void WorkerThreadableWebSocketChannel::Peer::didConnect()
273 {
274     ASSERT(isMainThread());
275     m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidConnect, m_workerClientWrapper, m_mainWebSocketChannel->subprotocol()), m_taskMode);
276 }
277
278 static void workerContextDidReceiveMessage(ScriptExecutionContext* context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, const String& message)
279 {
280     ASSERT_UNUSED(context, context->isWorkerContext());
281     workerClientWrapper->didReceiveMessage(message);
282 }
283
284 void WorkerThreadableWebSocketChannel::Peer::didReceiveMessage(const String& message)
285 {
286     ASSERT(isMainThread());
287     m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidReceiveMessage, m_workerClientWrapper, message), m_taskMode);
288 }
289
290 static void workerContextDidReceiveBinaryData(ScriptExecutionContext* context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, PassOwnPtr<Vector<char> > binaryData)
291 {
292     ASSERT_UNUSED(context, context->isWorkerContext());
293     workerClientWrapper->didReceiveBinaryData(binaryData);
294 }
295
296 void WorkerThreadableWebSocketChannel::Peer::didReceiveBinaryData(PassOwnPtr<Vector<char> > binaryData)
297 {
298     ASSERT(isMainThread());
299     m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidReceiveBinaryData, m_workerClientWrapper, binaryData), m_taskMode);
300 }
301
302 static void workerContextDidStartClosingHandshake(ScriptExecutionContext* context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper)
303 {
304     ASSERT_UNUSED(context, context->isWorkerContext());
305     workerClientWrapper->didStartClosingHandshake();
306 }
307
308 void WorkerThreadableWebSocketChannel::Peer::didStartClosingHandshake()
309 {
310     ASSERT(isMainThread());
311     m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidStartClosingHandshake, m_workerClientWrapper), m_taskMode);
312 }
313
314 static void workerContextDidClose(ScriptExecutionContext* context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, unsigned long unhandledBufferedAmount, WebSocketChannelClient::ClosingHandshakeCompletionStatus closingHandshakeCompletion, unsigned short code, const String& reason)
315 {
316     ASSERT_UNUSED(context, context->isWorkerContext());
317     workerClientWrapper->didClose(unhandledBufferedAmount, closingHandshakeCompletion, code, reason);
318 }
319
320 void WorkerThreadableWebSocketChannel::Peer::didClose(unsigned long unhandledBufferedAmount, ClosingHandshakeCompletionStatus closingHandshakeCompletion, unsigned short code, const String& reason)
321 {
322     ASSERT(isMainThread());
323     m_mainWebSocketChannel = 0;
324     m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidClose, m_workerClientWrapper, unhandledBufferedAmount, closingHandshakeCompletion, code, reason), m_taskMode);
325 }
326
327 void WorkerThreadableWebSocketChannel::Bridge::setWebSocketChannel(ScriptExecutionContext* context, Bridge* thisPtr, Peer* peer, PassRefPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, bool useHixie76Protocol)
328 {
329     ASSERT_UNUSED(context, context->isWorkerContext());
330     thisPtr->m_peer = peer;
331     workerClientWrapper->setUseHixie76Protocol(useHixie76Protocol);
332     workerClientWrapper->setSyncMethodDone();
333 }
334
335 void WorkerThreadableWebSocketChannel::Bridge::mainThreadCreateWebSocketChannel(ScriptExecutionContext* context, Bridge* thisPtr, PassRefPtr<ThreadableWebSocketChannelClientWrapper> prpClientWrapper, const String& taskMode)
336 {
337     ASSERT(isMainThread());
338     ASSERT_UNUSED(context, context->isDocument());
339
340     RefPtr<ThreadableWebSocketChannelClientWrapper> clientWrapper = prpClientWrapper;
341
342     Peer* peer = Peer::create(clientWrapper, thisPtr->m_loaderProxy, context, taskMode);
343     thisPtr->m_loaderProxy.postTaskForModeToWorkerContext(
344         createCallbackTask(&Bridge::setWebSocketChannel,
345                            AllowCrossThreadAccess(thisPtr),
346                            AllowCrossThreadAccess(peer), clientWrapper, peer->useHixie76Protocol()), taskMode);
347 }
348
349 WorkerThreadableWebSocketChannel::Bridge::Bridge(PassRefPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, PassRefPtr<WorkerContext> workerContext, const String& taskMode)
350     : m_workerClientWrapper(workerClientWrapper)
351     , m_workerContext(workerContext)
352     , m_loaderProxy(m_workerContext->thread()->workerLoaderProxy())
353     , m_taskMode(taskMode)
354     , m_peer(0)
355 {
356     ASSERT(m_workerClientWrapper.get());
357     setMethodNotCompleted();
358     m_loaderProxy.postTaskToLoader(
359         createCallbackTask(&Bridge::mainThreadCreateWebSocketChannel,
360                            AllowCrossThreadAccess(this), m_workerClientWrapper, m_taskMode));
361     waitForMethodCompletion();
362     ASSERT(m_peer);
363 }
364
365 WorkerThreadableWebSocketChannel::Bridge::~Bridge()
366 {
367     disconnect();
368 }
369
370 void WorkerThreadableWebSocketChannel::mainThreadConnect(ScriptExecutionContext* context, Peer* peer, const KURL& url, const String& protocol)
371 {
372     ASSERT(isMainThread());
373     ASSERT_UNUSED(context, context->isDocument());
374     ASSERT(peer);
375
376     peer->connect(url, protocol);
377 }
378
379 void WorkerThreadableWebSocketChannel::Bridge::connect(const KURL& url, const String& protocol)
380 {
381     ASSERT(m_workerClientWrapper);
382     ASSERT(m_peer);
383     m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadConnect, AllowCrossThreadAccess(m_peer), url, protocol));
384 }
385
386 void WorkerThreadableWebSocketChannel::mainThreadSend(ScriptExecutionContext* context, Peer* peer, const String& message)
387 {
388     ASSERT(isMainThread());
389     ASSERT_UNUSED(context, context->isDocument());
390     ASSERT(peer);
391
392     peer->send(message);
393 }
394
395 void WorkerThreadableWebSocketChannel::mainThreadSendArrayBuffer(ScriptExecutionContext* context, Peer* peer, PassOwnPtr<Vector<char> > data)
396 {
397     ASSERT(isMainThread());
398     ASSERT_UNUSED(context, context->isDocument());
399     ASSERT(peer);
400
401     RefPtr<ArrayBuffer> arrayBuffer = ArrayBuffer::create(data->data(), data->size());
402     peer->send(*arrayBuffer);
403 }
404
405 void WorkerThreadableWebSocketChannel::mainThreadSendBlob(ScriptExecutionContext* context, Peer* peer, const KURL& url, const String& type, long long size)
406 {
407     ASSERT(isMainThread());
408     ASSERT_UNUSED(context, context->isDocument());
409     ASSERT(peer);
410
411     RefPtr<Blob> blob = Blob::create(url, type, size);
412     peer->send(*blob);
413 }
414
415 bool WorkerThreadableWebSocketChannel::Bridge::send(const String& message)
416 {
417     if (!m_workerClientWrapper)
418         return false;
419     ASSERT(m_peer);
420     setMethodNotCompleted();
421     m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadSend, AllowCrossThreadAccess(m_peer), message));
422     RefPtr<Bridge> protect(this);
423     waitForMethodCompletion();
424     ThreadableWebSocketChannelClientWrapper* clientWrapper = m_workerClientWrapper.get();
425     return clientWrapper && clientWrapper->sendRequestResult();
426 }
427
428 bool WorkerThreadableWebSocketChannel::Bridge::send(const ArrayBuffer& binaryData)
429 {
430     if (!m_workerClientWrapper)
431         return false;
432     ASSERT(m_peer);
433     // ArrayBuffer isn't thread-safe, hence the content of ArrayBuffer is copied into Vector<char>.
434     OwnPtr<Vector<char> > data = adoptPtr(new Vector<char>(binaryData.byteLength()));
435     if (binaryData.byteLength())
436         memcpy(data->data(), binaryData.data(), binaryData.byteLength());
437     setMethodNotCompleted();
438     m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadSendArrayBuffer, AllowCrossThreadAccess(m_peer), data.release()));
439     RefPtr<Bridge> protect(this);
440     waitForMethodCompletion();
441     ThreadableWebSocketChannelClientWrapper* clientWrapper = m_workerClientWrapper.get();
442     return clientWrapper && clientWrapper->sendRequestResult();
443 }
444
445 bool WorkerThreadableWebSocketChannel::Bridge::send(const Blob& binaryData)
446 {
447     if (!m_workerClientWrapper)
448         return false;
449     ASSERT(m_peer);
450     setMethodNotCompleted();
451     m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadSendBlob, AllowCrossThreadAccess(m_peer), binaryData.url(), binaryData.type(), binaryData.size()));
452     RefPtr<Bridge> protect(this);
453     waitForMethodCompletion();
454     ThreadableWebSocketChannelClientWrapper* clientWrapper = m_workerClientWrapper.get();
455     return clientWrapper && clientWrapper->sendRequestResult();
456 }
457
458 void WorkerThreadableWebSocketChannel::mainThreadBufferedAmount(ScriptExecutionContext* context, Peer* peer)
459 {
460     ASSERT(isMainThread());
461     ASSERT_UNUSED(context, context->isDocument());
462     ASSERT(peer);
463
464     peer->bufferedAmount();
465 }
466
467 unsigned long WorkerThreadableWebSocketChannel::Bridge::bufferedAmount()
468 {
469     if (!m_workerClientWrapper)
470         return 0;
471     ASSERT(m_peer);
472     setMethodNotCompleted();
473     m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadBufferedAmount, AllowCrossThreadAccess(m_peer)));
474     RefPtr<Bridge> protect(this);
475     waitForMethodCompletion();
476     ThreadableWebSocketChannelClientWrapper* clientWrapper = m_workerClientWrapper.get();
477     if (clientWrapper)
478         return clientWrapper->bufferedAmount();
479     return 0;
480 }
481
482 void WorkerThreadableWebSocketChannel::mainThreadClose(ScriptExecutionContext* context, Peer* peer, int code, const String&reason)
483 {
484     ASSERT(isMainThread());
485     ASSERT_UNUSED(context, context->isDocument());
486     ASSERT(peer);
487
488     peer->close(code, reason);
489 }
490
491 void WorkerThreadableWebSocketChannel::Bridge::close(int code, const String& reason)
492 {
493     ASSERT(m_peer);
494     m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadClose, AllowCrossThreadAccess(m_peer), code, reason));
495 }
496
497 void WorkerThreadableWebSocketChannel::mainThreadFail(ScriptExecutionContext* context, Peer* peer, const String& reason)
498 {
499     ASSERT(isMainThread());
500     ASSERT_UNUSED(context, context->isDocument());
501     ASSERT(peer);
502
503     peer->fail(reason);
504 }
505
506 void WorkerThreadableWebSocketChannel::Bridge::fail(const String& reason)
507 {
508     ASSERT(m_peer);
509     m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadFail, AllowCrossThreadAccess(m_peer), reason));
510 }
511
512 void WorkerThreadableWebSocketChannel::mainThreadDestroy(ScriptExecutionContext* context, Peer* peer)
513 {
514     ASSERT(isMainThread());
515     ASSERT_UNUSED(context, context->isDocument());
516     ASSERT(peer);
517
518     delete peer;
519 }
520
521 void WorkerThreadableWebSocketChannel::Bridge::disconnect()
522 {
523     clearClientWrapper();
524     if (m_peer) {
525         Peer* peer = m_peer;
526         m_peer = 0;
527         m_loaderProxy.postTaskToLoader(createCallbackTask(&mainThreadDestroy, AllowCrossThreadAccess(peer)));
528     }
529     m_workerContext = 0;
530 }
531
532 void WorkerThreadableWebSocketChannel::mainThreadSuspend(ScriptExecutionContext* context, Peer* peer)
533 {
534     ASSERT(isMainThread());
535     ASSERT_UNUSED(context, context->isDocument());
536     ASSERT(peer);
537
538     peer->suspend();
539 }
540
541 void WorkerThreadableWebSocketChannel::Bridge::suspend()
542 {
543     ASSERT(m_peer);
544     m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadSuspend, AllowCrossThreadAccess(m_peer)));
545 }
546
547 void WorkerThreadableWebSocketChannel::mainThreadResume(ScriptExecutionContext* context, Peer* peer)
548 {
549     ASSERT(isMainThread());
550     ASSERT_UNUSED(context, context->isDocument());
551     ASSERT(peer);
552
553     peer->resume();
554 }
555
556 void WorkerThreadableWebSocketChannel::Bridge::resume()
557 {
558     ASSERT(m_peer);
559     m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadResume, AllowCrossThreadAccess(m_peer)));
560 }
561
562 void WorkerThreadableWebSocketChannel::Bridge::clearClientWrapper()
563 {
564     m_workerClientWrapper->clearClient();
565 }
566
567 void WorkerThreadableWebSocketChannel::Bridge::setMethodNotCompleted()
568 {
569     ASSERT(m_workerClientWrapper);
570     m_workerClientWrapper->clearSyncMethodDone();
571 }
572
573 // Caller of this function should hold a reference to the bridge, because this function may call WebSocket::didClose() in the end,
574 // which causes the bridge to get disconnected from the WebSocket and deleted if there is no other reference.
575 void WorkerThreadableWebSocketChannel::Bridge::waitForMethodCompletion()
576 {
577     if (!m_workerContext)
578         return;
579     WorkerRunLoop& runLoop = m_workerContext->thread()->runLoop();
580     MessageQueueWaitResult result = MessageQueueMessageReceived;
581     ThreadableWebSocketChannelClientWrapper* clientWrapper = m_workerClientWrapper.get();
582     while (m_workerContext && clientWrapper && !clientWrapper->syncMethodDone() && result != MessageQueueTerminated) {
583         result = runLoop.runInMode(m_workerContext.get(), m_taskMode); // May cause this bridge to get disconnected, which makes m_workerContext become null.
584         clientWrapper = m_workerClientWrapper.get();
585     }
586 }
587
588 } // namespace WebCore
589
590 #endif // ENABLE(WEB_SOCKETS)