- add third_party src.
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / modules / websockets / WebSocket.cpp
1 /*
2  * Copyright (C) 2011 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 #include "modules/websockets/WebSocket.h"
34
35 #include "bindings/v8/ExceptionMessages.h"
36 #include "bindings/v8/ExceptionState.h"
37 #include "bindings/v8/ScriptController.h"
38 #include "core/dom/Document.h"
39 #include "core/dom/ExceptionCode.h"
40 #include "core/dom/ExecutionContext.h"
41 #include "core/events/Event.h"
42 #include "core/events/EventListener.h"
43 #include "core/events/MessageEvent.h"
44 #include "core/events/ThreadLocalEventNames.h"
45 #include "core/fileapi/Blob.h"
46 #include "core/frame/ConsoleTypes.h"
47 #include "core/frame/ContentSecurityPolicy.h"
48 #include "core/frame/DOMWindow.h"
49 #include "core/frame/Frame.h"
50 #include "core/inspector/ScriptCallStack.h"
51 #include "modules/websockets/CloseEvent.h"
52 #include "modules/websockets/WebSocketChannel.h"
53 #include "platform/Logging.h"
54 #include "platform/blob/BlobData.h"
55 #include "weborigin/KnownPorts.h"
56 #include "weborigin/SecurityOrigin.h"
57 #include "wtf/ArrayBuffer.h"
58 #include "wtf/ArrayBufferView.h"
59 #include "wtf/Deque.h"
60 #include "wtf/HashSet.h"
61 #include "wtf/OwnPtr.h"
62 #include "wtf/PassOwnPtr.h"
63 #include "wtf/StdLibExtras.h"
64 #include "wtf/text/CString.h"
65 #include "wtf/text/StringBuilder.h"
66 #include "wtf/text/WTFString.h"
67
68 using namespace std;
69
70 namespace WebCore {
71
72 WebSocket::EventQueue::EventQueue(EventTarget* target)
73     : m_state(Active)
74     , m_target(target)
75     , m_resumeTimer(this, &EventQueue::resumeTimerFired) { }
76
77 WebSocket::EventQueue::~EventQueue() { stop(); }
78
79 void WebSocket::EventQueue::dispatch(PassRefPtr<Event> event)
80 {
81     switch (m_state) {
82     case Active:
83         ASSERT(m_events.isEmpty());
84         ASSERT(m_target->executionContext());
85         m_target->dispatchEvent(event);
86         break;
87     case Suspended:
88         m_events.append(event);
89         break;
90     case Stopped:
91         ASSERT(m_events.isEmpty());
92         // Do nothing.
93         break;
94     }
95 }
96
97 void WebSocket::EventQueue::suspend()
98 {
99     if (m_state != Active)
100         return;
101
102     m_state = Suspended;
103 }
104
105 void WebSocket::EventQueue::resume()
106 {
107     if (m_state != Suspended || m_resumeTimer.isActive())
108         return;
109
110     m_resumeTimer.startOneShot(0);
111 }
112
113 void WebSocket::EventQueue::stop()
114 {
115     if (m_state == Stopped)
116         return;
117
118     m_state = Stopped;
119     m_resumeTimer.stop();
120     m_events.clear();
121 }
122
123 void WebSocket::EventQueue::dispatchQueuedEvents()
124 {
125     if (m_state != Active)
126         return;
127
128     RefPtr<EventQueue> protect(this);
129
130     Deque<RefPtr<Event> > events;
131     events.swap(m_events);
132     while (!events.isEmpty()) {
133         if (m_state == Stopped || m_state == Suspended)
134             break;
135         ASSERT(m_state == Active);
136         ASSERT(m_target->executionContext());
137         m_target->dispatchEvent(events.takeFirst());
138         // |this| can be stopped here.
139     }
140     if (m_state == Suspended) {
141         while (!m_events.isEmpty())
142             events.append(m_events.takeFirst());
143         events.swap(m_events);
144     }
145 }
146
147 void WebSocket::EventQueue::resumeTimerFired(Timer<EventQueue>*)
148 {
149     ASSERT(m_state == Suspended);
150     m_state = Active;
151     dispatchQueuedEvents();
152 }
153
154 const size_t maxReasonSizeInBytes = 123;
155
156 static inline bool isValidProtocolCharacter(UChar character)
157 {
158     // Hybi-10 says "(Subprotocol string must consist of) characters in the range U+0021 to U+007E not including
159     // separator characters as defined in [RFC2616]."
160     const UChar minimumProtocolCharacter = '!'; // U+0021.
161     const UChar maximumProtocolCharacter = '~'; // U+007E.
162     return character >= minimumProtocolCharacter && character <= maximumProtocolCharacter
163         && character != '"' && character != '(' && character != ')' && character != ',' && character != '/'
164         && !(character >= ':' && character <= '@') // U+003A - U+0040 (':', ';', '<', '=', '>', '?', '@').
165         && !(character >= '[' && character <= ']') // U+005B - U+005D ('[', '\\', ']').
166         && character != '{' && character != '}';
167 }
168
169 static bool isValidProtocolString(const String& protocol)
170 {
171     if (protocol.isEmpty())
172         return false;
173     for (size_t i = 0; i < protocol.length(); ++i) {
174         if (!isValidProtocolCharacter(protocol[i]))
175             return false;
176     }
177     return true;
178 }
179
180 static String encodeProtocolString(const String& protocol)
181 {
182     StringBuilder builder;
183     for (size_t i = 0; i < protocol.length(); i++) {
184         if (protocol[i] < 0x20 || protocol[i] > 0x7E)
185             builder.append(String::format("\\u%04X", protocol[i]));
186         else if (protocol[i] == 0x5c)
187             builder.append("\\\\");
188         else
189             builder.append(protocol[i]);
190     }
191     return builder.toString();
192 }
193
194 static String joinStrings(const Vector<String>& strings, const char* separator)
195 {
196     StringBuilder builder;
197     for (size_t i = 0; i < strings.size(); ++i) {
198         if (i)
199             builder.append(separator);
200         builder.append(strings[i]);
201     }
202     return builder.toString();
203 }
204
205 static unsigned long saturateAdd(unsigned long a, unsigned long b)
206 {
207     if (numeric_limits<unsigned long>::max() - a < b)
208         return numeric_limits<unsigned long>::max();
209     return a + b;
210 }
211
212 const char* WebSocket::subProtocolSeperator()
213 {
214     return ", ";
215 }
216
217 WebSocket::WebSocket(ExecutionContext* context)
218     : ActiveDOMObject(context)
219     , m_state(CONNECTING)
220     , m_bufferedAmount(0)
221     , m_bufferedAmountAfterClose(0)
222     , m_binaryType(BinaryTypeBlob)
223     , m_subprotocol("")
224     , m_extensions("")
225     , m_dropProtectionRunner(this, &WebSocket::dropProtection)
226     , m_eventQueue(EventQueue::create(this))
227 {
228     ScriptWrappable::init(this);
229 }
230
231 WebSocket::~WebSocket()
232 {
233     if (m_channel)
234         m_channel->disconnect();
235 }
236
237 PassRefPtr<WebSocket> WebSocket::create(ExecutionContext* context, const String& url, ExceptionState& es)
238 {
239     Vector<String> protocols;
240     return create(context, url, protocols, es);
241 }
242
243 PassRefPtr<WebSocket> WebSocket::create(ExecutionContext* context, const String& url, const Vector<String>& protocols, ExceptionState& es)
244 {
245     if (url.isNull()) {
246         es.throwDOMException(SyntaxError, "Failed to create a WebSocket: the provided URL is invalid.");
247         return 0;
248     }
249
250     RefPtr<WebSocket> webSocket(adoptRef(new WebSocket(context)));
251     webSocket->suspendIfNeeded();
252
253     webSocket->connect(context->completeURL(url), protocols, es);
254     if (es.hadException())
255         return 0;
256
257     return webSocket.release();
258 }
259
260 PassRefPtr<WebSocket> WebSocket::create(ExecutionContext* context, const String& url, const String& protocol, ExceptionState& es)
261 {
262     Vector<String> protocols;
263     protocols.append(protocol);
264     return create(context, url, protocols, es);
265 }
266
267 void WebSocket::connect(const String& url, ExceptionState& es)
268 {
269     Vector<String> protocols;
270     connect(url, protocols, es);
271 }
272
273 void WebSocket::connect(const String& url, const String& protocol, ExceptionState& es)
274 {
275     Vector<String> protocols;
276     protocols.append(protocol);
277     connect(url, protocols, es);
278 }
279
280 void WebSocket::connect(const String& url, const Vector<String>& protocols, ExceptionState& es)
281 {
282     LOG(Network, "WebSocket %p connect() url='%s'", this, url.utf8().data());
283     m_url = KURL(KURL(), url);
284
285     if (!m_url.isValid()) {
286         m_state = CLOSED;
287         es.throwDOMException(SyntaxError, ExceptionMessages::failedToExecute("connect", "WebSocket", "the URL '" + url + "' is invalid."));
288         return;
289     }
290     if (!m_url.protocolIs("ws") && !m_url.protocolIs("wss")) {
291         m_state = CLOSED;
292         es.throwDOMException(SyntaxError, ExceptionMessages::failedToExecute("connect", "WebSocket", "The URL's scheme must be either 'ws' or 'wss'. '" + m_url.protocol() + "' is not allowed."));
293         return;
294     }
295     if (m_url.hasFragmentIdentifier()) {
296         m_state = CLOSED;
297         es.throwDOMException(SyntaxError, ExceptionMessages::failedToExecute("connect", "WebSocket", "The URL contains a fragment identifier ('" + m_url.fragmentIdentifier() + "'). Fragment identifiers are not allowed in WebSocket URLs."));
298         return;
299     }
300     if (!portAllowed(m_url)) {
301         m_state = CLOSED;
302         es.throwSecurityError(ExceptionMessages::failedToExecute("connect", "WebSocket", "The port " + String::number(m_url.port()) + " is not allowed."));
303         return;
304     }
305
306     // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved.
307     bool shouldBypassMainWorldContentSecurityPolicy = false;
308     if (executionContext()->isDocument()) {
309         Document* document = toDocument(executionContext());
310         shouldBypassMainWorldContentSecurityPolicy = document->frame()->script().shouldBypassMainWorldContentSecurityPolicy();
311     }
312     if (!shouldBypassMainWorldContentSecurityPolicy && !executionContext()->contentSecurityPolicy()->allowConnectToSource(m_url)) {
313         m_state = CLOSED;
314         // The URL is safe to expose to JavaScript, as this check happens synchronously before redirection.
315         es.throwSecurityError(ExceptionMessages::failedToExecute("connect", "WebSocket", "Refused to connect to '" + m_url.elidedString() + "' because it violates the document's Content Security Policy."));
316         return;
317     }
318
319     m_channel = WebSocketChannel::create(executionContext(), this);
320
321     // FIXME: There is a disagreement about restriction of subprotocols between WebSocket API and hybi-10 protocol
322     // draft. The former simply says "only characters in the range U+0021 to U+007E are allowed," while the latter
323     // imposes a stricter rule: "the elements MUST be non-empty strings with characters as defined in [RFC2616],
324     // and MUST all be unique strings."
325     //
326     // Here, we throw SyntaxError if the given protocols do not meet the latter criteria. This behavior does not
327     // comply with WebSocket API specification, but it seems to be the only reasonable way to handle this conflict.
328     for (size_t i = 0; i < protocols.size(); ++i) {
329         if (!isValidProtocolString(protocols[i])) {
330             m_state = CLOSED;
331             es.throwDOMException(SyntaxError, ExceptionMessages::failedToExecute("connect", "WebSocket", "The subprotocol '" + encodeProtocolString(protocols[i]) + "' is invalid."));
332             return;
333         }
334     }
335     HashSet<String> visited;
336     for (size_t i = 0; i < protocols.size(); ++i) {
337         if (!visited.add(protocols[i]).isNewEntry) {
338             m_state = CLOSED;
339             es.throwDOMException(SyntaxError, ExceptionMessages::failedToExecute("connect", "WebSocket", "The subprotocol '" + encodeProtocolString(protocols[i]) + "' is duplicated."));
340             return;
341         }
342     }
343
344     String protocolString;
345     if (!protocols.isEmpty())
346         protocolString = joinStrings(protocols, subProtocolSeperator());
347
348     m_channel->connect(m_url, protocolString);
349     ActiveDOMObject::setPendingActivity(this);
350 }
351
352 void WebSocket::handleSendResult(WebSocketChannel::SendResult result, ExceptionState& es)
353 {
354     switch (result) {
355     case WebSocketChannel::InvalidMessage:
356         es.throwDOMException(SyntaxError, ExceptionMessages::failedToExecute("send", "WebSocket", "the message contains invalid characters."));
357         return;
358     case WebSocketChannel::SendFail:
359         executionContext()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "WebSocket send() failed.");
360         return;
361     case WebSocketChannel::SendSuccess:
362         return;
363     }
364     ASSERT_NOT_REACHED();
365 }
366
367 void WebSocket::updateBufferedAmountAfterClose(unsigned long payloadSize)
368 {
369     m_bufferedAmountAfterClose = saturateAdd(m_bufferedAmountAfterClose, payloadSize);
370     m_bufferedAmountAfterClose = saturateAdd(m_bufferedAmountAfterClose, getFramingOverhead(payloadSize));
371
372     executionContext()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "WebSocket is already in CLOSING or CLOSED state.");
373 }
374
375 void WebSocket::send(const String& message, ExceptionState& es)
376 {
377     LOG(Network, "WebSocket %p send() Sending String '%s'", this, message.utf8().data());
378     if (m_state == CONNECTING) {
379         es.throwDOMException(InvalidStateError, ExceptionMessages::failedToExecute("send", "WebSocket", "already in CONNECTING state."));
380         return;
381     }
382     // No exception is raised if the connection was once established but has subsequently been closed.
383     if (m_state == CLOSING || m_state == CLOSED) {
384         updateBufferedAmountAfterClose(message.utf8().length());
385         return;
386     }
387     ASSERT(m_channel);
388     handleSendResult(m_channel->send(message), es);
389 }
390
391 void WebSocket::send(ArrayBuffer* binaryData, ExceptionState& es)
392 {
393     LOG(Network, "WebSocket %p send() Sending ArrayBuffer %p", this, binaryData);
394     ASSERT(binaryData);
395     if (m_state == CONNECTING) {
396         es.throwDOMException(InvalidStateError, ExceptionMessages::failedToExecute("send", "WebSocket", "already in CONNECTING state."));
397         return;
398     }
399     if (m_state == CLOSING || m_state == CLOSED) {
400         updateBufferedAmountAfterClose(binaryData->byteLength());
401         return;
402     }
403     ASSERT(m_channel);
404     handleSendResult(m_channel->send(*binaryData, 0, binaryData->byteLength()), es);
405 }
406
407 void WebSocket::send(ArrayBufferView* arrayBufferView, ExceptionState& es)
408 {
409     LOG(Network, "WebSocket %p send() Sending ArrayBufferView %p", this, arrayBufferView);
410     ASSERT(arrayBufferView);
411     if (m_state == CONNECTING) {
412         es.throwDOMException(InvalidStateError, ExceptionMessages::failedToExecute("send", "WebSocket", "already in CONNECTING state."));
413         return;
414     }
415     if (m_state == CLOSING || m_state == CLOSED) {
416         updateBufferedAmountAfterClose(arrayBufferView->byteLength());
417         return;
418     }
419     ASSERT(m_channel);
420     RefPtr<ArrayBuffer> arrayBuffer(arrayBufferView->buffer());
421     handleSendResult(m_channel->send(*arrayBuffer, arrayBufferView->byteOffset(), arrayBufferView->byteLength()), es);
422 }
423
424 void WebSocket::send(Blob* binaryData, ExceptionState& es)
425 {
426     LOG(Network, "WebSocket %p send() Sending Blob '%s'", this, binaryData->uuid().utf8().data());
427     ASSERT(binaryData);
428     if (m_state == CONNECTING) {
429         es.throwDOMException(InvalidStateError, ExceptionMessages::failedToExecute("send", "WebSocket", "already in CONNECTING state."));
430         return;
431     }
432     if (m_state == CLOSING || m_state == CLOSED) {
433         updateBufferedAmountAfterClose(static_cast<unsigned long>(binaryData->size()));
434         return;
435     }
436     ASSERT(m_channel);
437     handleSendResult(m_channel->send(binaryData->blobDataHandle()), es);
438 }
439
440 void WebSocket::close(unsigned short code, const String& reason, ExceptionState& es)
441 {
442     closeInternal(code, reason, es);
443 }
444
445 void WebSocket::close(ExceptionState& es)
446 {
447     closeInternal(WebSocketChannel::CloseEventCodeNotSpecified, String(), es);
448 }
449
450 void WebSocket::close(unsigned short code, ExceptionState& es)
451 {
452     closeInternal(code, String(), es);
453 }
454
455 void WebSocket::closeInternal(int code, const String& reason, ExceptionState& es)
456 {
457     if (code == WebSocketChannel::CloseEventCodeNotSpecified) {
458         LOG(Network, "WebSocket %p close() without code and reason", this);
459     } else {
460         LOG(Network, "WebSocket %p close() code=%d reason='%s'", this, code, reason.utf8().data());
461         if (!(code == WebSocketChannel::CloseEventCodeNormalClosure || (WebSocketChannel::CloseEventCodeMinimumUserDefined <= code && code <= WebSocketChannel::CloseEventCodeMaximumUserDefined))) {
462             es.throwDOMException(InvalidAccessError, ExceptionMessages::failedToExecute("close", "WebSocket", "the code must be either 1000, or between 3000 and 4999. " + String::number(code) + " is neither."));
463             return;
464         }
465         CString utf8 = reason.utf8(String::StrictConversionReplacingUnpairedSurrogatesWithFFFD);
466         if (utf8.length() > maxReasonSizeInBytes) {
467             es.throwDOMException(SyntaxError, ExceptionMessages::failedToExecute("close", "WebSocket", "the message must be smaller than " + String::number(maxReasonSizeInBytes) + " bytes."));
468             return;
469         }
470     }
471
472     if (m_state == CLOSING || m_state == CLOSED)
473         return;
474     if (m_state == CONNECTING) {
475         m_state = CLOSING;
476         m_channel->fail("WebSocket is closed before the connection is established.", WarningMessageLevel);
477         return;
478     }
479     m_state = CLOSING;
480     if (m_channel)
481         m_channel->close(code, reason);
482 }
483
484 const KURL& WebSocket::url() const
485 {
486     return m_url;
487 }
488
489 WebSocket::State WebSocket::readyState() const
490 {
491     return m_state;
492 }
493
494 unsigned long WebSocket::bufferedAmount() const
495 {
496     return saturateAdd(m_bufferedAmount, m_bufferedAmountAfterClose);
497 }
498
499 String WebSocket::protocol() const
500 {
501     return m_subprotocol;
502 }
503
504 String WebSocket::extensions() const
505 {
506     return m_extensions;
507 }
508
509 String WebSocket::binaryType() const
510 {
511     switch (m_binaryType) {
512     case BinaryTypeBlob:
513         return "blob";
514     case BinaryTypeArrayBuffer:
515         return "arraybuffer";
516     }
517     ASSERT_NOT_REACHED();
518     return String();
519 }
520
521 void WebSocket::setBinaryType(const String& binaryType)
522 {
523     if (binaryType == "blob") {
524         m_binaryType = BinaryTypeBlob;
525         return;
526     }
527     if (binaryType == "arraybuffer") {
528         m_binaryType = BinaryTypeArrayBuffer;
529         return;
530     }
531     executionContext()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "'" + binaryType + "' is not a valid value for binaryType; binaryType remains unchanged.");
532 }
533
534 const AtomicString& WebSocket::interfaceName() const
535 {
536     return EventTargetNames::WebSocket;
537 }
538
539 ExecutionContext* WebSocket::executionContext() const
540 {
541     return ActiveDOMObject::executionContext();
542 }
543
544 void WebSocket::contextDestroyed()
545 {
546     LOG(Network, "WebSocket %p contextDestroyed()", this);
547     ASSERT(!m_channel);
548     ASSERT(m_state == CLOSED);
549     ActiveDOMObject::contextDestroyed();
550 }
551
552 void WebSocket::suspend()
553 {
554     if (m_channel)
555         m_channel->suspend();
556     m_eventQueue->suspend();
557 }
558
559 void WebSocket::resume()
560 {
561     if (m_channel)
562         m_channel->resume();
563     m_eventQueue->resume();
564 }
565
566 void WebSocket::dropProtection()
567 {
568     unsetPendingActivity(this);
569 }
570
571 void WebSocket::stop()
572 {
573     m_eventQueue->stop();
574
575     if (!hasPendingActivity()) {
576         ASSERT(!m_channel);
577         ASSERT(m_state == CLOSED);
578         return;
579     }
580     if (m_channel) {
581         m_channel->close(WebSocketChannel::CloseEventCodeGoingAway, String());
582         m_channel->disconnect();
583         m_channel = 0;
584     }
585     m_state = CLOSED;
586
587     ActiveDOMObject::stop();
588
589     // ContextLifecycleNotifier is iterating over the set of ActiveDOMObject
590     // instances. Deleting this WebSocket instance synchronously leads to
591     // ContextLifecycleNotifier::removeObserver() call which is prohibited
592     // to be called during iteration. Defer it.
593     m_dropProtectionRunner.runAsync();
594 }
595
596 void WebSocket::didConnect()
597 {
598     LOG(Network, "WebSocket %p didConnect()", this);
599     if (m_state != CONNECTING)
600         return;
601     m_state = OPEN;
602     m_subprotocol = m_channel->subprotocol();
603     m_extensions = m_channel->extensions();
604     m_eventQueue->dispatch(Event::create(EventTypeNames::open));
605 }
606
607 void WebSocket::didReceiveMessage(const String& msg)
608 {
609     LOG(Network, "WebSocket %p didReceiveMessage() Text message '%s'", this, msg.utf8().data());
610     if (m_state != OPEN)
611         return;
612     m_eventQueue->dispatch(MessageEvent::create(msg, SecurityOrigin::create(m_url)->toString()));
613 }
614
615 void WebSocket::didReceiveBinaryData(PassOwnPtr<Vector<char> > binaryData)
616 {
617     LOG(Network, "WebSocket %p didReceiveBinaryData() %lu byte binary message", this, static_cast<unsigned long>(binaryData->size()));
618     switch (m_binaryType) {
619     case BinaryTypeBlob: {
620         size_t size = binaryData->size();
621         RefPtr<RawData> rawData = RawData::create();
622         binaryData->swap(*rawData->mutableData());
623         OwnPtr<BlobData> blobData = BlobData::create();
624         blobData->appendData(rawData.release(), 0, BlobDataItem::toEndOfFile);
625         RefPtr<Blob> blob = Blob::create(BlobDataHandle::create(blobData.release(), size));
626         m_eventQueue->dispatch(MessageEvent::create(blob.release(), SecurityOrigin::create(m_url)->toString()));
627         break;
628     }
629
630     case BinaryTypeArrayBuffer:
631         m_eventQueue->dispatch(MessageEvent::create(ArrayBuffer::create(binaryData->data(), binaryData->size()), SecurityOrigin::create(m_url)->toString()));
632         break;
633     }
634 }
635
636 void WebSocket::didReceiveMessageError()
637 {
638     LOG(Network, "WebSocket %p didReceiveMessageError()", this);
639     m_eventQueue->dispatch(Event::create(EventTypeNames::error));
640 }
641
642 void WebSocket::didUpdateBufferedAmount(unsigned long bufferedAmount)
643 {
644     LOG(Network, "WebSocket %p didUpdateBufferedAmount() New bufferedAmount is %lu", this, bufferedAmount);
645     if (m_state == CLOSED)
646         return;
647     m_bufferedAmount = bufferedAmount;
648 }
649
650 void WebSocket::didStartClosingHandshake()
651 {
652     LOG(Network, "WebSocket %p didStartClosingHandshake()", this);
653     m_state = CLOSING;
654 }
655
656 void WebSocket::didClose(unsigned long unhandledBufferedAmount, ClosingHandshakeCompletionStatus closingHandshakeCompletion, unsigned short code, const String& reason)
657 {
658     LOG(Network, "WebSocket %p didClose()", this);
659     if (!m_channel)
660         return;
661     bool wasClean = m_state == CLOSING && !unhandledBufferedAmount && closingHandshakeCompletion == ClosingHandshakeComplete && code != WebSocketChannel::CloseEventCodeAbnormalClosure;
662     m_state = CLOSED;
663     m_bufferedAmount = unhandledBufferedAmount;
664     m_eventQueue->dispatch(CloseEvent::create(wasClean, code, reason));
665
666     if (m_channel) {
667         m_channel->disconnect();
668         m_channel = 0;
669     }
670     if (hasPendingActivity())
671         ActiveDOMObject::unsetPendingActivity(this);
672 }
673
674 size_t WebSocket::getFramingOverhead(size_t payloadSize)
675 {
676     static const size_t hybiBaseFramingOverhead = 2; // Every frame has at least two-byte header.
677     static const size_t hybiMaskingKeyLength = 4; // Every frame from client must have masking key.
678     static const size_t minimumPayloadSizeWithTwoByteExtendedPayloadLength = 126;
679     static const size_t minimumPayloadSizeWithEightByteExtendedPayloadLength = 0x10000;
680     size_t overhead = hybiBaseFramingOverhead + hybiMaskingKeyLength;
681     if (payloadSize >= minimumPayloadSizeWithEightByteExtendedPayloadLength)
682         overhead += 8;
683     else if (payloadSize >= minimumPayloadSizeWithTwoByteExtendedPayloadLength)
684         overhead += 2;
685     return overhead;
686 }
687
688 } // namespace WebCore