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