Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / Modules / websockets / WebSocketChannel.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)
34
35 #include "WebSocketChannel.h"
36
37 #include "Blob.h"
38 #include "CookieJar.h"
39 #include "Document.h"
40 #include "ExceptionCodePlaceholder.h"
41 #include "FileError.h"
42 #include "FileReaderLoader.h"
43 #include "Frame.h"
44 #include "InspectorInstrumentation.h"
45 #include "Logging.h"
46 #include "Page.h"
47 #include "ProgressTracker.h"
48 #include "ResourceRequest.h"
49 #include "ScriptExecutionContext.h"
50 #include "Settings.h"
51 #include "SocketStreamError.h"
52 #include "SocketStreamHandle.h"
53 #include "WebSocketChannelClient.h"
54 #include "WebSocketHandshake.h"
55 #include <runtime/ArrayBuffer.h>
56 #include <wtf/Deque.h>
57 #include <wtf/FastMalloc.h>
58 #include <wtf/HashMap.h>
59 #include <wtf/text/CString.h>
60 #include <wtf/text/StringHash.h>
61 #include <wtf/text/WTFString.h>
62
63 namespace WebCore {
64
65 const double TCPMaximumSegmentLifetime = 2 * 60.0;
66
67 WebSocketChannel::WebSocketChannel(Document* document, WebSocketChannelClient* client)
68     : m_document(document)
69     , m_client(client)
70     , m_resumeTimer(*this, &WebSocketChannel::resumeTimerFired)
71     , m_suspended(false)
72     , m_closing(false)
73     , m_receivedClosingHandshake(false)
74     , m_closingTimer(*this, &WebSocketChannel::closingTimerFired)
75     , m_closed(false)
76     , m_shouldDiscardReceivedData(false)
77     , m_unhandledBufferedAmount(0)
78     , m_identifier(0)
79     , m_hasContinuousFrame(false)
80     , m_closeEventCode(CloseEventCodeAbnormalClosure)
81     , m_outgoingFrameQueueStatus(OutgoingFrameQueueOpen)
82     , m_blobLoaderStatus(BlobLoaderNotStarted)
83 {
84     ASSERT(m_document);
85
86     if (Page* page = m_document->page())
87         m_identifier = page->progress().createUniqueIdentifier();
88
89     LOG(Network, "WebSocketChannel %p ctor, identifier %lu", this, m_identifier);
90 }
91
92 WebSocketChannel::~WebSocketChannel()
93 {
94     LOG(Network, "WebSocketChannel %p dtor", this);
95 }
96
97 void WebSocketChannel::connect(const URL& url, const String& protocol)
98 {
99     LOG(Network, "WebSocketChannel %p connect()", this);
100     ASSERT(!m_handle);
101     ASSERT(!m_suspended);
102     m_handshake = std::make_unique<WebSocketHandshake>(url, protocol, m_document);
103     m_handshake->reset();
104     if (m_deflateFramer.canDeflate())
105         m_handshake->addExtensionProcessor(m_deflateFramer.createExtensionProcessor());
106     if (m_identifier)
107         InspectorInstrumentation::didCreateWebSocket(m_document, m_identifier, url);
108
109     if (Frame* frame = m_document->frame()) {
110         if (NetworkingContext* networkingContext = frame->loader().networkingContext()) {
111             ref();
112             m_handle = SocketStreamHandle::create(m_handshake->url(), this, *networkingContext);
113         }
114     }
115 }
116
117 String WebSocketChannel::subprotocol()
118 {
119     LOG(Network, "WebSocketChannel %p subprotocol()", this);
120     if (!m_handshake || m_handshake->mode() != WebSocketHandshake::Connected)
121         return "";
122     String serverProtocol = m_handshake->serverWebSocketProtocol();
123     if (serverProtocol.isNull())
124         return "";
125     return serverProtocol;
126 }
127
128 String WebSocketChannel::extensions()
129 {
130     LOG(Network, "WebSocketChannel %p extensions()", this);
131     if (!m_handshake || m_handshake->mode() != WebSocketHandshake::Connected)
132         return "";
133     String extensions = m_handshake->acceptedExtensions();
134     if (extensions.isNull())
135         return "";
136     return extensions;
137 }
138
139 ThreadableWebSocketChannel::SendResult WebSocketChannel::send(const String& message)
140 {
141     LOG(Network, "WebSocketChannel %p send() Sending String '%s'", this, message.utf8().data());
142     CString utf8 = message.utf8(StrictConversionReplacingUnpairedSurrogatesWithFFFD);
143     enqueueTextFrame(utf8);
144     processOutgoingFrameQueue();
145     // According to WebSocket API specification, WebSocket.send() should return void instead
146     // of boolean. However, our implementation still returns boolean due to compatibility
147     // concern (see bug 65850).
148     // m_channel->send() may happen later, thus it's not always possible to know whether
149     // the message has been sent to the socket successfully. In this case, we have no choice
150     // but to return true.
151     return ThreadableWebSocketChannel::SendSuccess;
152 }
153
154 ThreadableWebSocketChannel::SendResult WebSocketChannel::send(const ArrayBuffer& binaryData, unsigned byteOffset, unsigned byteLength)
155 {
156     LOG(Network, "WebSocketChannel %p send() Sending ArrayBuffer %p byteOffset=%u byteLength=%u", this, &binaryData, byteOffset, byteLength);
157     enqueueRawFrame(WebSocketFrame::OpCodeBinary, static_cast<const char*>(binaryData.data()) + byteOffset, byteLength);
158     processOutgoingFrameQueue();
159     return ThreadableWebSocketChannel::SendSuccess;
160 }
161
162 ThreadableWebSocketChannel::SendResult WebSocketChannel::send(Blob& binaryData)
163 {
164     LOG(Network, "WebSocketChannel %p send() Sending Blob '%s'", this, binaryData.url().string().utf8().data());
165     enqueueBlobFrame(WebSocketFrame::OpCodeBinary, binaryData);
166     processOutgoingFrameQueue();
167     return ThreadableWebSocketChannel::SendSuccess;
168 }
169
170 bool WebSocketChannel::send(const char* data, int length)
171 {
172     LOG(Network, "WebSocketChannel %p send() Sending char* data=%p length=%d", this, data, length);
173     enqueueRawFrame(WebSocketFrame::OpCodeBinary, data, length);
174     processOutgoingFrameQueue();
175     return true;
176 }
177
178 unsigned long WebSocketChannel::bufferedAmount() const
179 {
180     LOG(Network, "WebSocketChannel %p bufferedAmount()", this);
181     ASSERT(m_handle);
182     ASSERT(!m_suspended);
183     return m_handle->bufferedAmount();
184 }
185
186 void WebSocketChannel::close(int code, const String& reason)
187 {
188     LOG(Network, "WebSocketChannel %p close() code=%d reason='%s'", this, code, reason.utf8().data());
189     ASSERT(!m_suspended);
190     if (!m_handle)
191         return;
192     Ref<WebSocketChannel> protect(*this); // An attempt to send closing handshake may fail, which will get the channel closed and dereferenced.
193     startClosingHandshake(code, reason);
194     if (m_closing && !m_closingTimer.isActive())
195         m_closingTimer.startOneShot(2 * TCPMaximumSegmentLifetime);
196 }
197
198 void WebSocketChannel::fail(const String& reason)
199 {
200     LOG(Network, "WebSocketChannel %p fail() reason='%s'", this, reason.utf8().data());
201     ASSERT(!m_suspended);
202     if (m_document) {
203         InspectorInstrumentation::didReceiveWebSocketFrameError(m_document, m_identifier, reason);
204
205         String consoleMessage;
206         if (m_handshake)
207             consoleMessage = makeString("WebSocket connection to '", m_handshake->url().stringCenterEllipsizedToLength(), "' failed: ", reason);
208         else
209             consoleMessage = makeString("WebSocket connection failed: ", reason);
210
211         m_document->addConsoleMessage(MessageSource::Network, MessageLevel::Error, consoleMessage);
212     }
213
214     // Hybi-10 specification explicitly states we must not continue to handle incoming data
215     // once the WebSocket connection is failed (section 7.1.7).
216     Ref<WebSocketChannel> protect(*this); // The client can close the channel, potentially removing the last reference.
217     m_shouldDiscardReceivedData = true;
218     if (!m_buffer.isEmpty())
219         skipBuffer(m_buffer.size()); // Save memory.
220     m_deflateFramer.didFail();
221     m_hasContinuousFrame = false;
222     m_continuousFrameData.clear();
223     m_client->didReceiveMessageError();
224
225     if (m_handle && !m_closed)
226         m_handle->disconnect(); // Will call didClose().
227
228     // We should be closed by now, but if we never got a handshake then we never even opened.
229     ASSERT(m_closed || !m_handshake);
230 }
231
232 void WebSocketChannel::disconnect()
233 {
234     LOG(Network, "WebSocketChannel %p disconnect()", this);
235     if (m_identifier && m_document)
236         InspectorInstrumentation::didCloseWebSocket(m_document, m_identifier);
237     if (m_handshake)
238         m_handshake->clearScriptExecutionContext();
239     m_client = nullptr;
240     m_document = nullptr;
241     if (m_handle)
242         m_handle->disconnect();
243 }
244
245 void WebSocketChannel::suspend()
246 {
247     m_suspended = true;
248 }
249
250 void WebSocketChannel::resume()
251 {
252     m_suspended = false;
253     if ((!m_buffer.isEmpty() || m_closed) && m_client && !m_resumeTimer.isActive())
254         m_resumeTimer.startOneShot(0);
255 }
256
257 void WebSocketChannel::willOpenSocketStream(SocketStreamHandle*)
258 {
259     LOG(Network, "WebSocketChannel %p willOpenSocketStream()", this);
260 }
261
262 void WebSocketChannel::didOpenSocketStream(SocketStreamHandle* handle)
263 {
264     LOG(Network, "WebSocketChannel %p didOpenSocketStream()", this);
265     ASSERT(handle == m_handle);
266     if (!m_document)
267         return;
268     if (m_identifier)
269         InspectorInstrumentation::willSendWebSocketHandshakeRequest(m_document, m_identifier, m_handshake->clientHandshakeRequest());
270     CString handshakeMessage = m_handshake->clientHandshakeMessage();
271     if (!handle->send(handshakeMessage.data(), handshakeMessage.length()))
272         fail("Failed to send WebSocket handshake.");
273 }
274
275 void WebSocketChannel::didCloseSocketStream(SocketStreamHandle* handle)
276 {
277     LOG(Network, "WebSocketChannel %p didCloseSocketStream()", this);
278     if (m_identifier && m_document)
279         InspectorInstrumentation::didCloseWebSocket(m_document, m_identifier);
280     ASSERT_UNUSED(handle, handle == m_handle || !m_handle);
281     m_closed = true;
282     if (m_closingTimer.isActive())
283         m_closingTimer.stop();
284     if (m_outgoingFrameQueueStatus != OutgoingFrameQueueClosed)
285         abortOutgoingFrameQueue();
286     if (m_handle) {
287         m_unhandledBufferedAmount = m_handle->bufferedAmount();
288         if (m_suspended)
289             return;
290         WebSocketChannelClient* client = m_client;
291         m_client = nullptr;
292         m_document = nullptr;
293         m_handle = nullptr;
294         if (client)
295             client->didClose(m_unhandledBufferedAmount, m_receivedClosingHandshake ? WebSocketChannelClient::ClosingHandshakeComplete : WebSocketChannelClient::ClosingHandshakeIncomplete, m_closeEventCode, m_closeEventReason);
296     }
297     deref();
298 }
299
300 void WebSocketChannel::didReceiveSocketStreamData(SocketStreamHandle* handle, const char* data, int len)
301 {
302     LOG(Network, "WebSocketChannel %p didReceiveSocketStreamData() Received %d bytes", this, len);
303     Ref<WebSocketChannel> protect(*this); // The client can close the channel, potentially removing the last reference.
304     ASSERT(handle == m_handle);
305     if (!m_document) {
306         return;
307     }
308     if (len <= 0) {
309         handle->disconnect();
310         return;
311     }
312     if (!m_client) {
313         m_shouldDiscardReceivedData = true;
314         handle->disconnect();
315         return;
316     }
317     if (m_shouldDiscardReceivedData)
318         return;
319     if (!appendToBuffer(data, len)) {
320         m_shouldDiscardReceivedData = true;
321         fail("Ran out of memory while receiving WebSocket data.");
322         return;
323     }
324     while (!m_suspended && m_client && !m_buffer.isEmpty())
325         if (!processBuffer())
326             break;
327 }
328
329 void WebSocketChannel::didUpdateBufferedAmount(SocketStreamHandle*, size_t bufferedAmount)
330 {
331     if (m_client)
332         m_client->didUpdateBufferedAmount(bufferedAmount);
333 }
334
335 void WebSocketChannel::didFailSocketStream(SocketStreamHandle* handle, const SocketStreamError& error)
336 {
337     LOG(Network, "WebSocketChannel %p didFailSocketStream()", this);
338     ASSERT(handle == m_handle || !m_handle);
339     if (m_document) {
340         String message;
341         if (error.isNull())
342             message = "WebSocket network error";
343         else if (error.localizedDescription().isNull())
344             message = "WebSocket network error: error code " + String::number(error.errorCode());
345         else
346             message = "WebSocket network error: " + error.localizedDescription();
347         InspectorInstrumentation::didReceiveWebSocketFrameError(m_document, m_identifier, message);
348         m_document->addConsoleMessage(MessageSource::Network, MessageLevel::Error, message);
349     }
350     m_shouldDiscardReceivedData = true;
351     handle->disconnect();
352 }
353
354 void WebSocketChannel::didReceiveAuthenticationChallenge(SocketStreamHandle*, const AuthenticationChallenge&)
355 {
356 }
357
358 void WebSocketChannel::didCancelAuthenticationChallenge(SocketStreamHandle*, const AuthenticationChallenge&)
359 {
360 }
361
362 void WebSocketChannel::didStartLoading()
363 {
364     LOG(Network, "WebSocketChannel %p didStartLoading()", this);
365     ASSERT(m_blobLoader);
366     ASSERT(m_blobLoaderStatus == BlobLoaderStarted);
367 }
368
369 void WebSocketChannel::didReceiveData()
370 {
371     LOG(Network, "WebSocketChannel %p didReceiveData()", this);
372     ASSERT(m_blobLoader);
373     ASSERT(m_blobLoaderStatus == BlobLoaderStarted);
374 }
375
376 void WebSocketChannel::didFinishLoading()
377 {
378     LOG(Network, "WebSocketChannel %p didFinishLoading()", this);
379     ASSERT(m_blobLoader);
380     ASSERT(m_blobLoaderStatus == BlobLoaderStarted);
381     m_blobLoaderStatus = BlobLoaderFinished;
382     processOutgoingFrameQueue();
383     deref();
384 }
385
386 void WebSocketChannel::didFail(int errorCode)
387 {
388     LOG(Network, "WebSocketChannel %p didFail() errorCode=%d", this, errorCode);
389     ASSERT(m_blobLoader);
390     ASSERT(m_blobLoaderStatus == BlobLoaderStarted);
391     m_blobLoader = nullptr;
392     m_blobLoaderStatus = BlobLoaderFailed;
393     fail("Failed to load Blob: error code = " + String::number(errorCode)); // FIXME: Generate human-friendly reason message.
394     deref();
395 }
396
397 bool WebSocketChannel::appendToBuffer(const char* data, size_t len)
398 {
399     size_t newBufferSize = m_buffer.size() + len;
400     if (newBufferSize < m_buffer.size()) {
401         LOG(Network, "WebSocketChannel %p appendToBuffer() Buffer overflow (%lu bytes already in receive buffer and appending %lu bytes)", this, static_cast<unsigned long>(m_buffer.size()), static_cast<unsigned long>(len));
402         return false;
403     }
404     m_buffer.append(data, len);
405     return true;
406 }
407
408 void WebSocketChannel::skipBuffer(size_t len)
409 {
410     ASSERT_WITH_SECURITY_IMPLICATION(len <= m_buffer.size());
411     memmove(m_buffer.data(), m_buffer.data() + len, m_buffer.size() - len);
412     m_buffer.resize(m_buffer.size() - len);
413 }
414
415 bool WebSocketChannel::processBuffer()
416 {
417     ASSERT(!m_suspended);
418     ASSERT(m_client);
419     ASSERT(!m_buffer.isEmpty());
420     LOG(Network, "WebSocketChannel %p processBuffer() Receive buffer has %lu bytes", this, static_cast<unsigned long>(m_buffer.size()));
421
422     if (m_shouldDiscardReceivedData)
423         return false;
424
425     if (m_receivedClosingHandshake) {
426         skipBuffer(m_buffer.size());
427         return false;
428     }
429
430     Ref<WebSocketChannel> protect(*this); // The client can close the channel, potentially removing the last reference.
431
432     if (m_handshake->mode() == WebSocketHandshake::Incomplete) {
433         int headerLength = m_handshake->readServerHandshake(m_buffer.data(), m_buffer.size());
434         if (headerLength <= 0)
435             return false;
436         if (m_handshake->mode() == WebSocketHandshake::Connected) {
437             if (m_identifier)
438                 InspectorInstrumentation::didReceiveWebSocketHandshakeResponse(m_document, m_identifier, m_handshake->serverHandshakeResponse());
439             if (!m_handshake->serverSetCookie().isEmpty()) {
440                 if (cookiesEnabled(m_document)) {
441                     // Exception (for sandboxed documents) ignored.
442                     m_document->setCookie(m_handshake->serverSetCookie(), IGNORE_EXCEPTION);
443                 }
444             }
445             // FIXME: handle set-cookie2.
446             LOG(Network, "WebSocketChannel %p Connected", this);
447             skipBuffer(headerLength);
448             m_client->didConnect();
449             LOG(Network, "WebSocketChannel %p %lu bytes remaining in m_buffer", this, static_cast<unsigned long>(m_buffer.size()));
450             return !m_buffer.isEmpty();
451         }
452         ASSERT(m_handshake->mode() == WebSocketHandshake::Failed);
453         LOG(Network, "WebSocketChannel %p Connection failed", this);
454         skipBuffer(headerLength);
455         m_shouldDiscardReceivedData = true;
456         fail(m_handshake->failureReason());
457         return false;
458     }
459     if (m_handshake->mode() != WebSocketHandshake::Connected)
460         return false;
461
462     return processFrame();
463 }
464
465 void WebSocketChannel::resumeTimerFired()
466 {
467     Ref<WebSocketChannel> protect(*this); // The client can close the channel, potentially removing the last reference.
468     while (!m_suspended && m_client && !m_buffer.isEmpty())
469         if (!processBuffer())
470             break;
471     if (!m_suspended && m_client && m_closed && m_handle)
472         didCloseSocketStream(m_handle.get());
473 }
474
475 void WebSocketChannel::startClosingHandshake(int code, const String& reason)
476 {
477     LOG(Network, "WebSocketChannel %p startClosingHandshake() code=%d m_receivedClosingHandshake=%d", this, m_closing, m_receivedClosingHandshake);
478     ASSERT(!m_closed);
479     if (m_closing)
480         return;
481     ASSERT(m_handle);
482
483     Vector<char> buf;
484     if (!m_receivedClosingHandshake && code != CloseEventCodeNotSpecified) {
485         unsigned char highByte = code >> 8;
486         unsigned char lowByte = code;
487         buf.append(static_cast<char>(highByte));
488         buf.append(static_cast<char>(lowByte));
489         buf.append(reason.utf8().data(), reason.utf8().length());
490     }
491     enqueueRawFrame(WebSocketFrame::OpCodeClose, buf.data(), buf.size());
492     Ref<WebSocketChannel> protect(*this); // An attempt to send closing handshake may fail, which will get the channel closed and dereferenced.
493     processOutgoingFrameQueue();
494
495     if (m_closed) {
496         // The channel got closed because processOutgoingFrameQueue() failed.
497         return;
498     }
499
500     m_closing = true;
501     if (m_client)
502         m_client->didStartClosingHandshake();
503 }
504
505 void WebSocketChannel::closingTimerFired()
506 {
507     LOG(Network, "WebSocketChannel %p closingTimerFired()", this);
508     if (m_handle)
509         m_handle->disconnect();
510 }
511
512
513 bool WebSocketChannel::processFrame()
514 {
515     ASSERT(!m_buffer.isEmpty());
516
517     WebSocketFrame frame;
518     const char* frameEnd;
519     String errorString;
520     WebSocketFrame::ParseFrameResult result = WebSocketFrame::parseFrame(m_buffer.data(), m_buffer.size(), frame, frameEnd, errorString);
521     if (result == WebSocketFrame::FrameIncomplete)
522         return false;
523     if (result == WebSocketFrame::FrameError) {
524         fail(errorString);
525         return false;
526     }
527
528     ASSERT(m_buffer.data() < frameEnd);
529     ASSERT(frameEnd <= m_buffer.data() + m_buffer.size());
530
531     auto inflateResult = m_deflateFramer.inflate(frame);
532     if (!inflateResult->succeeded()) {
533         fail(inflateResult->failureReason());
534         return false;
535     }
536
537     // Validate the frame data.
538     if (WebSocketFrame::isReservedOpCode(frame.opCode)) {
539         fail("Unrecognized frame opcode: " + String::number(frame.opCode));
540         return false;
541     }
542
543     if (frame.reserved2 || frame.reserved3) {
544         fail("One or more reserved bits are on: reserved2 = " + String::number(frame.reserved2) + ", reserved3 = " + String::number(frame.reserved3));
545         return false;
546     }
547
548     if (frame.masked) {
549         fail("A server must not mask any frames that it sends to the client.");
550         return false;
551     }
552
553     // All control frames must not be fragmented.
554     if (WebSocketFrame::isControlOpCode(frame.opCode) && !frame.final) {
555         fail("Received fragmented control frame: opcode = " + String::number(frame.opCode));
556         return false;
557     }
558
559     // All control frames must have a payload of 125 bytes or less, which means the frame must not contain
560     // the "extended payload length" field.
561     if (WebSocketFrame::isControlOpCode(frame.opCode) && WebSocketFrame::needsExtendedLengthField(frame.payloadLength)) {
562         fail("Received control frame having too long payload: " + String::number(frame.payloadLength) + " bytes");
563         return false;
564     }
565
566     // A new data frame is received before the previous continuous frame finishes.
567     // Note that control frames are allowed to come in the middle of continuous frames.
568     if (m_hasContinuousFrame && frame.opCode != WebSocketFrame::OpCodeContinuation && !WebSocketFrame::isControlOpCode(frame.opCode)) {
569         fail("Received new data frame but previous continuous frame is unfinished.");
570         return false;
571     }
572
573     InspectorInstrumentation::didReceiveWebSocketFrame(m_document, m_identifier, frame);
574
575     switch (frame.opCode) {
576     case WebSocketFrame::OpCodeContinuation:
577         // An unexpected continuation frame is received without any leading frame.
578         if (!m_hasContinuousFrame) {
579             fail("Received unexpected continuation frame.");
580             return false;
581         }
582         m_continuousFrameData.append(frame.payload, frame.payloadLength);
583         skipBuffer(frameEnd - m_buffer.data());
584         if (frame.final) {
585             // onmessage handler may eventually call the other methods of this channel,
586             // so we should pretend that we have finished to read this frame and
587             // make sure that the member variables are in a consistent state before
588             // the handler is invoked.
589             Vector<char> continuousFrameData = WTFMove(m_continuousFrameData);
590             m_hasContinuousFrame = false;
591             if (m_continuousFrameOpCode == WebSocketFrame::OpCodeText) {
592                 String message;
593                 if (continuousFrameData.size())
594                     message = String::fromUTF8(continuousFrameData.data(), continuousFrameData.size());
595                 else
596                     message = emptyString();
597                 if (message.isNull())
598                     fail("Could not decode a text frame as UTF-8.");
599                 else
600                     m_client->didReceiveMessage(message);
601             } else if (m_continuousFrameOpCode == WebSocketFrame::OpCodeBinary)
602                 m_client->didReceiveBinaryData(WTFMove(continuousFrameData));
603         }
604         break;
605
606     case WebSocketFrame::OpCodeText:
607         if (frame.final) {
608             String message;
609             if (frame.payloadLength)
610                 message = String::fromUTF8(frame.payload, frame.payloadLength);
611             else
612                 message = emptyString();
613             skipBuffer(frameEnd - m_buffer.data());
614             if (message.isNull())
615                 fail("Could not decode a text frame as UTF-8.");
616             else
617                 m_client->didReceiveMessage(message);
618         } else {
619             m_hasContinuousFrame = true;
620             m_continuousFrameOpCode = WebSocketFrame::OpCodeText;
621             ASSERT(m_continuousFrameData.isEmpty());
622             m_continuousFrameData.append(frame.payload, frame.payloadLength);
623             skipBuffer(frameEnd - m_buffer.data());
624         }
625         break;
626
627     case WebSocketFrame::OpCodeBinary:
628         if (frame.final) {
629             Vector<char> binaryData(frame.payloadLength);
630             memcpy(binaryData.data(), frame.payload, frame.payloadLength);
631             skipBuffer(frameEnd - m_buffer.data());
632             m_client->didReceiveBinaryData(WTFMove(binaryData));
633         } else {
634             m_hasContinuousFrame = true;
635             m_continuousFrameOpCode = WebSocketFrame::OpCodeBinary;
636             ASSERT(m_continuousFrameData.isEmpty());
637             m_continuousFrameData.append(frame.payload, frame.payloadLength);
638             skipBuffer(frameEnd - m_buffer.data());
639         }
640         break;
641
642     case WebSocketFrame::OpCodeClose:
643         if (!frame.payloadLength)
644             m_closeEventCode = CloseEventCodeNoStatusRcvd;
645         else if (frame.payloadLength == 1) {
646             m_closeEventCode = CloseEventCodeAbnormalClosure;
647             fail("Received a broken close frame containing an invalid size body.");
648             return false;
649         } else {
650             unsigned char highByte = static_cast<unsigned char>(frame.payload[0]);
651             unsigned char lowByte = static_cast<unsigned char>(frame.payload[1]);
652             m_closeEventCode = highByte << 8 | lowByte;
653             if (m_closeEventCode == CloseEventCodeNoStatusRcvd || m_closeEventCode == CloseEventCodeAbnormalClosure || m_closeEventCode == CloseEventCodeTLSHandshake) {
654                 m_closeEventCode = CloseEventCodeAbnormalClosure;
655                 fail("Received a broken close frame containing a reserved status code.");
656                 return false;
657             }
658         }
659         if (frame.payloadLength >= 3)
660             m_closeEventReason = String::fromUTF8(&frame.payload[2], frame.payloadLength - 2);
661         else
662             m_closeEventReason = emptyString();
663         skipBuffer(frameEnd - m_buffer.data());
664         m_receivedClosingHandshake = true;
665         startClosingHandshake(m_closeEventCode, m_closeEventReason);
666         if (m_closing) {
667             if (m_outgoingFrameQueueStatus == OutgoingFrameQueueOpen)
668                 m_outgoingFrameQueueStatus = OutgoingFrameQueueClosing;
669             processOutgoingFrameQueue();
670         }
671         break;
672
673     case WebSocketFrame::OpCodePing:
674         enqueueRawFrame(WebSocketFrame::OpCodePong, frame.payload, frame.payloadLength);
675         skipBuffer(frameEnd - m_buffer.data());
676         processOutgoingFrameQueue();
677         break;
678
679     case WebSocketFrame::OpCodePong:
680         // A server may send a pong in response to our ping, or an unsolicited pong which is not associated with
681         // any specific ping. Either way, there's nothing to do on receipt of pong.
682         skipBuffer(frameEnd - m_buffer.data());
683         break;
684
685     default:
686         ASSERT_NOT_REACHED();
687         skipBuffer(frameEnd - m_buffer.data());
688         break;
689     }
690
691     return !m_buffer.isEmpty();
692 }
693
694 void WebSocketChannel::enqueueTextFrame(const CString& string)
695 {
696     ASSERT(m_outgoingFrameQueueStatus == OutgoingFrameQueueOpen);
697     auto frame = std::make_unique<QueuedFrame>();
698     frame->opCode = WebSocketFrame::OpCodeText;
699     frame->frameType = QueuedFrameTypeString;
700     frame->stringData = string;
701     m_outgoingFrameQueue.append(frame.release());
702 }
703
704 void WebSocketChannel::enqueueRawFrame(WebSocketFrame::OpCode opCode, const char* data, size_t dataLength)
705 {
706     ASSERT(m_outgoingFrameQueueStatus == OutgoingFrameQueueOpen);
707     auto frame = std::make_unique<QueuedFrame>();
708     frame->opCode = opCode;
709     frame->frameType = QueuedFrameTypeVector;
710     frame->vectorData.resize(dataLength);
711     if (dataLength)
712         memcpy(frame->vectorData.data(), data, dataLength);
713     m_outgoingFrameQueue.append(frame.release());
714 }
715
716 void WebSocketChannel::enqueueBlobFrame(WebSocketFrame::OpCode opCode, Blob& blob)
717 {
718     ASSERT(m_outgoingFrameQueueStatus == OutgoingFrameQueueOpen);
719     auto frame = std::make_unique<QueuedFrame>();
720     frame->opCode = opCode;
721     frame->frameType = QueuedFrameTypeBlob;
722     frame->blobData = &blob;
723     m_outgoingFrameQueue.append(frame.release());
724 }
725
726 void WebSocketChannel::processOutgoingFrameQueue()
727 {
728     if (m_outgoingFrameQueueStatus == OutgoingFrameQueueClosed)
729         return;
730
731     Ref<WebSocketChannel> protect(*this); // Any call to fail() will get the channel closed and dereferenced.
732
733     while (!m_outgoingFrameQueue.isEmpty()) {
734         auto frame = m_outgoingFrameQueue.takeFirst();
735         switch (frame->frameType) {
736         case QueuedFrameTypeString: {
737             if (!sendFrame(frame->opCode, frame->stringData.data(), frame->stringData.length()))
738                 fail("Failed to send WebSocket frame.");
739             break;
740         }
741
742         case QueuedFrameTypeVector:
743             if (!sendFrame(frame->opCode, frame->vectorData.data(), frame->vectorData.size()))
744                 fail("Failed to send WebSocket frame.");
745             break;
746
747         case QueuedFrameTypeBlob: {
748             switch (m_blobLoaderStatus) {
749             case BlobLoaderNotStarted:
750                 ref(); // Will be derefed after didFinishLoading() or didFail().
751                 ASSERT(!m_blobLoader);
752                 m_blobLoader = std::make_unique<FileReaderLoader>(FileReaderLoader::ReadAsArrayBuffer, this);
753                 m_blobLoaderStatus = BlobLoaderStarted;
754                 m_blobLoader->start(m_document, frame->blobData.get());
755                 m_outgoingFrameQueue.prepend(frame.release());
756                 return;
757
758             case BlobLoaderStarted:
759             case BlobLoaderFailed:
760                 m_outgoingFrameQueue.prepend(frame.release());
761                 return;
762
763             case BlobLoaderFinished: {
764                 RefPtr<ArrayBuffer> result = m_blobLoader->arrayBufferResult();
765                 m_blobLoader = nullptr;
766                 m_blobLoaderStatus = BlobLoaderNotStarted;
767                 if (!sendFrame(frame->opCode, static_cast<const char*>(result->data()), result->byteLength()))
768                     fail("Failed to send WebSocket frame.");
769                 break;
770             }
771             }
772             break;
773         }
774
775         default:
776             ASSERT_NOT_REACHED();
777             break;
778         }
779     }
780
781     ASSERT(m_outgoingFrameQueue.isEmpty());
782     if (m_outgoingFrameQueueStatus == OutgoingFrameQueueClosing) {
783         m_outgoingFrameQueueStatus = OutgoingFrameQueueClosed;
784         m_handle->close();
785     }
786 }
787
788 void WebSocketChannel::abortOutgoingFrameQueue()
789 {
790     m_outgoingFrameQueue.clear();
791     m_outgoingFrameQueueStatus = OutgoingFrameQueueClosed;
792     if (m_blobLoaderStatus == BlobLoaderStarted) {
793         m_blobLoader->cancel();
794         didFail(FileError::ABORT_ERR);
795     }
796 }
797
798 bool WebSocketChannel::sendFrame(WebSocketFrame::OpCode opCode, const char* data, size_t dataLength)
799 {
800     ASSERT(m_handle);
801     ASSERT(!m_suspended);
802
803     WebSocketFrame frame(opCode, true, false, true, data, dataLength);
804     InspectorInstrumentation::didSendWebSocketFrame(m_document, m_identifier, frame);
805
806     auto deflateResult = m_deflateFramer.deflate(frame);
807     if (!deflateResult->succeeded()) {
808         fail(deflateResult->failureReason());
809         return false;
810     }
811
812     Vector<char> frameData;
813     frame.makeFrameData(frameData);
814
815     return m_handle->send(frameData.data(), frameData.size());
816 }
817
818 }  // namespace WebCore
819
820 #endif  // ENABLE(WEB_SOCKETS)