BlobRegistry no longer needs SessionIDs
[WebKit-https.git] / Source / WebCore / Modules / mediastream / RTCDataChannel.cpp
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  * Copyright (C) 2017 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
21  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "RTCDataChannel.h"
28
29 #if ENABLE(WEB_RTC)
30
31 #include "Blob.h"
32 #include "EventNames.h"
33 #include "MessageEvent.h"
34 #include "ScriptExecutionContext.h"
35 #include "SharedBuffer.h"
36 #include <JavaScriptCore/ArrayBufferView.h>
37 #include <wtf/IsoMallocInlines.h>
38 #include <wtf/NeverDestroyed.h>
39
40 namespace WebCore {
41
42 WTF_MAKE_ISO_ALLOCATED_IMPL(RTCDataChannel);
43
44 static const AtomString& blobKeyword()
45 {
46     static NeverDestroyed<AtomString> blob("blob", AtomString::ConstructFromLiteral);
47     return blob;
48 }
49
50 static const AtomString& arraybufferKeyword()
51 {
52     static NeverDestroyed<AtomString> arraybuffer("arraybuffer", AtomString::ConstructFromLiteral);
53     return arraybuffer;
54 }
55
56 Ref<RTCDataChannel> RTCDataChannel::create(Document& document, std::unique_ptr<RTCDataChannelHandler>&& handler, String&& label, RTCDataChannelInit&& options)
57 {
58     ASSERT(handler);
59     auto channel = adoptRef(*new RTCDataChannel(document, WTFMove(handler), WTFMove(label), WTFMove(options)));
60     channel->suspendIfNeeded();
61     channel->m_handler->setClient(channel.get());
62     channel->setPendingActivity(channel.get());
63     return channel;
64 }
65
66 NetworkSendQueue RTCDataChannel::createMessageQueue(Document& document, RTCDataChannel& channel)
67 {
68     return { document, [&channel](const String& data) {
69         if (!channel.m_handler->sendStringData(data))
70             channel.scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "Error sending string through RTCDataChannel."_s);
71     }, [&channel](auto* data, size_t length) {
72         if (!channel.m_handler->sendRawData(data, length))
73             channel.scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "Error sending binary data through RTCDataChannel."_s);
74     }, [&channel](int errorCode) {
75         if (auto* context = channel.scriptExecutionContext())
76             context->addConsoleMessage(MessageSource::JS, MessageLevel::Error, makeString("Error ", errorCode, " in retrieving a blob data to be sent through RTCDataChannel."));
77         return NetworkSendQueue::Continue::Yes;
78     } };
79 }
80
81 RTCDataChannel::RTCDataChannel(Document& document, std::unique_ptr<RTCDataChannelHandler>&& handler, String&& label, RTCDataChannelInit&& options)
82     : ActiveDOMObject(document)
83     , m_handler(WTFMove(handler))
84     , m_scheduledEventTimer(*this, &RTCDataChannel::scheduledEventTimerFired)
85     , m_label(WTFMove(label))
86     , m_options(WTFMove(options))
87     , m_messageQueue(createMessageQueue(document, *this))
88 {
89 }
90
91 size_t RTCDataChannel::bufferedAmount() const
92 {
93     // FIXME: We should compute our own bufferedAmount and not count on m_handler which is made null at closing time.
94     if (m_stopped)
95         return 0;
96     return m_handler->bufferedAmount();
97 }
98
99 const AtomString& RTCDataChannel::binaryType() const
100 {
101     switch (m_binaryType) {
102     case BinaryType::Blob:
103         return blobKeyword();
104     case BinaryType::ArrayBuffer:
105         return arraybufferKeyword();
106     }
107
108     ASSERT_NOT_REACHED();
109     return emptyAtom();
110 }
111
112 ExceptionOr<void> RTCDataChannel::setBinaryType(const AtomString& binaryType)
113 {
114     if (binaryType == blobKeyword()) {
115         m_binaryType = BinaryType::Blob;
116         return { };
117     }
118     if (binaryType == arraybufferKeyword()) {
119         m_binaryType = BinaryType::ArrayBuffer;
120         return { };
121     }
122     return Exception { TypeMismatchError };
123 }
124
125 ExceptionOr<void> RTCDataChannel::send(const String& data)
126 {
127     if (m_readyState != RTCDataChannelState::Open)
128         return Exception { InvalidStateError };
129
130     m_messageQueue.enqueue(data);
131     return { };
132 }
133
134 ExceptionOr<void> RTCDataChannel::send(ArrayBuffer& data)
135 {
136     if (m_readyState != RTCDataChannelState::Open)
137         return Exception { InvalidStateError };
138
139     m_messageQueue.enqueue(data, 0, data.byteLength());
140     return { };
141 }
142
143 ExceptionOr<void> RTCDataChannel::send(ArrayBufferView& data)
144 {
145     if (m_readyState != RTCDataChannelState::Open)
146         return Exception { InvalidStateError };
147
148     m_messageQueue.enqueue(*data.unsharedBuffer(), data.byteOffset(), data.byteLength());
149     return { };
150 }
151
152 ExceptionOr<void> RTCDataChannel::send(Blob& blob)
153 {
154     if (m_readyState != RTCDataChannelState::Open)
155         return Exception { InvalidStateError };
156
157     m_messageQueue.enqueue(blob);
158     return { };
159 }
160
161 void RTCDataChannel::close()
162 {
163     if (m_stopped)
164         return;
165
166     m_stopped = true;
167     m_readyState = RTCDataChannelState::Closed;
168
169     m_messageQueue.clear();
170
171     m_handler->close();
172     m_handler = nullptr;
173     unsetPendingActivity(*this);
174 }
175
176 void RTCDataChannel::didChangeReadyState(RTCDataChannelState newState)
177 {
178     if (m_stopped || m_readyState == RTCDataChannelState::Closed || m_readyState == newState)
179         return;
180
181     m_readyState = newState;
182
183     switch (m_readyState) {
184     case RTCDataChannelState::Open:
185         scheduleDispatchEvent(Event::create(eventNames().openEvent, Event::CanBubble::No, Event::IsCancelable::No));
186         break;
187     case RTCDataChannelState::Closed:
188         scheduleDispatchEvent(Event::create(eventNames().closeEvent, Event::CanBubble::No, Event::IsCancelable::No));
189         break;
190     default:
191         break;
192     }
193 }
194
195 void RTCDataChannel::didReceiveStringData(const String& text)
196 {
197     if (m_stopped)
198         return;
199
200     scheduleDispatchEvent(MessageEvent::create(text));
201 }
202
203 void RTCDataChannel::didReceiveRawData(const char* data, size_t dataLength)
204 {
205     if (m_stopped)
206         return;
207
208     switch (m_binaryType) {
209     case BinaryType::Blob:
210         scheduleDispatchEvent(MessageEvent::create(Blob::create(SharedBuffer::create(data, dataLength), emptyString()), { }));
211         return;
212     case BinaryType::ArrayBuffer:
213         scheduleDispatchEvent(MessageEvent::create(ArrayBuffer::create(data, dataLength)));
214         return;
215     }
216     ASSERT_NOT_REACHED();
217 }
218
219 void RTCDataChannel::didDetectError()
220 {
221     if (m_stopped)
222         return;
223
224     scheduleDispatchEvent(Event::create(eventNames().errorEvent, Event::CanBubble::No, Event::IsCancelable::No));
225 }
226
227 void RTCDataChannel::bufferedAmountIsDecreasing(size_t amount)
228 {
229     if (m_stopped)
230         return;
231
232     if (amount <= m_bufferedAmountLowThreshold)
233         scheduleDispatchEvent(Event::create(eventNames().bufferedamountlowEvent, Event::CanBubble::No, Event::IsCancelable::No));
234 }
235
236 void RTCDataChannel::stop()
237 {
238     close();
239 }
240
241 void RTCDataChannel::scheduleDispatchEvent(Ref<Event>&& event)
242 {
243     m_scheduledEvents.append(WTFMove(event));
244
245     if (!m_scheduledEventTimer.isActive())
246         m_scheduledEventTimer.startOneShot(0_s);
247 }
248
249 void RTCDataChannel::scheduledEventTimerFired()
250 {
251     if (m_stopped)
252         return;
253
254     Vector<Ref<Event>> events;
255     events.swap(m_scheduledEvents);
256
257     for (auto& event : events)
258         dispatchEvent(event);
259 }
260
261 } // namespace WebCore
262
263 #endif // ENABLE(WEB_RTC)