source: trunk/Source/WebCore/Modules/websockets/WebSocketChannel.cpp @ 109840

Revision 109840, 37.8 KB checked in by bashi@chromium.org, 3 years ago (diff)

[WebSocket] Should raise SYNTAX_ERR when message contains unpaired surrogates
https://bugs.webkit.org/show_bug.cgi?id=80103

Reviewed by Kent Tamura.

Source/WebCore:

Add UTF8 validation checks for WebSocket message and close reason.

Tests: http/tests/websocket/tests/hybi/unpaired-surrogates-in-close-reason.html

http/tests/websocket/tests/hybi/unpaired-surrogates-in-message.html

  • Modules/websockets/WebSocket.cpp:

(WebCore::WebSocket::send): Raise SYNTAX_ERR if the message is invalid.
(WebCore::WebSocket::close):Raise SYNTAX_ERR if the reason is invalid.

  • Modules/websockets/WebSocketChannel.cpp:

(WebCore::WebSocketChannel::send): Check whether message is a valid UTF8 string.

LayoutTests:

Added tests for unpaired surrogates check for WebSocket message and close reason.
Updated two expectations for close() tests because further error message is added.

  • http/tests/websocket/tests/hybi/close-expected.txt: Updated.
  • http/tests/websocket/tests/hybi/unpaired-surrogates-in-close-reason-expected.txt: Added.
  • http/tests/websocket/tests/hybi/unpaired-surrogates-in-close-reason.html: Added.
  • http/tests/websocket/tests/hybi/unpaired-surrogates-in-message-expected.txt: Added.
  • http/tests/websocket/tests/hybi/unpaired-surrogates-in-message.html: Added.
  • http/tests/websocket/tests/hybi/workers/close-expected.txt: Updated.
  • Property svn:eol-style set to native
Line 
1/*
2 * Copyright (C) 2011, 2012 Google Inc.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32
33#if ENABLE(WEB_SOCKETS)
34
35#include "WebSocketChannel.h"
36
37#include "Blob.h"
38#include "CookieJar.h"
39#include "Document.h"
40#include "FileError.h"
41#include "FileReaderLoader.h"
42#include "InspectorInstrumentation.h"
43#include "Logging.h"
44#include "Page.h"
45#include "ProgressTracker.h"
46#include "ScriptCallStack.h"
47#include "ScriptExecutionContext.h"
48#include "Settings.h"
49#include "SocketStreamError.h"
50#include "SocketStreamHandle.h"
51#include "WebSocketChannelClient.h"
52#include "WebSocketHandshake.h"
53
54#include <wtf/ArrayBuffer.h>
55#include <wtf/CryptographicallyRandomNumber.h>
56#include <wtf/Deque.h>
57#include <wtf/FastMalloc.h>
58#include <wtf/HashMap.h>
59#include <wtf/OwnPtr.h>
60#include <wtf/PassOwnPtr.h>
61#include <wtf/text/CString.h>
62#include <wtf/text/StringHash.h>
63#include <wtf/text/WTFString.h>
64
65using namespace std;
66
67namespace WebCore {
68
69const double TCPMaximumSegmentLifetime = 2 * 60.0;
70
71// Constants for hybi-10 frame format.
72const unsigned char finalBit = 0x80;
73const unsigned char compressBit = 0x40;
74const unsigned char reserved2Bit = 0x20;
75const unsigned char reserved3Bit = 0x10;
76const unsigned char opCodeMask = 0xF;
77const unsigned char maskBit = 0x80;
78const unsigned char payloadLengthMask = 0x7F;
79const size_t maxPayloadLengthWithoutExtendedLengthField = 125;
80const size_t payloadLengthWithTwoByteExtendedLengthField = 126;
81const size_t payloadLengthWithEightByteExtendedLengthField = 127;
82const size_t maskingKeyWidthInBytes = 4;
83
84WebSocketChannel::WebSocketChannel(Document* document, WebSocketChannelClient* client)
85    : m_document(document)
86    , m_client(client)
87    , m_buffer(0)
88    , m_bufferSize(0)
89    , m_resumeTimer(this, &WebSocketChannel::resumeTimerFired)
90    , m_suspended(false)
91    , m_closing(false)
92    , m_receivedClosingHandshake(false)
93    , m_closingTimer(this, &WebSocketChannel::closingTimerFired)
94    , m_closed(false)
95    , m_shouldDiscardReceivedData(false)
96    , m_unhandledBufferedAmount(0)
97    , m_identifier(0)
98    , m_useHixie76Protocol(true)
99    , m_hasContinuousFrame(false)
100    , m_closeEventCode(CloseEventCodeAbnormalClosure)
101    , m_outgoingFrameQueueStatus(OutgoingFrameQueueOpen)
102#if ENABLE(BLOB)
103    , m_blobLoaderStatus(BlobLoaderNotStarted)
104#endif
105{
106    if (Settings* settings = m_document->settings())
107        m_useHixie76Protocol = settings->useHixie76WebSocketProtocol();
108
109    if (Page* page = m_document->page())
110        m_identifier = page->progress()->createUniqueIdentifier();
111}
112
113WebSocketChannel::~WebSocketChannel()
114{
115    fastFree(m_buffer);
116}
117
118bool WebSocketChannel::useHixie76Protocol()
119{
120    return m_useHixie76Protocol;
121}
122
123void WebSocketChannel::connect(const KURL& url, const String& protocol)
124{
125    LOG(Network, "WebSocketChannel %p connect", this);
126    ASSERT(!m_handle);
127    ASSERT(!m_suspended);
128    m_handshake = adoptPtr(new WebSocketHandshake(url, protocol, m_document, m_useHixie76Protocol));
129    m_handshake->reset();
130    if (!m_useHixie76Protocol && m_deflateFramer.canDeflate())
131        m_handshake->addExtensionProcessor(m_deflateFramer.createExtensionProcessor());
132    if (m_identifier)
133        InspectorInstrumentation::didCreateWebSocket(m_document, m_identifier, url, m_document->url());
134    ref();
135    m_handle = SocketStreamHandle::create(m_handshake->url(), this);
136}
137
138String WebSocketChannel::subprotocol()
139{
140    LOG(Network, "WebSocketChannel %p subprotocol", this);
141    if (!m_handshake || m_handshake->mode() != WebSocketHandshake::Connected)
142        return "";
143    String serverProtocol = m_handshake->serverWebSocketProtocol();
144    if (serverProtocol.isNull())
145        return "";
146    return serverProtocol;
147}
148
149String WebSocketChannel::extensions()
150{
151    LOG(Network, "WebSocketChannel %p extensions", this);
152    if (!m_handshake || m_handshake->mode() != WebSocketHandshake::Connected)
153        return "";
154    String extensions = m_handshake->acceptedExtensions();
155    if (extensions.isNull())
156        return "";
157    return extensions;
158}
159
160ThreadableWebSocketChannel::SendResult WebSocketChannel::send(const String& message)
161{
162    LOG(Network, "WebSocketChannel %p send %s", this, message.utf8().data());
163    CString utf8 = message.utf8(true);
164    if (utf8.isNull() && message.length())
165        return InvalidMessage;
166    if (m_useHixie76Protocol) {
167        return sendFrameHixie76(utf8.data(), utf8.length()) ? ThreadableWebSocketChannel::SendSuccess : ThreadableWebSocketChannel::SendFail;
168    }
169    enqueueTextFrame(utf8);
170    // According to WebSocket API specification, WebSocket.send() should return void instead
171    // of boolean. However, our implementation still returns boolean due to compatibility
172    // concern (see bug 65850).
173    // m_channel->send() may happen later, thus it's not always possible to know whether
174    // the message has been sent to the socket successfully. In this case, we have no choice
175    // but to return true.
176    return ThreadableWebSocketChannel::SendSuccess;
177}
178
179ThreadableWebSocketChannel::SendResult WebSocketChannel::send(const ArrayBuffer& binaryData)
180{
181    LOG(Network, "WebSocketChannel %p send arraybuffer %p", this, &binaryData);
182    ASSERT(!m_useHixie76Protocol);
183    enqueueRawFrame(WebSocketFrame::OpCodeBinary, static_cast<const char*>(binaryData.data()), binaryData.byteLength());
184    return ThreadableWebSocketChannel::SendSuccess;
185}
186
187ThreadableWebSocketChannel::SendResult WebSocketChannel::send(const Blob& binaryData)
188{
189    LOG(Network, "WebSocketChannel %p send blob %s", this, binaryData.url().string().utf8().data());
190    ASSERT(!m_useHixie76Protocol);
191    enqueueBlobFrame(WebSocketFrame::OpCodeBinary, binaryData);
192    return ThreadableWebSocketChannel::SendSuccess;
193}
194
195bool WebSocketChannel::send(const char* data, int length)
196{
197    LOG(Network, "WebSocketChannel %p send binary %p (%dB)", this, data, length);
198    ASSERT(!m_useHixie76Protocol);
199    enqueueRawFrame(WebSocketFrame::OpCodeBinary, data, length);
200    return true;
201}
202
203unsigned long WebSocketChannel::bufferedAmount() const
204{
205    LOG(Network, "WebSocketChannel %p bufferedAmount", this);
206    ASSERT(m_handle);
207    ASSERT(!m_suspended);
208    return m_handle->bufferedAmount();
209}
210
211void WebSocketChannel::close(int code, const String& reason)
212{
213    LOG(Network, "WebSocketChannel %p close", this);
214    ASSERT(!m_suspended);
215    if (!m_handle)
216        return;
217    startClosingHandshake(code, reason);
218    if (m_closing && !m_closingTimer.isActive())
219        m_closingTimer.startOneShot(2 * TCPMaximumSegmentLifetime);
220}
221
222void WebSocketChannel::fail(const String& reason)
223{
224    LOG(Network, "WebSocketChannel %p fail: %s", this, reason.utf8().data());
225    ASSERT(!m_suspended);
226    if (m_document)
227        m_document->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, reason, m_handshake->clientOrigin());
228    if (!m_useHixie76Protocol) {
229        // Hybi-10 specification explicitly states we must not continue to handle incoming data
230        // once the WebSocket connection is failed (section 7.1.7).
231        // FIXME: Should we do this in hixie-76 too?
232        m_shouldDiscardReceivedData = true;
233        if (m_buffer)
234            skipBuffer(m_bufferSize); // Save memory.
235        m_deflateFramer.didFail();
236        m_hasContinuousFrame = false;
237        m_continuousFrameData.clear();
238    }
239    if (m_handle && !m_closed)
240        m_handle->disconnect(); // Will call didClose().
241}
242
243void WebSocketChannel::disconnect()
244{
245    LOG(Network, "WebSocketChannel %p disconnect", this);
246    if (m_identifier && m_document)
247        InspectorInstrumentation::didCloseWebSocket(m_document, m_identifier);
248    if (m_handshake)
249        m_handshake->clearScriptExecutionContext();
250    m_client = 0;
251    m_document = 0;
252    if (m_handle)
253        m_handle->disconnect();
254}
255
256void WebSocketChannel::suspend()
257{
258    m_suspended = true;
259}
260
261void WebSocketChannel::resume()
262{
263    m_suspended = false;
264    if ((m_buffer || m_closed) && m_client && !m_resumeTimer.isActive())
265        m_resumeTimer.startOneShot(0);
266}
267
268void WebSocketChannel::didOpenSocketStream(SocketStreamHandle* handle)
269{
270    LOG(Network, "WebSocketChannel %p didOpenSocketStream", this);
271    ASSERT(handle == m_handle);
272    if (!m_document)
273        return;
274    if (m_identifier)
275        InspectorInstrumentation::willSendWebSocketHandshakeRequest(m_document, m_identifier, m_handshake->clientHandshakeRequest());
276    CString handshakeMessage = m_handshake->clientHandshakeMessage();
277    if (!handle->send(handshakeMessage.data(), handshakeMessage.length()))
278        fail("Failed to send WebSocket handshake.");
279}
280
281void 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_useHixie76Protocol && 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 = 0;
298        m_document = 0;
299        m_handle = 0;
300        if (client)
301            client->didClose(m_unhandledBufferedAmount, m_receivedClosingHandshake ? WebSocketChannelClient::ClosingHandshakeComplete : WebSocketChannelClient::ClosingHandshakeIncomplete, m_closeEventCode, m_closeEventReason);
302    }
303    deref();
304}
305
306void WebSocketChannel::didReceiveSocketStreamData(SocketStreamHandle* handle, const char* data, int len)
307{
308    LOG(Network, "WebSocketChannel %p didReceiveSocketStreamData %d", this, len);
309    RefPtr<WebSocketChannel> protect(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 (len <= 0) {
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, len)) {
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)
331        if (!processBuffer())
332            break;
333}
334
335void WebSocketChannel::didUpdateBufferedAmount(SocketStreamHandle*, size_t bufferedAmount)
336{
337    if (m_client)
338        m_client->didUpdateBufferedAmount(bufferedAmount);
339}
340
341void WebSocketChannel::didFailSocketStream(SocketStreamHandle* handle, const SocketStreamError& error)
342{
343    LOG(Network, "WebSocketChannel %p didFailSocketStream", this);
344    ASSERT(handle == m_handle || !m_handle);
345    if (m_document) {
346        String message;
347        if (error.isNull())
348            message = "WebSocket network error";
349        else if (error.localizedDescription().isNull())
350            message = "WebSocket network error: error code " + String::number(error.errorCode());
351        else
352            message = "WebSocket network error: " + error.localizedDescription();
353        String failingURL = error.failingURL();
354        ASSERT(failingURL.isNull() || m_handshake->url().string() == failingURL);
355        if (failingURL.isNull())
356            failingURL = m_handshake->url().string();
357        m_document->addConsoleMessage(NetworkMessageSource, LogMessageType, ErrorMessageLevel, message, failingURL);
358    }
359    m_shouldDiscardReceivedData = true;
360    handle->disconnect();
361}
362
363void WebSocketChannel::didReceiveAuthenticationChallenge(SocketStreamHandle*, const AuthenticationChallenge&)
364{
365}
366
367void WebSocketChannel::didCancelAuthenticationChallenge(SocketStreamHandle*, const AuthenticationChallenge&)
368{
369}
370
371#if ENABLE(BLOB)
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 %d", this, errorCode);
399    ASSERT(m_blobLoader);
400    ASSERT(m_blobLoaderStatus == BlobLoaderStarted);
401    m_blobLoader.clear();
402    m_blobLoaderStatus = BlobLoaderFailed;
403    fail("Failed to load Blob: error code = " + String::number(errorCode)); // FIXME: Generate human-friendly reason message.
404    deref();
405}
406#endif
407
408bool WebSocketChannel::appendToBuffer(const char* data, size_t len)
409{
410    size_t newBufferSize = m_bufferSize + len;
411    if (newBufferSize < m_bufferSize) {
412        LOG(Network, "WebSocket buffer overflow (%lu+%lu)", static_cast<unsigned long>(m_bufferSize), static_cast<unsigned long>(len));
413        return false;
414    }
415    char* newBuffer = 0;
416    if (!tryFastMalloc(newBufferSize).getValue(newBuffer))
417        return false;
418
419    if (m_buffer)
420        memcpy(newBuffer, m_buffer, m_bufferSize);
421    memcpy(newBuffer + m_bufferSize, data, len);
422    fastFree(m_buffer);
423    m_buffer = newBuffer;
424    m_bufferSize = newBufferSize;
425    return true;
426}
427
428void WebSocketChannel::skipBuffer(size_t len)
429{
430    ASSERT(len <= m_bufferSize);
431    m_bufferSize -= len;
432    if (!m_bufferSize) {
433        fastFree(m_buffer);
434        m_buffer = 0;
435        return;
436    }
437    memmove(m_buffer, m_buffer + len, m_bufferSize);
438}
439
440bool WebSocketChannel::processBuffer()
441{
442    ASSERT(!m_suspended);
443    ASSERT(m_client);
444    ASSERT(m_buffer);
445    LOG(Network, "WebSocketChannel %p processBuffer %lu", this, static_cast<unsigned long>(m_bufferSize));
446
447    if (m_shouldDiscardReceivedData)
448        return false;
449
450    if (m_receivedClosingHandshake) {
451        skipBuffer(m_bufferSize);
452        return false;
453    }
454
455    RefPtr<WebSocketChannel> protect(this); // The client can close the channel, potentially removing the last reference.
456
457    if (m_handshake->mode() == WebSocketHandshake::Incomplete) {
458        int headerLength = m_handshake->readServerHandshake(m_buffer, m_bufferSize);
459        if (headerLength <= 0)
460            return false;
461        if (m_handshake->mode() == WebSocketHandshake::Connected) {
462            if (m_identifier)
463                InspectorInstrumentation::didReceiveWebSocketHandshakeResponse(m_document, m_identifier, m_handshake->serverHandshakeResponse());
464            if (!m_handshake->serverSetCookie().isEmpty()) {
465                if (cookiesEnabled(m_document)) {
466                    ExceptionCode ec; // Exception (for sandboxed documents) ignored.
467                    m_document->setCookie(m_handshake->serverSetCookie(), ec);
468                }
469            }
470            // FIXME: handle set-cookie2.
471            LOG(Network, "WebSocketChannel %p connected", this);
472            skipBuffer(headerLength);
473            m_client->didConnect();
474            LOG(Network, "remaining in read buf %lu", static_cast<unsigned long>(m_bufferSize));
475            return m_buffer;
476        }
477        ASSERT(m_handshake->mode() == WebSocketHandshake::Failed);
478        LOG(Network, "WebSocketChannel %p connection failed", this);
479        skipBuffer(headerLength);
480        m_shouldDiscardReceivedData = true;
481        fail(m_handshake->failureReason());
482        return false;
483    }
484    if (m_handshake->mode() != WebSocketHandshake::Connected)
485        return false;
486
487    if (m_useHixie76Protocol)
488        return processFrameHixie76();
489
490    return processFrame();
491}
492
493void WebSocketChannel::resumeTimerFired(Timer<WebSocketChannel>* timer)
494{
495    ASSERT_UNUSED(timer, timer == &m_resumeTimer);
496
497    RefPtr<WebSocketChannel> protect(this); // The client can close the channel, potentially removing the last reference.
498    while (!m_suspended && m_client && m_buffer)
499        if (!processBuffer())
500            break;
501    if (!m_suspended && m_client && m_closed && m_handle)
502        didCloseSocketStream(m_handle.get());
503}
504
505void WebSocketChannel::startClosingHandshake(int code, const String& reason)
506{
507    LOG(Network, "WebSocketChannel %p closing %d %d", this, m_closing, m_receivedClosingHandshake);
508    if (m_closing)
509        return;
510    ASSERT(m_handle);
511    if (m_useHixie76Protocol) {
512        Vector<char> buf;
513        buf.append('\xff');
514        buf.append('\0');
515        if (!m_handle->send(buf.data(), buf.size())) {
516            m_handle->disconnect();
517            return;
518        }
519    } else {
520        Vector<char> buf;
521        if (!m_receivedClosingHandshake && code != CloseEventCodeNotSpecified) {
522            unsigned char highByte = code >> 8;
523            unsigned char lowByte = code;
524            buf.append(static_cast<char>(highByte));
525            buf.append(static_cast<char>(lowByte));
526            buf.append(reason.utf8().data(), reason.utf8().length());
527        }
528        enqueueRawFrame(WebSocketFrame::OpCodeClose, buf.data(), buf.size());
529    }
530    m_closing = true;
531    if (m_client)
532        m_client->didStartClosingHandshake();
533}
534
535void WebSocketChannel::closingTimerFired(Timer<WebSocketChannel>* timer)
536{
537    LOG(Network, "WebSocketChannel %p closing timer", this);
538    ASSERT_UNUSED(timer, &m_closingTimer == timer);
539    if (m_handle)
540        m_handle->disconnect();
541}
542
543WebSocketChannel::ParseFrameResult WebSocketChannel::parseFrame(WebSocketFrame& frame, const char*& frameEnd)
544{
545    const char* p = m_buffer;
546    const char* bufferEnd = m_buffer + m_bufferSize;
547
548    if (m_bufferSize < 2)
549        return FrameIncomplete;
550
551    unsigned char firstByte = *p++;
552    unsigned char secondByte = *p++;
553
554    bool final = firstByte & finalBit;
555    bool compress = firstByte & compressBit;
556    bool reserved2 = firstByte & reserved2Bit;
557    bool reserved3 = firstByte & reserved3Bit;
558    unsigned char opCode = firstByte & opCodeMask;
559
560    bool masked = secondByte & maskBit;
561    uint64_t payloadLength64 = secondByte & payloadLengthMask;
562    if (payloadLength64 > maxPayloadLengthWithoutExtendedLengthField) {
563        int extendedPayloadLengthSize;
564        if (payloadLength64 == payloadLengthWithTwoByteExtendedLengthField)
565            extendedPayloadLengthSize = 2;
566        else {
567            ASSERT(payloadLength64 == payloadLengthWithEightByteExtendedLengthField);
568            extendedPayloadLengthSize = 8;
569        }
570        if (bufferEnd - p < extendedPayloadLengthSize)
571            return FrameIncomplete;
572        payloadLength64 = 0;
573        for (int i = 0; i < extendedPayloadLengthSize; ++i) {
574            payloadLength64 <<= 8;
575            payloadLength64 |= static_cast<unsigned char>(*p++);
576        }
577    }
578
579    // FIXME: UINT64_C(0x7FFFFFFFFFFFFFFF) should be used but it did not compile on Qt bots.
580#if COMPILER(MSVC)
581    static const uint64_t maxPayloadLength = 0x7FFFFFFFFFFFFFFFui64;
582#else
583    static const uint64_t maxPayloadLength = 0x7FFFFFFFFFFFFFFFull;
584#endif
585    size_t maskingKeyLength = masked ? maskingKeyWidthInBytes : 0;
586    if (payloadLength64 > maxPayloadLength || payloadLength64 + maskingKeyLength > numeric_limits<size_t>::max()) {
587        fail("WebSocket frame length too large: " + String::number(payloadLength64) + " bytes");
588        return FrameError;
589    }
590    size_t payloadLength = static_cast<size_t>(payloadLength64);
591
592    if (static_cast<size_t>(bufferEnd - p) < maskingKeyLength + payloadLength)
593        return FrameIncomplete;
594
595    if (masked) {
596        const char* maskingKey = p;
597        char* payload = const_cast<char*>(p + maskingKeyWidthInBytes);
598        for (size_t i = 0; i < payloadLength; ++i)
599            payload[i] ^= maskingKey[i % maskingKeyWidthInBytes]; // Unmask the payload.
600    }
601
602    frame.opCode = static_cast<WebSocketFrame::OpCode>(opCode);
603    frame.final = final;
604    frame.compress = compress;
605    frame.reserved2 = reserved2;
606    frame.reserved3 = reserved3;
607    frame.masked = masked;
608    frame.payload = p + maskingKeyLength;
609    frame.payloadLength = payloadLength;
610    frameEnd = p + maskingKeyLength + payloadLength;
611    return FrameOK;
612}
613
614bool WebSocketChannel::processFrame()
615{
616    ASSERT(m_buffer);
617
618    WebSocketFrame frame;
619    const char* frameEnd;
620    if (parseFrame(frame, frameEnd) != FrameOK)
621        return false;
622
623    ASSERT(m_buffer < frameEnd);
624    ASSERT(frameEnd <= m_buffer + m_bufferSize);
625
626    OwnPtr<InflateResultHolder> inflateResult = m_deflateFramer.inflate(frame);
627    if (!inflateResult->succeeded()) {
628        fail(inflateResult->failureReason());
629        return false;
630    }
631
632    // Validate the frame data.
633    if (WebSocketFrame::isReservedOpCode(frame.opCode)) {
634        fail("Unrecognized frame opcode: " + String::number(frame.opCode));
635        return false;
636    }
637
638    if (frame.reserved2 || frame.reserved3) {
639        fail("One or more reserved bits are on: reserved2 = " + String::number(frame.reserved2) + ", reserved3 = " + String::number(frame.reserved3));
640        return false;
641    }
642
643    // All control frames must not be fragmented.
644    if (WebSocketFrame::isControlOpCode(frame.opCode) && !frame.final) {
645        fail("Received fragmented control frame: opcode = " + String::number(frame.opCode));
646        return false;
647    }
648
649    // All control frames must have a payload of 125 bytes or less, which means the frame must not contain
650    // the "extended payload length" field.
651    if (WebSocketFrame::isControlOpCode(frame.opCode) && frame.payloadLength > maxPayloadLengthWithoutExtendedLengthField) {
652        fail("Received control frame having too long payload: " + String::number(frame.payloadLength) + " bytes");
653        return false;
654    }
655
656    // A new data frame is received before the previous continuous frame finishes.
657    // Note that control frames are allowed to come in the middle of continuous frames.
658    if (m_hasContinuousFrame && frame.opCode != WebSocketFrame::OpCodeContinuation && !WebSocketFrame::isControlOpCode(frame.opCode)) {
659        fail("Received new data frame but previous continuous frame is unfinished.");
660        return false;
661    }
662
663    switch (frame.opCode) {
664    case WebSocketFrame::OpCodeContinuation:
665        // An unexpected continuation frame is received without any leading frame.
666        if (!m_hasContinuousFrame) {
667            fail("Received unexpected continuation frame.");
668            return false;
669        }
670        m_continuousFrameData.append(frame.payload, frame.payloadLength);
671        skipBuffer(frameEnd - m_buffer);
672        if (frame.final) {
673            // onmessage handler may eventually call the other methods of this channel,
674            // so we should pretend that we have finished to read this frame and
675            // make sure that the member variables are in a consistent state before
676            // the handler is invoked.
677            // Vector<char>::swap() is used here to clear m_continuousFrameData.
678            OwnPtr<Vector<char> > continuousFrameData = adoptPtr(new Vector<char>);
679            m_continuousFrameData.swap(*continuousFrameData);
680            m_hasContinuousFrame = false;
681            if (m_continuousFrameOpCode == WebSocketFrame::OpCodeText) {
682                String message;
683                if (continuousFrameData->size())
684                    message = String::fromUTF8(continuousFrameData->data(), continuousFrameData->size());
685                else
686                    message = "";
687                if (message.isNull())
688                    fail("Could not decode a text frame as UTF-8.");
689                else
690                    m_client->didReceiveMessage(message);
691            } else if (m_continuousFrameOpCode == WebSocketFrame::OpCodeBinary)
692                m_client->didReceiveBinaryData(continuousFrameData.release());
693        }
694        break;
695
696    case WebSocketFrame::OpCodeText:
697        if (frame.final) {
698            String message;
699            if (frame.payloadLength)
700                message = String::fromUTF8(frame.payload, frame.payloadLength);
701            else
702                message = "";
703            skipBuffer(frameEnd - m_buffer);
704            if (message.isNull())
705                fail("Could not decode a text frame as UTF-8.");
706            else
707                m_client->didReceiveMessage(message);
708        } else {
709            m_hasContinuousFrame = true;
710            m_continuousFrameOpCode = WebSocketFrame::OpCodeText;
711            ASSERT(m_continuousFrameData.isEmpty());
712            m_continuousFrameData.append(frame.payload, frame.payloadLength);
713            skipBuffer(frameEnd - m_buffer);
714        }
715        break;
716
717    case WebSocketFrame::OpCodeBinary:
718        if (frame.final) {
719            OwnPtr<Vector<char> > binaryData = adoptPtr(new Vector<char>(frame.payloadLength));
720            memcpy(binaryData->data(), frame.payload, frame.payloadLength);
721            skipBuffer(frameEnd - m_buffer);
722            m_client->didReceiveBinaryData(binaryData.release());
723        } else {
724            m_hasContinuousFrame = true;
725            m_continuousFrameOpCode = WebSocketFrame::OpCodeBinary;
726            ASSERT(m_continuousFrameData.isEmpty());
727            m_continuousFrameData.append(frame.payload, frame.payloadLength);
728            skipBuffer(frameEnd - m_buffer);
729        }
730        break;
731
732    case WebSocketFrame::OpCodeClose:
733        if (frame.payloadLength >= 2) {
734            unsigned char highByte = static_cast<unsigned char>(frame.payload[0]);
735            unsigned char lowByte = static_cast<unsigned char>(frame.payload[1]);
736            m_closeEventCode = highByte << 8 | lowByte;
737        } else
738            m_closeEventCode = CloseEventCodeNoStatusRcvd;
739        if (frame.payloadLength >= 3)
740            m_closeEventReason = String::fromUTF8(&frame.payload[2], frame.payloadLength - 2);
741        else
742            m_closeEventReason = "";
743        skipBuffer(frameEnd - m_buffer);
744        m_receivedClosingHandshake = true;
745        startClosingHandshake(m_closeEventCode, m_closeEventReason);
746        if (m_closing) {
747            m_outgoingFrameQueueStatus = OutgoingFrameQueueClosing;
748            processOutgoingFrameQueue();
749        }
750        break;
751
752    case WebSocketFrame::OpCodePing:
753        enqueueRawFrame(WebSocketFrame::OpCodePong, frame.payload, frame.payloadLength);
754        skipBuffer(frameEnd - m_buffer);
755        break;
756
757    case WebSocketFrame::OpCodePong:
758        // A server may send a pong in response to our ping, or an unsolicited pong which is not associated with
759        // any specific ping. Either way, there's nothing to do on receipt of pong.
760        skipBuffer(frameEnd - m_buffer);
761        break;
762
763    default:
764        ASSERT_NOT_REACHED();
765        skipBuffer(frameEnd - m_buffer);
766        break;
767    }
768
769    return m_buffer;
770}
771
772bool WebSocketChannel::processFrameHixie76()
773{
774    const char* nextFrame = m_buffer;
775    const char* p = m_buffer;
776    const char* end = p + m_bufferSize;
777
778    unsigned char frameByte = static_cast<unsigned char>(*p++);
779    if ((frameByte & 0x80) == 0x80) {
780        size_t length = 0;
781        bool errorFrame = false;
782        bool lengthFinished = false;
783        while (p < end) {
784            if (length > numeric_limits<size_t>::max() / 128) {
785                LOG(Network, "frame length overflow %lu", static_cast<unsigned long>(length));
786                errorFrame = true;
787                break;
788            }
789            size_t newLength = length * 128;
790            unsigned char msgByte = static_cast<unsigned char>(*p);
791            unsigned int lengthMsgByte = msgByte & 0x7f;
792            if (newLength > numeric_limits<size_t>::max() - lengthMsgByte) {
793                LOG(Network, "frame length overflow %lu+%u", static_cast<unsigned long>(newLength), lengthMsgByte);
794                errorFrame = true;
795                break;
796            }
797            newLength += lengthMsgByte;
798            if (newLength < length) { // sanity check
799                LOG(Network, "frame length integer wrap %lu->%lu", static_cast<unsigned long>(length), static_cast<unsigned long>(newLength));
800                errorFrame = true;
801                break;
802            }
803            length = newLength;
804            ++p;
805            if (!(msgByte & 0x80)) {
806                lengthFinished = true;
807                break;
808            }
809        }
810        if (!errorFrame && !lengthFinished)
811            return false;
812        if (p + length < p) {
813            LOG(Network, "frame buffer pointer wrap %p+%lu->%p", p, static_cast<unsigned long>(length), p + length);
814            errorFrame = true;
815        }
816        if (errorFrame) {
817            skipBuffer(m_bufferSize); // Save memory.
818            m_shouldDiscardReceivedData = true;
819            m_client->didReceiveMessageError();
820            fail("WebSocket frame length too large");
821            return false;
822        }
823        ASSERT(p + length >= p);
824        if (p + length <= end) {
825            p += length;
826            nextFrame = p;
827            ASSERT(nextFrame > m_buffer);
828            skipBuffer(nextFrame - m_buffer);
829            if (frameByte == 0xff && !length) {
830                m_receivedClosingHandshake = true;
831                startClosingHandshake(CloseEventCodeNotSpecified, "");
832                if (m_closing)
833                    m_handle->close(); // close after sending FF 00.
834            } else
835                m_client->didReceiveMessageError();
836            return m_buffer;
837        }
838        return false;
839    }
840
841    const char* msgStart = p;
842    while (p < end && *p != '\xff')
843        ++p;
844    if (p < end && *p == '\xff') {
845        int msgLength = p - msgStart;
846        ++p;
847        nextFrame = p;
848        if (frameByte == 0x00) {
849            String msg = String::fromUTF8(msgStart, msgLength);
850            skipBuffer(nextFrame - m_buffer);
851            m_client->didReceiveMessage(msg);
852        } else {
853            skipBuffer(nextFrame - m_buffer);
854            m_client->didReceiveMessageError();
855        }
856        return m_buffer;
857    }
858    return false;
859}
860
861void WebSocketChannel::enqueueTextFrame(const CString& string)
862{
863    ASSERT(!m_useHixie76Protocol);
864    ASSERT(m_outgoingFrameQueueStatus == OutgoingFrameQueueOpen);
865    OwnPtr<QueuedFrame> frame = adoptPtr(new QueuedFrame);
866    frame->opCode = WebSocketFrame::OpCodeText;
867    frame->frameType = QueuedFrameTypeString;
868    frame->stringData = string;
869    m_outgoingFrameQueue.append(frame.release());
870    processOutgoingFrameQueue();
871}
872
873void WebSocketChannel::enqueueRawFrame(WebSocketFrame::OpCode opCode, const char* data, size_t dataLength)
874{
875    ASSERT(!m_useHixie76Protocol);
876    ASSERT(m_outgoingFrameQueueStatus == OutgoingFrameQueueOpen);
877    OwnPtr<QueuedFrame> frame = adoptPtr(new QueuedFrame);
878    frame->opCode = opCode;
879    frame->frameType = QueuedFrameTypeVector;
880    frame->vectorData.resize(dataLength);
881    if (dataLength)
882        memcpy(frame->vectorData.data(), data, dataLength);
883    m_outgoingFrameQueue.append(frame.release());
884    processOutgoingFrameQueue();
885}
886
887void WebSocketChannel::enqueueBlobFrame(WebSocketFrame::OpCode opCode, const Blob& blob)
888{
889    ASSERT(!m_useHixie76Protocol);
890    ASSERT(m_outgoingFrameQueueStatus == OutgoingFrameQueueOpen);
891    OwnPtr<QueuedFrame> frame = adoptPtr(new QueuedFrame);
892    frame->opCode = opCode;
893    frame->frameType = QueuedFrameTypeBlob;
894    frame->blobData = Blob::create(blob.url(), blob.type(), blob.size());
895    m_outgoingFrameQueue.append(frame.release());
896    processOutgoingFrameQueue();
897}
898
899void WebSocketChannel::processOutgoingFrameQueue()
900{
901    ASSERT(!m_useHixie76Protocol);
902    if (m_outgoingFrameQueueStatus == OutgoingFrameQueueClosed)
903        return;
904
905    while (!m_outgoingFrameQueue.isEmpty()) {
906        OwnPtr<QueuedFrame> frame = m_outgoingFrameQueue.takeFirst();
907        switch (frame->frameType) {
908        case QueuedFrameTypeString: {
909            if (!sendFrame(frame->opCode, frame->stringData.data(), frame->stringData.length()))
910                fail("Failed to send WebSocket frame.");
911            break;
912        }
913
914        case QueuedFrameTypeVector:
915            if (!sendFrame(frame->opCode, frame->vectorData.data(), frame->vectorData.size()))
916                fail("Failed to send WebSocket frame.");
917            break;
918
919        case QueuedFrameTypeBlob: {
920#if ENABLE(BLOB)
921            switch (m_blobLoaderStatus) {
922            case BlobLoaderNotStarted:
923                ref(); // Will be derefed after didFinishLoading() or didFail().
924                ASSERT(!m_blobLoader);
925                m_blobLoader = adoptPtr(new FileReaderLoader(FileReaderLoader::ReadAsArrayBuffer, this));
926                m_blobLoaderStatus = BlobLoaderStarted;
927                m_blobLoader->start(m_document, frame->blobData.get());
928                m_outgoingFrameQueue.prepend(frame.release());
929                return;
930
931            case BlobLoaderStarted:
932            case BlobLoaderFailed:
933                m_outgoingFrameQueue.prepend(frame.release());
934                return;
935
936            case BlobLoaderFinished: {
937                RefPtr<ArrayBuffer> result = m_blobLoader->arrayBufferResult();
938                m_blobLoader.clear();
939                m_blobLoaderStatus = BlobLoaderNotStarted;
940                if (!sendFrame(frame->opCode, static_cast<const char*>(result->data()), result->byteLength()))
941                    fail("Failed to send WebSocket frame.");
942                break;
943            }
944            }
945#else
946            fail("FileReader is not available. Could not send a Blob as WebSocket binary message.");
947#endif
948            break;
949        }
950
951        default:
952            ASSERT_NOT_REACHED();
953            break;
954        }
955    }
956
957    ASSERT(m_outgoingFrameQueue.isEmpty());
958    if (m_outgoingFrameQueueStatus == OutgoingFrameQueueClosing) {
959        m_outgoingFrameQueueStatus = OutgoingFrameQueueClosed;
960        m_handle->close();
961    }
962}
963
964void WebSocketChannel::abortOutgoingFrameQueue()
965{
966    ASSERT(!m_useHixie76Protocol);
967    m_outgoingFrameQueue.clear();
968    m_outgoingFrameQueueStatus = OutgoingFrameQueueClosed;
969#if ENABLE(BLOB)
970    if (m_blobLoaderStatus == BlobLoaderStarted) {
971        m_blobLoader->cancel();
972        didFail(FileError::ABORT_ERR);
973    }
974#endif
975}
976
977static void appendMaskedFramePayload(const WebSocketFrame& frame, Vector<char>& frameData)
978{
979    size_t maskingKeyStart = frameData.size();
980    frameData.grow(frameData.size() + maskingKeyWidthInBytes); // Add placeholder for masking key. Will be overwritten.
981    size_t payloadStart = frameData.size();
982    frameData.append(frame.payload, frame.payloadLength);
983
984    cryptographicallyRandomValues(frameData.data() + maskingKeyStart, maskingKeyWidthInBytes);
985    for (size_t i = 0; i < frame.payloadLength; ++i)
986        frameData[payloadStart + i] ^= frameData[maskingKeyStart + i % maskingKeyWidthInBytes];
987}
988
989static void makeFrameData(const WebSocketFrame& frame, Vector<char>& frameData)
990{
991    unsigned char firstByte = (frame.final ? finalBit : 0) | frame.opCode;
992    if (frame.compress)
993        firstByte |= compressBit;
994    frameData.append(firstByte);
995    if (frame.payloadLength <= maxPayloadLengthWithoutExtendedLengthField)
996        frameData.append(maskBit | frame.payloadLength);
997    else if (frame.payloadLength <= 0xFFFF) {
998        frameData.append(maskBit | payloadLengthWithTwoByteExtendedLengthField);
999        frameData.append((frame.payloadLength & 0xFF00) >> 8);
1000        frameData.append(frame.payloadLength & 0xFF);
1001    } else {
1002        frameData.append(maskBit | payloadLengthWithEightByteExtendedLengthField);
1003        char extendedPayloadLength[8];
1004        size_t remaining = frame.payloadLength;
1005        // Fill the length into extendedPayloadLength in the network byte order.
1006        for (int i = 0; i < 8; ++i) {
1007            extendedPayloadLength[7 - i] = remaining & 0xFF;
1008            remaining >>= 8;
1009        }
1010        ASSERT(!remaining);
1011        frameData.append(extendedPayloadLength, 8);
1012    }
1013
1014    appendMaskedFramePayload(frame, frameData);
1015}
1016
1017bool WebSocketChannel::sendFrame(WebSocketFrame::OpCode opCode, const char* data, size_t dataLength)
1018{
1019    ASSERT(m_handle);
1020    ASSERT(!m_suspended);
1021
1022    ASSERT(!(opCode & ~opCodeMask)); // Checks whether "opCode" fits in the range of opCodes.
1023    WebSocketFrame frame(opCode, true, false, true, data, dataLength);
1024
1025    OwnPtr<DeflateResultHolder> deflateResult = m_deflateFramer.deflate(frame);
1026    if (!deflateResult->succeeded()) {
1027        fail(deflateResult->failureReason());
1028        return false;
1029    }
1030
1031    Vector<char> frameData;
1032    makeFrameData(frame, frameData);
1033
1034    return m_handle->send(frameData.data(), frameData.size());
1035}
1036
1037bool WebSocketChannel::sendFrameHixie76(const char* data, size_t dataLength)
1038{
1039    ASSERT(m_handle);
1040    ASSERT(!m_suspended);
1041
1042    Vector<char> frame;
1043    frame.append('\0'); // Frame type.
1044    frame.append(data, dataLength);
1045    frame.append('\xff'); // Frame end.
1046    return m_handle->send(frame.data(), frame.size());
1047}
1048
1049}  // namespace WebCore
1050
1051#endif  // ENABLE(WEB_SOCKETS)
Note: See TracBrowser for help on using the repository browser.