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