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