Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / modules / websockets / WebSocket.cpp
index 44e1300..2ae0d15 100644 (file)
 #include "core/frame/LocalFrame.h"
 #include "core/frame/csp/ContentSecurityPolicy.h"
 #include "core/inspector/ScriptCallStack.h"
-#include "heap/Handle.h"
 #include "modules/websockets/CloseEvent.h"
 #include "platform/Logging.h"
 #include "platform/blob/BlobData.h"
+#include "platform/heap/Handle.h"
 #include "platform/weborigin/KnownPorts.h"
 #include "platform/weborigin/SecurityOrigin.h"
+#include "public/platform/Platform.h"
 #include "wtf/ArrayBuffer.h"
 #include "wtf/ArrayBufferView.h"
+#include "wtf/Assertions.h"
 #include "wtf/HashSet.h"
 #include "wtf/PassOwnPtr.h"
 #include "wtf/StdLibExtras.h"
@@ -71,7 +73,7 @@ WebSocket::EventQueue::EventQueue(EventTarget* target)
 
 WebSocket::EventQueue::~EventQueue() { stop(); }
 
-void WebSocket::EventQueue::dispatch(PassRefPtr<Event> event)
+void WebSocket::EventQueue::dispatch(PassRefPtrWillBeRawPtr<Event> event)
 {
     switch (m_state) {
     case Active:
@@ -125,9 +127,9 @@ void WebSocket::EventQueue::dispatchQueuedEvents()
     if (m_state != Active)
         return;
 
-    RefPtr<EventQueue> protect(this);
+    RefPtrWillBeRawPtr<EventQueue> protect(this);
 
-    Deque<RefPtr<Event> > events;
+    WillBeHeapDeque<RefPtrWillBeMember<Event> > events;
     events.swap(m_events);
     while (!events.isEmpty()) {
         if (m_state == Stopped || m_state == Suspended)
@@ -151,33 +153,38 @@ void WebSocket::EventQueue::resumeTimerFired(Timer<EventQueue>*)
     dispatchQueuedEvents();
 }
 
+void WebSocket::EventQueue::trace(Visitor* visitor)
+{
+    visitor->trace(m_events);
+}
+
 const size_t maxReasonSizeInBytes = 123;
 
-static inline bool isValidProtocolCharacter(UChar character)
+static inline bool isValidSubprotocolCharacter(UChar character)
 {
-    // Hybi-10 says "(Subprotocol string must consist of) characters in the range U+0021 to U+007E not including
-    // separator characters as defined in [RFC2616]."
     const UChar minimumProtocolCharacter = '!'; // U+0021.
     const UChar maximumProtocolCharacter = '~'; // U+007E.
-    return character >= minimumProtocolCharacter && character <= maximumProtocolCharacter
-        && character != '"' && character != '(' && character != ')' && character != ',' && character != '/'
+    // Set to true if character does not matches "separators" ABNF defined in
+    // RFC2616. SP and HT are excluded since the range check excludes them.
+    bool isNotSeparator = character != '"' && character != '(' && character != ')' && character != ',' && character != '/'
         && !(character >= ':' && character <= '@') // U+003A - U+0040 (':', ';', '<', '=', '>', '?', '@').
         && !(character >= '[' && character <= ']') // U+005B - U+005D ('[', '\\', ']').
         && character != '{' && character != '}';
+    return character >= minimumProtocolCharacter && character <= maximumProtocolCharacter && isNotSeparator;
 }
 
-static bool isValidProtocolString(const String& protocol)
+static bool isValidSubprotocolString(const String& protocol)
 {
     if (protocol.isEmpty())
         return false;
     for (size_t i = 0; i < protocol.length(); ++i) {
-        if (!isValidProtocolCharacter(protocol[i]))
+        if (!isValidSubprotocolCharacter(protocol[i]))
             return false;
     }
     return true;
 }
 
-static String encodeProtocolString(const String& protocol)
+static String encodeSubprotocolString(const String& protocol)
 {
     StringBuilder builder;
     for (size_t i = 0; i < protocol.length(); i++) {
@@ -242,30 +249,30 @@ void WebSocket::logError(const String& message)
     executionContext()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, message);
 }
 
-PassRefPtr<WebSocket> WebSocket::create(ExecutionContext* context, const String& url, ExceptionState& exceptionState)
+PassRefPtrWillBeRawPtr<WebSocket> WebSocket::create(ExecutionContext* context, const String& url, ExceptionState& exceptionState)
 {
     Vector<String> protocols;
     return create(context, url, protocols, exceptionState);
 }
 
-PassRefPtr<WebSocket> WebSocket::create(ExecutionContext* context, const String& url, const Vector<String>& protocols, ExceptionState& exceptionState)
+PassRefPtrWillBeRawPtr<WebSocket> WebSocket::create(ExecutionContext* context, const String& url, const Vector<String>& protocols, ExceptionState& exceptionState)
 {
     if (url.isNull()) {
         exceptionState.throwDOMException(SyntaxError, "Failed to create a WebSocket: the provided URL is invalid.");
         return nullptr;
     }
 
-    RefPtr<WebSocket> webSocket(adoptRef(new WebSocket(context)));
+    RefPtrWillBeRawPtr<WebSocket> webSocket(adoptRefWillBeRefCountedGarbageCollected(new WebSocket(context)));
     webSocket->suspendIfNeeded();
 
-    webSocket->connect(context->completeURL(url), protocols, exceptionState);
+    webSocket->connect(url, protocols, exceptionState);
     if (exceptionState.hadException())
         return nullptr;
 
     return webSocket.release();
 }
 
-PassRefPtr<WebSocket> WebSocket::create(ExecutionContext* context, const String& url, const String& protocol, ExceptionState& exceptionState)
+PassRefPtrWillBeRawPtr<WebSocket> WebSocket::create(ExecutionContext* context, const String& url, const String& protocol, ExceptionState& exceptionState)
 {
     Vector<String> protocols;
     protocols.append(protocol);
@@ -300,11 +307,7 @@ void WebSocket::connect(const String& url, const Vector<String>& protocols, Exce
         exceptionState.throwDOMException(SyntaxError, "The URL's scheme must be either 'ws' or 'wss'. '" + m_url.protocol() + "' is not allowed.");
         return;
     }
-    if (MixedContentChecker::isMixedContent(executionContext()->securityOrigin(), m_url)) {
-        // FIXME: Throw an exception and close the connection.
-        String message = "Connecting to a non-secure WebSocket server from a secure origin is deprecated.";
-        executionContext()->addConsoleMessage(JSMessageSource, WarningMessageLevel, message);
-    }
+
     if (m_url.hasFragmentIdentifier()) {
         m_state = CLOSED;
         exceptionState.throwDOMException(SyntaxError, "The URL contains a fragment identifier ('" + m_url.fragmentIdentifier() + "'). Fragment identifiers are not allowed in WebSocket URLs.");
@@ -331,17 +334,10 @@ void WebSocket::connect(const String& url, const Vector<String>& protocols, Exce
 
     m_channel = WebSocketChannel::create(executionContext(), this);
 
-    // FIXME: There is a disagreement about restriction of subprotocols between WebSocket API and hybi-10 protocol
-    // draft. The former simply says "only characters in the range U+0021 to U+007E are allowed," while the latter
-    // imposes a stricter rule: "the elements MUST be non-empty strings with characters as defined in [RFC2616],
-    // and MUST all be unique strings."
-    //
-    // Here, we throw SyntaxError if the given protocols do not meet the latter criteria. This behavior does not
-    // comply with WebSocket API specification, but it seems to be the only reasonable way to handle this conflict.
     for (size_t i = 0; i < protocols.size(); ++i) {
-        if (!isValidProtocolString(protocols[i])) {
+        if (!isValidSubprotocolString(protocols[i])) {
             m_state = CLOSED;
-            exceptionState.throwDOMException(SyntaxError, "The subprotocol '" + encodeProtocolString(protocols[i]) + "' is invalid.");
+            exceptionState.throwDOMException(SyntaxError, "The subprotocol '" + encodeSubprotocolString(protocols[i]) + "' is invalid.");
             releaseChannel();
             return;
         }
@@ -350,7 +346,7 @@ void WebSocket::connect(const String& url, const Vector<String>& protocols, Exce
     for (size_t i = 0; i < protocols.size(); ++i) {
         if (!visited.add(protocols[i]).isNewEntry) {
             m_state = CLOSED;
-            exceptionState.throwDOMException(SyntaxError, "The subprotocol '" + encodeProtocolString(protocols[i]) + "' is duplicated.");
+            exceptionState.throwDOMException(SyntaxError, "The subprotocol '" + encodeSubprotocolString(protocols[i]) + "' is duplicated.");
             releaseChannel();
             return;
         }
@@ -360,10 +356,15 @@ void WebSocket::connect(const String& url, const Vector<String>& protocols, Exce
     if (!protocols.isEmpty())
         protocolString = joinStrings(protocols, subProtocolSeperator());
 
-    m_channel->connect(m_url, protocolString);
+    if (!m_channel->connect(m_url, protocolString)) {
+        m_state = CLOSED;
+        exceptionState.throwSecurityError("An insecure WebSocket connection may not be initiated from a page loaded over HTTPS.");
+        releaseChannel();
+        return;
+    }
 }
 
-void WebSocket::handleSendResult(WebSocketChannel::SendResult result, ExceptionState& exceptionState)
+void WebSocket::handleSendResult(WebSocketChannel::SendResult result, ExceptionState& exceptionState, WebSocketSendType dataType)
 {
     switch (result) {
     case WebSocketChannel::InvalidMessage:
@@ -373,6 +374,7 @@ void WebSocket::handleSendResult(WebSocketChannel::SendResult result, ExceptionS
         logError("WebSocket send() failed.");
         return;
     case WebSocketChannel::SendSuccess:
+        blink::Platform::current()->histogramEnumeration("WebCore.WebSocket.SendType", dataType, WebSocketSendTypeMax);
         return;
     }
     ASSERT_NOT_REACHED();
@@ -406,7 +408,7 @@ void WebSocket::send(const String& message, ExceptionState& exceptionState)
         return;
     }
     ASSERT(m_channel);
-    handleSendResult(m_channel->send(message), exceptionState);
+    handleSendResult(m_channel->send(message), exceptionState, WebSocketSendTypeString);
 }
 
 void WebSocket::send(ArrayBuffer* binaryData, ExceptionState& exceptionState)
@@ -422,7 +424,7 @@ void WebSocket::send(ArrayBuffer* binaryData, ExceptionState& exceptionState)
         return;
     }
     ASSERT(m_channel);
-    handleSendResult(m_channel->send(*binaryData, 0, binaryData->byteLength()), exceptionState);
+    handleSendResult(m_channel->send(*binaryData, 0, binaryData->byteLength()), exceptionState, WebSocketSendTypeArrayBuffer);
 }
 
 void WebSocket::send(ArrayBufferView* arrayBufferView, ExceptionState& exceptionState)
@@ -439,7 +441,7 @@ void WebSocket::send(ArrayBufferView* arrayBufferView, ExceptionState& exception
     }
     ASSERT(m_channel);
     RefPtr<ArrayBuffer> arrayBuffer(arrayBufferView->buffer());
-    handleSendResult(m_channel->send(*arrayBuffer, arrayBufferView->byteOffset(), arrayBufferView->byteLength()), exceptionState);
+    handleSendResult(m_channel->send(*arrayBuffer, arrayBufferView->byteOffset(), arrayBufferView->byteLength()), exceptionState, WebSocketSendTypeArrayBufferView);
 }
 
 void WebSocket::send(Blob* binaryData, ExceptionState& exceptionState)
@@ -455,7 +457,7 @@ void WebSocket::send(Blob* binaryData, ExceptionState& exceptionState)
         return;
     }
     ASSERT(m_channel);
-    handleSendResult(m_channel->send(binaryData->blobDataHandle()), exceptionState);
+    handleSendResult(m_channel->send(binaryData->blobDataHandle()), exceptionState, WebSocketSendTypeBlob);
 }
 
 void WebSocket::close(unsigned short code, const String& reason, ExceptionState& exceptionState)
@@ -634,7 +636,14 @@ void WebSocket::didReceiveBinaryData(PassOwnPtr<Vector<char> > binaryData)
     }
 
     case BinaryTypeArrayBuffer:
-        m_eventQueue->dispatch(MessageEvent::create(ArrayBuffer::create(binaryData->data(), binaryData->size()), SecurityOrigin::create(m_url)->toString()));
+        RefPtr<ArrayBuffer> arrayBuffer = ArrayBuffer::create(binaryData->data(), binaryData->size());
+        if (!arrayBuffer) {
+            // Failed to allocate an ArrayBuffer. We need to crash the renderer
+            // since there's no way defined in the spec to tell this to the
+            // user.
+            CRASH();
+        }
+        m_eventQueue->dispatch(MessageEvent::create(arrayBuffer.release(), SecurityOrigin::create(m_url)->toString()));
         break;
     }
 }
@@ -687,4 +696,10 @@ size_t WebSocket::getFramingOverhead(size_t payloadSize)
     return overhead;
 }
 
+void WebSocket::trace(Visitor* visitor)
+{
+    visitor->trace(m_channel);
+    visitor->trace(m_eventQueue);
+}
+
 } // namespace WebCore