#include "core/dom/Document.h"
#include "core/inspector/ScriptCallStack.h"
#include "core/loader/CookieJar.h"
-#include "modules/websockets/WebSocket.h"
+#include "modules/websockets/DOMWebSocket.h"
#include "platform/Cookie.h"
+#include "platform/Crypto.h"
#include "platform/Logging.h"
#include "platform/network/HTTPHeaderMap.h"
#include "platform/network/HTTPParsers.h"
#include "platform/weborigin/SecurityOrigin.h"
#include "public/platform/Platform.h"
#include "wtf/CryptographicallyRandomNumber.h"
-#include "wtf/SHA1.h"
#include "wtf/StdLibExtras.h"
#include "wtf/StringExtras.h"
#include "wtf/Vector.h"
#include "wtf/text/StringBuilder.h"
#include "wtf/unicode/CharacterNames.h"
-namespace WebCore {
-
-namespace {
-
-// FIXME: The spec says that the Sec-WebSocket-Protocol header in a handshake
-// response can't be null if the header in a request is not null.
-// Some servers are not accustomed to the shutdown,
-// so we provide an adhoc white-list for it tentatively.
-const char* const missingProtocolWhiteList[] = {
- "ica.citrix.com",
-};
+namespace blink {
String formatHandshakeFailureReason(const String& detail)
{
return "Error during WebSocket handshake: " + detail;
}
-} // namespace
-
static String resourceName(const KURL& url)
{
StringBuilder name;
String WebSocketHandshake::getExpectedWebSocketAccept(const String& secWebSocketKey)
{
static const char webSocketKeyGUID[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
- SHA1 sha1;
CString keyData = secWebSocketKey.ascii();
- sha1.addBytes(reinterpret_cast<const uint8_t*>(keyData.data()), keyData.length());
- sha1.addBytes(reinterpret_cast<const uint8_t*>(webSocketKeyGUID), strlen(webSocketKeyGUID));
- Vector<uint8_t, SHA1::outputSizeBytes> hash;
- sha1.computeHash(hash);
- return base64Encode(reinterpret_cast<const char*>(hash.data()),
- SHA1::outputSizeBytes);
+
+ StringBuilder digestable;
+ digestable.append(secWebSocketKey);
+ digestable.append(webSocketKeyGUID, strlen(webSocketKeyGUID));
+ CString digestableCString = digestable.toString().utf8();
+ DigestValue digest;
+ bool digestSuccess = computeDigest(HashAlgorithmSha1, digestableCString.data(), digestableCString.length(), digest);
+ RELEASE_ASSERT(digestSuccess);
+
+ return base64Encode(reinterpret_cast<const char*>(digest.data()), sha1HashSize);
}
WebSocketHandshake::WebSocketHandshake(const KURL& url, const String& protocol, Document* document)
WebSocketHandshake::~WebSocketHandshake()
{
- blink::Platform::current()->histogramEnumeration("WebCore.WebSocket.HandshakeResult", m_mode, WebSocketHandshake::ModeMax);
+ Platform::current()->histogramEnumeration("WebCore.WebSocket.HandshakeResult", m_mode, WebSocketHandshake::ModeMax);
}
const KURL& WebSocketHandshake::url() const
if (!m_clientProtocol.isEmpty())
fields.append("Sec-WebSocket-Protocol: " + m_clientProtocol);
- KURL url = httpURLForAuthenticationAndCookies();
-
- String cookie = cookieRequestHeaderFieldValue(m_document, url);
- if (!cookie.isEmpty())
- fields.append("Cookie: " + cookie);
- // Set "Cookie2: <cookie>" if cookies 2 exists for url?
-
// Add no-cache headers to avoid compatibility issue.
// There are some proxies that rewrite "Connection: upgrade"
// to "Connection: close" in the response if a request doesn't contain
void WebSocketHandshake::clearDocument()
{
- m_document = 0;
+ m_document = nullptr;
}
int WebSocketHandshake::readServerHandshake(const char* header, size_t len)
return m_response.headerFields().get("sec-websocket-protocol");
}
-const AtomicString& WebSocketHandshake::serverSetCookie() const
-{
- return m_response.headerFields().get("set-cookie");
-}
-
-const AtomicString& WebSocketHandshake::serverSetCookie2() const
-{
- return m_response.headerFields().get("set-cookie2");
-}
-
const AtomicString& WebSocketHandshake::serverUpgrade() const
{
return m_response.headerFields().get("upgrade");
bool sawSecWebSocketAcceptHeaderField = false;
bool sawSecWebSocketProtocolHeaderField = false;
const char* p = start;
- for (; p < end; p++) {
+ while (p < end) {
size_t consumedLength = parseHTTPHeader(p, end - p, m_failureReason, name, value);
if (!consumedLength)
return 0;
return false;
}
Vector<String> result;
- m_clientProtocol.split(String(WebSocket::subProtocolSeperator()), result);
+ m_clientProtocol.split(String(DOMWebSocket::subprotocolSeperator()), result);
if (!result.contains(serverWebSocketProtocol)) {
m_failureReason = formatHandshakeFailureReason("'Sec-WebSocket-Protocol' header value '" + serverWebSocketProtocol + "' in response does not match any of sent values");
return false;
}
} else if (!m_clientProtocol.isEmpty()) {
- // FIXME: Some servers are not accustomed to this failure, so we provide an adhoc white-list for it tentatively.
- Vector<String> protocols;
- m_clientProtocol.split(String(WebSocket::subProtocolSeperator()), protocols);
- bool match = false;
- for (size_t i = 0; i < protocols.size() && !match; ++i) {
- for (size_t j = 0; j < WTF_ARRAY_LENGTH(missingProtocolWhiteList) && !match; ++j) {
- if (protocols[i] == missingProtocolWhiteList[j])
- match = true;
- }
- }
- if (!match) {
- m_failureReason = formatHandshakeFailureReason("Sent non-empty 'Sec-WebSocket-Protocol' header but no response was received");
- return false;
- }
+ m_failureReason = formatHandshakeFailureReason("Sent non-empty 'Sec-WebSocket-Protocol' header but no response was received");
+ return false;
}
return true;
}
-} // namespace WebCore
+void WebSocketHandshake::trace(Visitor* visitor)
+{
+ visitor->trace(m_document);
+}
+
+} // namespace blink