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