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