void WebSocket::connect(const String& url, const Vector<String>& protocols, ExceptionCode& ec) { LOG(Network, "WebSocket %p connect to %s", this, url.utf8().data()); m_url = KURL(KURL(), url); if (!m_url.isValid()) { scriptExecutionContext()->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Invalid url for WebSocket " + m_url.string(), scriptExecutionContext()->securityOrigin()->toString()); m_state = CLOSED; ec = SYNTAX_ERR; return; } if (!m_url.protocolIs("ws") && !m_url.protocolIs("wss")) { scriptExecutionContext()->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Wrong url scheme for WebSocket " + m_url.string(), scriptExecutionContext()->securityOrigin()->toString()); m_state = CLOSED; ec = SYNTAX_ERR; return; } if (m_url.hasFragmentIdentifier()) { scriptExecutionContext()->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "URL has fragment component " + m_url.string(), scriptExecutionContext()->securityOrigin()->toString()); m_state = CLOSED; ec = SYNTAX_ERR; return; } if (!portAllowed(m_url)) { scriptExecutionContext()->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "WebSocket port " + String::number(m_url.port()) + " blocked", scriptExecutionContext()->securityOrigin()->toString()); m_state = CLOSED; ec = SECURITY_ERR; return; } if (!scriptExecutionContext()->contentSecurityPolicy()->allowConnectFromSource(m_url)) { m_state = CLOSED; // FIXME: Should this be throwing an exception? ec = SECURITY_ERR; return; } m_channel = ThreadableWebSocketChannel::create(scriptExecutionContext(), this); m_useHixie76Protocol = m_channel->useHixie76Protocol(); String protocolString; if (m_useHixie76Protocol) { if (!protocols.isEmpty()) { // Emulate JavaScript's Array.toString() behavior. protocolString = joinStrings(protocols, ","); } if (!isValidProtocolStringHixie76(protocolString)) { scriptExecutionContext()->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Wrong protocol for WebSocket '" + encodeProtocolString(protocolString) + "'", scriptExecutionContext()->securityOrigin()->toString()); m_state = CLOSED; ec = SYNTAX_ERR; return; } } else { // 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 SYNTAX_ERR 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])) { scriptExecutionContext()->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Wrong protocol for WebSocket '" + encodeProtocolString(protocols[i]) + "'", scriptExecutionContext()->securityOrigin()->toString()); m_state = CLOSED; ec = SYNTAX_ERR; return; } } HashSet<String> visited; for (size_t i = 0; i < protocols.size(); ++i) { if (visited.contains(protocols[i])) { scriptExecutionContext()->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "WebSocket protocols contain duplicates: '" + encodeProtocolString(protocols[i]) + "'", scriptExecutionContext()->securityOrigin()->toString()); m_state = CLOSED; ec = SYNTAX_ERR; return; } visited.add(protocols[i]); } if (!protocols.isEmpty()) protocolString = joinStrings(protocols, ", "); } m_channel->connect(m_url, protocolString); ActiveDOMObject::setPendingActivity(this); }
void WebSocket::connect(const String& url, const Vector<String>& protocols, ExceptionCode& ec) { LOG(Network, "WebSocket %p connect to %s", this, url.utf8().data()); m_url = KURL(KURL(), url); if (!m_url.isValid()) { scriptExecutionContext()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Invalid url for WebSocket " + m_url.elidedString()); m_state = CLOSED; ec = SYNTAX_ERR; return; } if (!m_url.protocolIs("ws") && !m_url.protocolIs("wss")) { scriptExecutionContext()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Wrong url scheme for WebSocket " + m_url.elidedString()); m_state = CLOSED; ec = SYNTAX_ERR; return; } if (m_url.hasFragmentIdentifier()) { scriptExecutionContext()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "URL has fragment component " + m_url.elidedString()); m_state = CLOSED; ec = SYNTAX_ERR; return; } if (!portAllowed(m_url)) { scriptExecutionContext()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "WebSocket port " + String::number(m_url.port()) + " blocked"); m_state = CLOSED; ec = SECURITY_ERR; return; } // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved. bool shouldBypassMainWorldContentSecurityPolicy = false; if (scriptExecutionContext()->isDocument()) { Document* document = static_cast<Document*>(scriptExecutionContext()); shouldBypassMainWorldContentSecurityPolicy = document->frame()->script()->shouldBypassMainWorldContentSecurityPolicy(); } if (!shouldBypassMainWorldContentSecurityPolicy && !scriptExecutionContext()->contentSecurityPolicy()->allowConnectToSource(m_url)) { m_state = CLOSED; // FIXME: Should this be throwing an exception? ec = SECURITY_ERR; return; } m_channel = ThreadableWebSocketChannel::create(scriptExecutionContext(), 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 SYNTAX_ERR 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])) { scriptExecutionContext()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Wrong protocol for WebSocket '" + encodeProtocolString(protocols[i]) + "'"); m_state = CLOSED; ec = SYNTAX_ERR; return; } } HashSet<String> visited; for (size_t i = 0; i < protocols.size(); ++i) { if (visited.contains(protocols[i])) { scriptExecutionContext()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "WebSocket protocols contain duplicates: '" + encodeProtocolString(protocols[i]) + "'"); m_state = CLOSED; ec = SYNTAX_ERR; return; } visited.add(protocols[i]); } String protocolString; if (!protocols.isEmpty()) protocolString = joinStrings(protocols, subProtocolSeperator()); m_channel->connect(m_url, protocolString); ActiveDOMObject::setPendingActivity(this); }
void WebSocket::connect(const KURL& url, const String& protocol, ExceptionCode& ec) { LOG(Network, "WebSocket %p connect to %s protocol=%s", this, url.string().utf8().data(), protocol.utf8().data()); m_url = url; m_protocol = protocol; if (!m_url.isValid()) { scriptExecutionContext()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Invalid url for WebSocket " + url.string(), 0, scriptExecutionContext()->securityOrigin()->toString()); m_state = CLOSED; ec = SYNTAX_ERR; return; } if (!m_url.protocolIs("ws") && !m_url.protocolIs("wss")) { scriptExecutionContext()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Wrong url scheme for WebSocket " + url.string(), 0, scriptExecutionContext()->securityOrigin()->toString()); m_state = CLOSED; ec = SYNTAX_ERR; return; } if (m_url.hasFragmentIdentifier()) { scriptExecutionContext()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "URL has fragment component " + url.string(), 0, scriptExecutionContext()->securityOrigin()->toString()); m_state = CLOSED; ec = SYNTAX_ERR; return; } if (!isValidProtocolString(m_protocol)) { scriptExecutionContext()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Wrong protocol for WebSocket '" + encodeProtocolString(m_protocol) + "'", 0, scriptExecutionContext()->securityOrigin()->toString()); m_state = CLOSED; ec = SYNTAX_ERR; return; } if (!portAllowed(url)) { scriptExecutionContext()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, String::format("WebSocket port %d blocked", url.port()), 0, scriptExecutionContext()->securityOrigin()->toString()); m_state = CLOSED; ec = SECURITY_ERR; return; } m_channel = ThreadableWebSocketChannel::create(scriptExecutionContext(), this, m_url, m_protocol); m_channel->connect(); ActiveDOMObject::setPendingActivity(this); }