1231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block/* 2231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * Copyright (C) 2009 Google Inc. All rights reserved. 365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch * Copyright (C) Research In Motion Limited 2011. All rights reserved. 4231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * 5231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * Redistribution and use in source and binary forms, with or without 6231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * modification, are permitted provided that the following conditions are 7231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * met: 8231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * 9231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * * Redistributions of source code must retain the above copyright 10231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * notice, this list of conditions and the following disclaimer. 11231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * * Redistributions in binary form must reproduce the above 12231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * copyright notice, this list of conditions and the following disclaimer 13231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * in the documentation and/or other materials provided with the 14231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * distribution. 15231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * * Neither the name of Google Inc. nor the names of its 16231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * contributors may be used to endorse or promote products derived from 17231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * this software without specific prior written permission. 18231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * 19231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block */ 31231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 32231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "config.h" 33231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 34231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#if ENABLE(WEB_SOCKETS) 35231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 36231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "WebSocketHandshake.h" 37231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 388a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block#include "Cookie.h" 39231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "CookieJar.h" 40231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "Document.h" 41231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "HTTPHeaderMap.h" 42231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "KURL.h" 43231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "Logging.h" 44ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch#include "ScriptCallStack.h" 45231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "ScriptExecutionContext.h" 46231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "SecurityOrigin.h" 4781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#include <wtf/CryptographicallyRandomNumber.h> 48e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block#include <wtf/MD5.h> 49e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block#include <wtf/StdLibExtras.h> 50231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include <wtf/StringExtras.h> 51231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include <wtf/Vector.h> 52f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick#include <wtf/text/AtomicString.h> 53e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block#include <wtf/text/CString.h> 54a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include <wtf/text/StringBuilder.h> 55a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include <wtf/text/StringConcatenate.h> 562fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include <wtf/unicode/CharacterNames.h> 57231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 58231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blocknamespace WebCore { 59231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 60e78cbe89e6f337f2f1fe40315be88f742b547151Steve Blockstatic const char randomCharacterInSecWebSocketKey[] = "!\"#$%&'()*+,-./:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; 61231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 62643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockstatic String resourceName(const KURL& url) 63643ca7872b450ea4efacab6188849e5aac2ba161Steve Block{ 64d0825bca7fe65beaee391d30da42e937db621564Steve Block String name = url.path(); 65d0825bca7fe65beaee391d30da42e937db621564Steve Block if (name.isEmpty()) 66d0825bca7fe65beaee391d30da42e937db621564Steve Block name = "/"; 67d0825bca7fe65beaee391d30da42e937db621564Steve Block if (!url.query().isNull()) 68d0825bca7fe65beaee391d30da42e937db621564Steve Block name += "?" + url.query(); 69d0825bca7fe65beaee391d30da42e937db621564Steve Block ASSERT(!name.isEmpty()); 70d0825bca7fe65beaee391d30da42e937db621564Steve Block ASSERT(!name.contains(' ')); 71d0825bca7fe65beaee391d30da42e937db621564Steve Block return name; 72643ca7872b450ea4efacab6188849e5aac2ba161Steve Block} 73643ca7872b450ea4efacab6188849e5aac2ba161Steve Block 74e78cbe89e6f337f2f1fe40315be88f742b547151Steve Blockstatic String hostName(const KURL& url, bool secure) 75e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block{ 76e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block ASSERT(url.protocolIs("wss") == secure); 77e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block StringBuilder builder; 78e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block builder.append(url.host().lower()); 79e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block if (url.port() && ((!secure && url.port() != 80) || (secure && url.port() != 443))) { 80a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch builder.append(':'); 81e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block builder.append(String::number(url.port())); 82e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block } 83e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block return builder.toString(); 84e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block} 85e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block 8606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsenstatic const size_t maxConsoleMessageSize = 128; 87dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockstatic String trimConsoleMessage(const char* p, size_t len) 88dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{ 8906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen String s = String(p, std::min<size_t>(len, maxConsoleMessageSize)); 9006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (len > maxConsoleMessageSize) 9106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen s.append(horizontalEllipsis); 92dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return s; 93dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block} 94dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 9581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochstatic uint32_t randomNumberLessThan(uint32_t n) 9681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{ 9781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (!n) 9881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return 0; 9981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (n == std::numeric_limits<uint32_t>::max()) 10081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return cryptographicallyRandomNumber(); 10181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch uint32_t max = std::numeric_limits<uint32_t>::max() - (std::numeric_limits<uint32_t>::max() % n); 10281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch ASSERT(!(max % n)); 10381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch uint32_t v; 10481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch do { 10581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch v = cryptographicallyRandomNumber(); 10681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch } while (v >= max); 10781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return v % n; 10881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch} 10981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch 110e78cbe89e6f337f2f1fe40315be88f742b547151Steve Blockstatic void generateSecWebSocketKey(uint32_t& number, String& key) 111e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block{ 11281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch uint32_t space = randomNumberLessThan(12) + 1; 113e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block uint32_t max = 4294967295U / space; 11481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch number = randomNumberLessThan(max); 115e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block uint32_t product = number * space; 116e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block 117e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block String s = String::number(product); 11881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch int n = randomNumberLessThan(12) + 1; 119e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block DEFINE_STATIC_LOCAL(String, randomChars, (randomCharacterInSecWebSocketKey)); 120e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block for (int i = 0; i < n; i++) { 12181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch int pos = randomNumberLessThan(s.length() + 1); 12281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch int chpos = randomNumberLessThan(randomChars.length()); 123e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block s.insert(randomChars.substring(chpos, 1), pos); 124e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block } 125e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block DEFINE_STATIC_LOCAL(String, spaceChar, (" ")); 126e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block for (uint32_t i = 0; i < space; i++) { 12781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch int pos = randomNumberLessThan(s.length() - 1) + 1; 128e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block s.insert(spaceChar, pos); 129e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block } 130ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block ASSERT(s[0] != ' '); 131ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block ASSERT(s[s.length() - 1] != ' '); 132e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block key = s; 133e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block} 134e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block 135e78cbe89e6f337f2f1fe40315be88f742b547151Steve Blockstatic void generateKey3(unsigned char key3[8]) 136e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block{ 13781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch cryptographicallyRandomValues(key3, 8); 138e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block} 139e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block 140e78cbe89e6f337f2f1fe40315be88f742b547151Steve Blockstatic void setChallengeNumber(unsigned char* buf, uint32_t number) 141e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block{ 142e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block unsigned char* p = buf + 3; 143e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block for (int i = 0; i < 4; i++) { 144e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block *p = number & 0xFF; 145e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block --p; 146e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block number >>= 8; 147e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block } 148e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block} 149e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block 150e78cbe89e6f337f2f1fe40315be88f742b547151Steve Blockstatic void generateExpectedChallengeResponse(uint32_t number1, uint32_t number2, unsigned char key3[8], unsigned char expectedChallenge[16]) 151e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block{ 152e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block unsigned char challenge[16]; 153e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block setChallengeNumber(&challenge[0], number1); 154e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block setChallengeNumber(&challenge[4], number2); 155e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block memcpy(&challenge[8], key3, 8); 156e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block MD5 md5; 157e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block md5.addBytes(challenge, sizeof(challenge)); 158e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block Vector<uint8_t, 16> digest; 159e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block md5.checksum(digest); 160e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block memcpy(expectedChallenge, digest.data(), 16); 161e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block} 162e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block 163231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockWebSocketHandshake::WebSocketHandshake(const KURL& url, const String& protocol, ScriptExecutionContext* context) 164231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block : m_url(url) 165231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block , m_clientProtocol(protocol) 166231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block , m_secure(m_url.protocolIs("wss")) 167231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block , m_context(context) 168231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block , m_mode(Incomplete) 169231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 170e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block uint32_t number1; 171e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block uint32_t number2; 172e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block generateSecWebSocketKey(number1, m_secWebSocketKey1); 173e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block generateSecWebSocketKey(number2, m_secWebSocketKey2); 174e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block generateKey3(m_key3); 175e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block generateExpectedChallengeResponse(number1, number2, m_key3, m_expectedChallengeResponse); 176231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 177231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 178231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockWebSocketHandshake::~WebSocketHandshake() 179231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 180231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 181231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 182231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockconst KURL& WebSocketHandshake::url() const 183231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 184231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return m_url; 185231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 186231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 187231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid WebSocketHandshake::setURL(const KURL& url) 188231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 189231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_url = url.copy(); 190231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 191231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 192231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockconst String WebSocketHandshake::host() const 193231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 194231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return m_url.host().lower(); 195231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 196231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 197231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockconst String& WebSocketHandshake::clientProtocol() const 198231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 199231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return m_clientProtocol; 200231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 201231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 202231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid WebSocketHandshake::setClientProtocol(const String& protocol) 203231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 204231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_clientProtocol = protocol; 205231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 206231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 207231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockbool WebSocketHandshake::secure() const 208231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 209231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return m_secure; 210231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 211231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 212231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockString WebSocketHandshake::clientOrigin() const 213231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 214231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return m_context->securityOrigin()->toString(); 215231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 216231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 217231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockString WebSocketHandshake::clientLocation() const 218231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 219231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block StringBuilder builder; 220231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block builder.append(m_secure ? "wss" : "ws"); 221231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block builder.append("://"); 222e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block builder.append(hostName(m_url, m_secure)); 223643ca7872b450ea4efacab6188849e5aac2ba161Steve Block builder.append(resourceName(m_url)); 224231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return builder.toString(); 225231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 226231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 227231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockCString WebSocketHandshake::clientHandshakeMessage() const 228231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 229dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // Keep the following consistent with clientHandshakeRequest(). 230231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block StringBuilder builder; 231231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 232231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block builder.append("GET "); 233643ca7872b450ea4efacab6188849e5aac2ba161Steve Block builder.append(resourceName(m_url)); 234231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block builder.append(" HTTP/1.1\r\n"); 235e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block 236e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block Vector<String> fields; 237e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block fields.append("Upgrade: WebSocket"); 238e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block fields.append("Connection: Upgrade"); 239e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block fields.append("Host: " + hostName(m_url, m_secure)); 240e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block fields.append("Origin: " + clientOrigin()); 241e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block if (!m_clientProtocol.isEmpty()) 242e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block fields.append("Sec-WebSocket-Protocol: " + m_clientProtocol); 243dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 244231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block KURL url = httpURLForAuthenticationAndCookies(); 245231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (m_context->isDocument()) { 246231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block Document* document = static_cast<Document*>(m_context); 2478a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block String cookie = cookieRequestHeaderFieldValue(document, url); 248e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block if (!cookie.isEmpty()) 249e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block fields.append("Cookie: " + cookie); 250231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block // Set "Cookie2: <cookie>" if cookies 2 exists for url? 251231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 252dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 253e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block fields.append("Sec-WebSocket-Key1: " + m_secWebSocketKey1); 254e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block fields.append("Sec-WebSocket-Key2: " + m_secWebSocketKey2); 255e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block 256e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block // Fields in the handshake are sent by the client in a random order; the 257e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block // order is not meaningful. Thus, it's ok to send the order we constructed 258e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block // the fields. 259e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block 260e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block for (size_t i = 0; i < fields.size(); i++) { 261e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block builder.append(fields[i]); 262e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block builder.append("\r\n"); 263e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block } 264e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block 265231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block builder.append("\r\n"); 266e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block 267e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block CString handshakeHeader = builder.toString().utf8(); 268e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block char* characterBuffer = 0; 269e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block CString msg = CString::newUninitialized(handshakeHeader.length() + sizeof(m_key3), characterBuffer); 270e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block memcpy(characterBuffer, handshakeHeader.data(), handshakeHeader.length()); 271e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block memcpy(characterBuffer + handshakeHeader.length(), m_key3, sizeof(m_key3)); 272e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block return msg; 273231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 274231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 275dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve BlockWebSocketHandshakeRequest WebSocketHandshake::clientHandshakeRequest() const 276dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{ 277dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // Keep the following consistent with clientHandshakeMessage(). 278e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block // FIXME: do we need to store m_secWebSocketKey1, m_secWebSocketKey2 and 279e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block // m_key3 in WebSocketHandshakeRequest? 28006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen WebSocketHandshakeRequest request("GET", m_url); 28106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen request.addHeaderField("Upgrade", "WebSocket"); 28206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen request.addHeaderField("Connection", "Upgrade"); 28306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen request.addHeaderField("Host", hostName(m_url, m_secure)); 28406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen request.addHeaderField("Origin", clientOrigin()); 28506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (!m_clientProtocol.isEmpty()) 28606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen request.addHeaderField("Sec-WebSocket-Protocol:", m_clientProtocol); 287dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 288dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block KURL url = httpURLForAuthenticationAndCookies(); 289dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (m_context->isDocument()) { 290dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block Document* document = static_cast<Document*>(m_context); 291dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block String cookie = cookieRequestHeaderFieldValue(document, url); 292dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (!cookie.isEmpty()) 29306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen request.addHeaderField("Cookie", cookie); 294dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // Set "Cookie2: <cookie>" if cookies 2 exists for url? 295dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 296dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 29706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen request.addHeaderField("Sec-WebSocket-Key1", m_secWebSocketKey1); 29806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen request.addHeaderField("Sec-WebSocket-Key2", m_secWebSocketKey2); 29906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen request.setKey3(m_key3); 30006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 301dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return request; 302dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block} 303dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 304231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid WebSocketHandshake::reset() 305231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 306231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_mode = Incomplete; 307231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 308231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 309dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvoid WebSocketHandshake::clearScriptExecutionContext() 310dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{ 311dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block m_context = 0; 312dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block} 313dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 314231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockint WebSocketHandshake::readServerHandshake(const char* header, size_t len) 315231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 316231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_mode = Incomplete; 31706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen int statusCode; 31806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen String statusText; 31906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen int lineLength = readStatusLine(header, len, statusCode, statusText); 32006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (lineLength == -1) 321231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return -1; 32206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (statusCode == -1) { 323e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block m_mode = Failed; 324e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block return len; 325231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 32606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen LOG(Network, "response code: %d", statusCode); 32706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen m_response.setStatusCode(statusCode); 32806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen m_response.setStatusText(statusText); 32906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (statusCode != 101) { 330e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block m_mode = Failed; 331ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, makeString("Unexpected response code: ", String::number(statusCode)), 0, clientOrigin(), 0); 332e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block return len; 333231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 334e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block m_mode = Normal; 335e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block if (!strnstr(header, "\r\n\r\n", len)) { 336231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block // Just hasn't been received fully yet. 337d0825bca7fe65beaee391d30da42e937db621564Steve Block m_mode = Incomplete; 338231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return -1; 339231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 34006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen const char* p = readHTTPHeaders(header + lineLength, header + len); 341231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (!p) { 342231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block LOG(Network, "readHTTPHeaders failed"); 343231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_mode = Failed; 344231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return len; 345231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 34606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (!checkResponseHeaders()) { 347231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block LOG(Network, "header process failed"); 348231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_mode = Failed; 349231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return p - header; 350231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 351e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block if (len < static_cast<size_t>(p - header + sizeof(m_expectedChallengeResponse))) { 352e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block // Just hasn't been received /expected/ yet. 353e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block m_mode = Incomplete; 354e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block return -1; 355e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block } 35606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen m_response.setChallengeResponse(static_cast<const unsigned char*>(static_cast<const void*>(p))); 357e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block if (memcmp(p, m_expectedChallengeResponse, sizeof(m_expectedChallengeResponse))) { 358231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_mode = Failed; 359e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block return (p - header) + sizeof(m_expectedChallengeResponse); 360231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 361e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block m_mode = Connected; 362e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block return (p - header) + sizeof(m_expectedChallengeResponse); 363231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 364231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 365231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockWebSocketHandshake::Mode WebSocketHandshake::mode() const 366231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 367231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return m_mode; 368231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 369231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 37081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen MurdochString WebSocketHandshake::serverWebSocketOrigin() const 371231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 37281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return m_response.headerFields().get("sec-websocket-origin"); 373231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 374231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 37581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen MurdochString WebSocketHandshake::serverWebSocketLocation() const 376231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 37781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return m_response.headerFields().get("sec-websocket-location"); 378231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 379231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 38081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen MurdochString WebSocketHandshake::serverWebSocketProtocol() const 381231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 38281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return m_response.headerFields().get("sec-websocket-protocol"); 383231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 384231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 38581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen MurdochString WebSocketHandshake::serverSetCookie() const 386231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 38781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return m_response.headerFields().get("set-cookie"); 388231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 389231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 39081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen MurdochString WebSocketHandshake::serverSetCookie2() const 391231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 39281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return m_response.headerFields().get("set-cookie2"); 393231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 394231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 39581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen MurdochString WebSocketHandshake::serverUpgrade() const 396231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 39781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return m_response.headerFields().get("upgrade"); 398231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 399231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 40081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen MurdochString WebSocketHandshake::serverConnection() const 401231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 40281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return m_response.headerFields().get("connection"); 403231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 404231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 40506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsenconst WebSocketHandshakeResponse& WebSocketHandshake::serverHandshakeResponse() const 40606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen{ 40706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen return m_response; 40806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen} 40906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 410231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockKURL WebSocketHandshake::httpURLForAuthenticationAndCookies() const 411231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 412231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block KURL url = m_url.copy(); 413d0825bca7fe65beaee391d30da42e937db621564Steve Block bool couldSetProtocol = url.setProtocol(m_secure ? "https" : "http"); 414d0825bca7fe65beaee391d30da42e937db621564Steve Block ASSERT_UNUSED(couldSetProtocol, couldSetProtocol); 415231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return url; 416231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 417231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 41806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen// Returns the header length (including "\r\n"), or -1 if we have not received enough data yet. 41906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen// If the line is malformed or the status code is not a 3-digit number, 42006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen// statusCode and statusText will be set to -1 and a null string, respectively. 42106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsenint WebSocketHandshake::readStatusLine(const char* header, size_t headerLength, int& statusCode, String& statusText) 42206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen{ 42365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch // Arbitrary size limit to prevent the server from sending an unbounded 42465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch // amount of data with no newlines and forcing us to buffer it all. 42565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch static const int maximumLength = 1024; 42665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 42706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen statusCode = -1; 42806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen statusText = String(); 42906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 43006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen const char* space1 = 0; 43106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen const char* space2 = 0; 43206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen const char* p; 43306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen size_t consumedLength; 43406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 43506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen for (p = header, consumedLength = 0; consumedLength < headerLength; p++, consumedLength++) { 43606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (*p == ' ') { 43706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (!space1) 43806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen space1 = p; 43906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen else if (!space2) 44006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen space2 = p; 44165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch } else if (*p == '\0') { 44265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch // The caller isn't prepared to deal with null bytes in status 44365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch // line. WebSockets specification doesn't prohibit this, but HTTP 44465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch // does, so we'll just treat this as an error. 445ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Status line contains embedded null", 0, clientOrigin(), 0); 44665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch return p + 1 - header; 44706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen } else if (*p == '\n') 44806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen break; 44906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen } 45006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (consumedLength == headerLength) 45106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen return -1; // We have not received '\n' yet. 45206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 45306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen const char* end = p + 1; 45465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch if (end - header > maximumLength) { 455ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Status line is too long", 0, clientOrigin(), 0); 45665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch return maximumLength; 45706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen } 45806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen int lineLength = end - header; 45906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 46006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (!space1 || !space2) { 461ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "No response code found: " + trimConsoleMessage(header, lineLength - 1), 0, clientOrigin(), 0); 46206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen return lineLength; 46306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen } 46406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 46506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen // The line must end with "\r\n". 46606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (*(end - 2) != '\r') { 467ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Status line does not end with CRLF", 0, clientOrigin(), 0); 46806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen return lineLength; 46906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen } 47006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 47106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen String statusCodeString(space1 + 1, space2 - space1 - 1); 47206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (statusCodeString.length() != 3) // Status code must consist of three digits. 47306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen return lineLength; 47406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen for (int i = 0; i < 3; ++i) 47506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (statusCodeString[i] < '0' || statusCodeString[i] > '9') { 476ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Invalid status code: " + statusCodeString, 0, clientOrigin(), 0); 47706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen return lineLength; 47806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen } 47906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 48006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen bool ok = false; 48106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen statusCode = statusCodeString.toInt(&ok); 48206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen ASSERT(ok); 48306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 48406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen statusText = String(space2 + 1, end - space2 - 3); // Exclude "\r\n". 48506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen return lineLength; 48606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen} 48706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 48806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsenconst char* WebSocketHandshake::readHTTPHeaders(const char* start, const char* end) 489231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 49006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen m_response.clearHeaderFields(); 49106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 492231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block Vector<char> name; 493231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block Vector<char> value; 494231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block for (const char* p = start; p < end; p++) { 495231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block name.clear(); 496231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block value.clear(); 497231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 498231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block for (; p < end; p++) { 499231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block switch (*p) { 500231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block case '\r': 501231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (name.isEmpty()) { 502231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (p + 1 < end && *(p + 1) == '\n') 503231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return p + 2; 504ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "CR doesn't follow LF at " + trimConsoleMessage(p, end - p), 0, clientOrigin(), 0); 505231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return 0; 506231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 507ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Unexpected CR in name at " + trimConsoleMessage(name.data(), name.size()), 0, clientOrigin(), 0); 508231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return 0; 509231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block case '\n': 510ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Unexpected LF in name at " + trimConsoleMessage(name.data(), name.size()), 0, clientOrigin(), 0); 511231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return 0; 512231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block case ':': 513231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block break; 514231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block default: 51506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen name.append(*p); 516231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block continue; 517231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 518231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (*p == ':') { 519231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block ++p; 520231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block break; 521231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 522231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 523231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 524231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block for (; p < end && *p == 0x20; p++) { } 525231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 526231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block for (; p < end; p++) { 527231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block switch (*p) { 528231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block case '\r': 529231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block break; 530231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block case '\n': 531ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Unexpected LF in value at " + trimConsoleMessage(value.data(), value.size()), 0, clientOrigin(), 0); 532231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return 0; 533231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block default: 534231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block value.append(*p); 535231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 536231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (*p == '\r') { 537231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block ++p; 538231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block break; 539231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 540231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 541231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (p >= end || *p != '\n') { 542ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "CR doesn't follow LF after value at " + trimConsoleMessage(p, end - p), 0, clientOrigin(), 0); 543231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return 0; 544231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 54581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch AtomicString nameStr = AtomicString::fromUTF8(name.data(), name.size()); 546231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block String valueStr = String::fromUTF8(value.data(), value.size()); 547dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (nameStr.isNull()) { 548ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "invalid UTF-8 sequence in header name", 0, clientOrigin(), 0); 549dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return 0; 550dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 551dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (valueStr.isNull()) { 552ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "invalid UTF-8 sequence in header value", 0, clientOrigin(), 0); 553dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return 0; 554dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 555231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block LOG(Network, "name=%s value=%s", nameStr.string().utf8().data(), valueStr.utf8().data()); 55606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen m_response.addHeaderField(nameStr, valueStr); 557231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 558231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block ASSERT_NOT_REACHED(); 559231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return 0; 560231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 561231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 562e78cbe89e6f337f2f1fe40315be88f742b547151Steve Blockbool WebSocketHandshake::checkResponseHeaders() 563231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 56481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch const String& serverWebSocketLocation = this->serverWebSocketLocation(); 56581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch const String& serverWebSocketOrigin = this->serverWebSocketOrigin(); 56681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch const String& serverWebSocketProtocol = this->serverWebSocketProtocol(); 56781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch const String& serverUpgrade = this->serverUpgrade(); 56881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch const String& serverConnection = this->serverConnection(); 56981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch 57081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (serverUpgrade.isNull()) { 57181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Error during WebSocket handshake: 'Upgrade' header is missing", 0, clientOrigin(), 0); 57281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return false; 57381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch } 57481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (serverConnection.isNull()) { 57581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Error during WebSocket handshake: 'Connection' header is missing", 0, clientOrigin(), 0); 57681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return false; 57781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch } 57881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (serverWebSocketOrigin.isNull()) { 57981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Error during WebSocket handshake: 'Sec-WebSocket-Origin' header is missing", 0, clientOrigin(), 0); 58081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return false; 58181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch } 58281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (serverWebSocketLocation.isNull()) { 58381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Error during WebSocket handshake: 'Sec-WebSocket-Location' header is missing", 0, clientOrigin(), 0); 58481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return false; 58581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch } 58681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch 58781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (!equalIgnoringCase(serverUpgrade, "websocket")) { 58881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Error during WebSocket handshake: 'Upgrade' header value is not 'WebSocket'", 0, clientOrigin(), 0); 589e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block return false; 590d0825bca7fe65beaee391d30da42e937db621564Steve Block } 59181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (!equalIgnoringCase(serverConnection, "upgrade")) { 59281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Error during WebSocket handshake: 'Connection' header value is not 'Upgrade'", 0, clientOrigin(), 0); 593e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block return false; 594d0825bca7fe65beaee391d30da42e937db621564Steve Block } 595231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 59681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (clientOrigin() != serverWebSocketOrigin) { 59781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Error during WebSocket handshake: origin mismatch: " + clientOrigin() + " != " + serverWebSocketOrigin, 0, clientOrigin(), 0); 598e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block return false; 599231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 60081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (clientLocation() != serverWebSocketLocation) { 60181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Error during WebSocket handshake: location mismatch: " + clientLocation() + " != " + serverWebSocketLocation, 0, clientOrigin(), 0); 602e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block return false; 603231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 60481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (!m_clientProtocol.isEmpty() && m_clientProtocol != serverWebSocketProtocol) { 60581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch m_context->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Error during WebSocket handshake: protocol mismatch: " + m_clientProtocol + " != " + serverWebSocketProtocol, 0, clientOrigin(), 0); 606e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block return false; 607231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 608e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block return true; 609231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 610231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 611e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block} // namespace WebCore 612231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 613e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block#endif // ENABLE(WEB_SOCKETS) 614