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#pragma once
32
33#include "ThreadableWebSocketChannel.h"
34#include "WebSocketChannelClient.h"
35#include "WorkerGlobalScope.h"
36#include <wtf/RefCounted.h>
37#include <wtf/RefPtr.h>
38#include <wtf/text/WTFString.h>
39
40namespace WebCore {
41
42class ScriptExecutionContext;
43class ThreadableWebSocketChannelClientWrapper;
44class WorkerGlobalScope;
45class WorkerLoaderProxy;
46class WorkerRunLoop;
47
48class WorkerThreadableWebSocketChannel final : public RefCounted<WorkerThreadableWebSocketChannel>, public ThreadableWebSocketChannel {
49 WTF_MAKE_FAST_ALLOCATED;
50public:
51 static Ref<ThreadableWebSocketChannel> create(WorkerGlobalScope& workerGlobalScope, WebSocketChannelClient& client, const String& taskMode, SocketProvider& provider)
52 {
53 return adoptRef(*new WorkerThreadableWebSocketChannel(workerGlobalScope, client, taskMode, provider));
54 }
55 virtual ~WorkerThreadableWebSocketChannel();
56
57 // ThreadableWebSocketChannel functions.
58 ConnectStatus connect(const URL&, const String& protocol) final;
59 String subprotocol() final;
60 String extensions() final;
61 ThreadableWebSocketChannel::SendResult send(const String& message) final;
62 ThreadableWebSocketChannel::SendResult send(const JSC::ArrayBuffer&, unsigned byteOffset, unsigned byteLength) final;
63 ThreadableWebSocketChannel::SendResult send(Blob&) final;
64 unsigned bufferedAmount() const final;
65 void close(int code, const String& reason) final;
66 void fail(const String& reason) final;
67 void disconnect() final; // Will suppress didClose().
68 void suspend() final;
69 void resume() final;
70
71 // Generated by the bridge. The Peer and its bridge should have identical
72 // lifetimes.
73 class Peer : public WebSocketChannelClient {
74 WTF_MAKE_NONCOPYABLE(Peer); WTF_MAKE_FAST_ALLOCATED;
75 public:
76 Peer(Ref<ThreadableWebSocketChannelClientWrapper>&&, WorkerLoaderProxy&, ScriptExecutionContext&, const String& taskMode, SocketProvider&);
77 ~Peer();
78
79 ConnectStatus connect(const URL&, const String& protocol);
80 void send(const String& message);
81 void send(const JSC::ArrayBuffer&);
82 void send(Blob&);
83 void bufferedAmount();
84 void close(int code, const String& reason);
85 void fail(const String& reason);
86 void disconnect();
87 void suspend();
88 void resume();
89
90 // WebSocketChannelClient functions.
91 void didConnect() final;
92 void didReceiveMessage(const String& message) final;
93 void didReceiveBinaryData(Vector<uint8_t>&&) final;
94 void didUpdateBufferedAmount(unsigned bufferedAmount) final;
95 void didStartClosingHandshake() final;
96 void didClose(unsigned unhandledBufferedAmount, ClosingHandshakeCompletionStatus, unsigned short code, const String& reason) final;
97 void didReceiveMessageError() final;
98 void didUpgradeURL() final;
99
100 private:
101 Ref<ThreadableWebSocketChannelClientWrapper> m_workerClientWrapper;
102 WorkerLoaderProxy& m_loaderProxy;
103 RefPtr<ThreadableWebSocketChannel> m_mainWebSocketChannel;
104 String m_taskMode;
105 };
106
107 using RefCounted<WorkerThreadableWebSocketChannel>::ref;
108 using RefCounted<WorkerThreadableWebSocketChannel>::deref;
109
110protected:
111 void refThreadableWebSocketChannel() override { ref(); }
112 void derefThreadableWebSocketChannel() override { deref(); }
113
114private:
115 // Bridge for Peer. Running on the worker thread.
116 class Bridge : public RefCounted<Bridge> {
117 public:
118 static Ref<Bridge> create(Ref<ThreadableWebSocketChannelClientWrapper>&& workerClientWrapper, Ref<WorkerGlobalScope>&& workerGlobalScope, const String& taskMode, Ref<SocketProvider>&& provider)
119 {
120 return adoptRef(*new Bridge(WTFMove(workerClientWrapper), WTFMove(workerGlobalScope), taskMode, WTFMove(provider)));
121 }
122 ~Bridge();
123 void initialize();
124 void connect(const URL&, const String& protocol);
125 ThreadableWebSocketChannel::SendResult send(const String& message);
126 ThreadableWebSocketChannel::SendResult send(const JSC::ArrayBuffer&, unsigned byteOffset, unsigned byteLength);
127 ThreadableWebSocketChannel::SendResult send(Blob&);
128 unsigned bufferedAmount();
129 void close(int code, const String& reason);
130 void fail(const String& reason);
131 void disconnect();
132 void suspend();
133 void resume();
134
135 using RefCounted<Bridge>::ref;
136 using RefCounted<Bridge>::deref;
137
138 private:
139 Bridge(Ref<ThreadableWebSocketChannelClientWrapper>&&, Ref<WorkerGlobalScope>&&, const String& taskMode, Ref<SocketProvider>&&);
140
141 static void setWebSocketChannel(ScriptExecutionContext*, Bridge* thisPtr, Peer*, Ref<ThreadableWebSocketChannelClientWrapper>&&);
142
143 // Executed on the main thread to create a Peer for this bridge.
144 static void mainThreadInitialize(ScriptExecutionContext&, WorkerLoaderProxy&, Ref<ThreadableWebSocketChannelClientWrapper>&&, const String& taskMode, Ref<SocketProvider>&&);
145
146 // Executed on the worker context's thread.
147 void clearClientWrapper();
148
149 void setMethodNotCompleted();
150 void waitForMethodCompletion();
151
152 Ref<ThreadableWebSocketChannelClientWrapper> m_workerClientWrapper;
153 RefPtr<WorkerGlobalScope> m_workerGlobalScope;
154 WorkerLoaderProxy& m_loaderProxy;
155 String m_taskMode;
156 Peer* m_peer { nullptr };
157 Ref<SocketProvider> m_socketProvider;
158 };
159
160 WEBCORE_EXPORT WorkerThreadableWebSocketChannel(WorkerGlobalScope&, WebSocketChannelClient&, const String& taskMode, SocketProvider&);
161
162 class WorkerGlobalScopeDidInitializeTask;
163
164 Ref<WorkerGlobalScope> m_workerGlobalScope;
165 Ref<ThreadableWebSocketChannelClientWrapper> m_workerClientWrapper;
166 RefPtr<Bridge> m_bridge;
167 Ref<SocketProvider> m_socketProvider;
168};
169
170} // namespace WebCore
171