1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string>
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <vector>
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h"
93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_split.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/stringprintf.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/websockets/websocket_handshake.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "testing/gmock/include/gmock/gmock.h"
143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "testing/gtest/include/gtest/gtest.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "testing/platform_test.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace net {
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass WebSocketHandshakeTest : public testing::Test {
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static void SetUpParameter(WebSocketHandshake* handshake,
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             uint32 number_1, uint32 number_2,
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             const std::string& key_1, const std::string& key_2,
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             const std::string& key_3) {
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    WebSocketHandshake::Parameter* parameter =
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new WebSocketHandshake::Parameter;
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    parameter->number_1_ = number_1;
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    parameter->number_2_ = number_2;
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    parameter->key_1_ = key_1;
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    parameter->key_2_ = key_2;
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    parameter->key_3_ = key_3;
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    handshake->parameter_.reset(parameter);
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static void ExpectHeaderEquals(const std::string& expected,
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          const std::string& actual) {
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<std::string> expected_lines;
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Tokenize(expected, "\r\n", &expected_lines);
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<std::string> actual_lines;
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Tokenize(actual, "\r\n", &actual_lines);
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Request lines.
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXPECT_EQ(expected_lines[0], actual_lines[0]);
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<std::string> expected_headers;
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (size_t i = 1; i < expected_lines.size(); i++) {
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Finish at first CRLF CRLF.  Note that /key_3/ might include CRLF.
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (expected_lines[i] == "")
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      expected_headers.push_back(expected_lines[i]);
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    sort(expected_headers.begin(), expected_headers.end());
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<std::string> actual_headers;
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (size_t i = 1; i < actual_lines.size(); i++) {
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Finish at first CRLF CRLF.  Note that /key_3/ might include CRLF.
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (actual_lines[i] == "")
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      actual_headers.push_back(actual_lines[i]);
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    sort(actual_headers.begin(), actual_headers.end());
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXPECT_EQ(expected_headers.size(), actual_headers.size())
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        << "expected:" << expected
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        << "\nactual:" << actual;
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (size_t i = 0; i < expected_headers.size(); i++) {
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXPECT_EQ(expected_headers[i], actual_headers[i]);
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static void ExpectHandshakeMessageEquals(const std::string& expected,
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           const std::string& actual) {
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Headers.
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ExpectHeaderEquals(expected, actual);
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Compare tailing \r\n\r\n<key3> (4 + 8 bytes).
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ASSERT_GT(expected.size(), 12U);
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char* expected_key3 = expected.data() + expected.size() - 12;
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXPECT_GT(actual.size(), 12U);
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (actual.size() <= 12U)
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char* actual_key3 = actual.data() + actual.size() - 12;
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXPECT_TRUE(memcmp(expected_key3, actual_key3, 12) == 0)
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        << "expected_key3:" << DumpKey(expected_key3, 12)
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        << ", actual_key3:" << DumpKey(actual_key3, 12);
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static std::string DumpKey(const char* buf, int len) {
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string s;
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (int i = 0; i < len; i++) {
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (isprint(buf[i]))
903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        s += base::StringPrintf("%c", buf[i]);
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      else
923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        s += base::StringPrintf("\\x%02x", buf[i]);
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return s;
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static std::string GetResourceName(WebSocketHandshake* handshake) {
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return handshake->GetResourceName();
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static std::string GetHostFieldValue(WebSocketHandshake* handshake) {
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return handshake->GetHostFieldValue();
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static std::string GetOriginFieldValue(WebSocketHandshake* handshake) {
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return handshake->GetOriginFieldValue();
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(WebSocketHandshakeTest, Connect) {
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::string kExpectedClientHandshakeMessage =
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "GET /demo HTTP/1.1\r\n"
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Upgrade: WebSocket\r\n"
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Connection: Upgrade\r\n"
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Host: example.com\r\n"
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Origin: http://example.com\r\n"
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Sec-WebSocket-Protocol: sample\r\n"
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Sec-WebSocket-Key1: 388P O503D&ul7 {K%gX( %7  15\r\n"
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Sec-WebSocket-Key2: 1 N ?|k UT0or 3o  4 I97N 5-S3O 31\r\n"
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "\r\n"
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "\x47\x30\x22\x2D\x5A\x3F\x47\x58";
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<WebSocketHandshake> handshake(
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new WebSocketHandshake(GURL("ws://example.com/demo"),
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "http://example.com",
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "ws://example.com/demo",
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "sample"));
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SetUpParameter(handshake.get(), 777007543U, 114997259U,
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 "388P O503D&ul7 {K%gX( %7  15",
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 "1 N ?|k UT0or 3o  4 I97N 5-S3O 31",
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 std::string("\x47\x30\x22\x2D\x5A\x3F\x47\x58", 8));
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode());
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExpectHandshakeMessageEquals(
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kExpectedClientHandshakeMessage,
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      handshake->CreateClientHandshakeMessage());
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char kResponse[] = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Upgrade: WebSocket\r\n"
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Connection: Upgrade\r\n"
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Sec-WebSocket-Origin: http://example.com\r\n"
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Sec-WebSocket-Location: ws://example.com/demo\r\n"
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Sec-WebSocket-Protocol: sample\r\n"
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "\r\n"
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "\x30\x73\x74\x33\x52\x6C\x26\x71\x2D\x32\x5A\x55\x5E\x77\x65\x75";
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<std::string> response_lines;
1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  base::SplitStringDontTrim(kResponse, '\n', &response_lines);
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode());
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // too short
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(-1, handshake->ReadServerHandshake(kResponse, 16));
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode());
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // only status line
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string response = response_lines[0];
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(-1, handshake->ReadServerHandshake(
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      response.data(), response.size()));
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode());
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // by upgrade header
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response += response_lines[1];
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(-1, handshake->ReadServerHandshake(
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      response.data(), response.size()));
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode());
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // by connection header
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response += response_lines[2];
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(-1, handshake->ReadServerHandshake(
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      response.data(), response.size()));
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode());
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response += response_lines[3];  // Sec-WebSocket-Origin
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response += response_lines[4];  // Sec-WebSocket-Location
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response += response_lines[5];  // Sec-WebSocket-Protocol
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(-1, handshake->ReadServerHandshake(
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      response.data(), response.size()));
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode());
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response += response_lines[6];  // \r\n
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(-1, handshake->ReadServerHandshake(
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      response.data(), response.size()));
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode());
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int handshake_length = sizeof(kResponse) - 1;  // -1 for terminating \0
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(handshake_length, handshake->ReadServerHandshake(
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kResponse, handshake_length));  // -1 for terminating \0
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(WebSocketHandshake::MODE_CONNECTED, handshake->mode());
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(WebSocketHandshakeTest, ServerSentData) {
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::string kExpectedClientHandshakeMessage =
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "GET /demo HTTP/1.1\r\n"
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Upgrade: WebSocket\r\n"
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Connection: Upgrade\r\n"
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Host: example.com\r\n"
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Origin: http://example.com\r\n"
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Sec-WebSocket-Protocol: sample\r\n"
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Sec-WebSocket-Key1: 388P O503D&ul7 {K%gX( %7  15\r\n"
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Sec-WebSocket-Key2: 1 N ?|k UT0or 3o  4 I97N 5-S3O 31\r\n"
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "\r\n"
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "\x47\x30\x22\x2D\x5A\x3F\x47\x58";
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<WebSocketHandshake> handshake(
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new WebSocketHandshake(GURL("ws://example.com/demo"),
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "http://example.com",
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "ws://example.com/demo",
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "sample"));
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SetUpParameter(handshake.get(), 777007543U, 114997259U,
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 "388P O503D&ul7 {K%gX( %7  15",
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 "1 N ?|k UT0or 3o  4 I97N 5-S3O 31",
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 std::string("\x47\x30\x22\x2D\x5A\x3F\x47\x58", 8));
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode());
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExpectHandshakeMessageEquals(
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kExpectedClientHandshakeMessage,
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      handshake->CreateClientHandshakeMessage());
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char kResponse[] = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Upgrade: WebSocket\r\n"
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Connection: Upgrade\r\n"
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Sec-WebSocket-Origin: http://example.com\r\n"
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Sec-WebSocket-Location: ws://example.com/demo\r\n"
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Sec-WebSocket-Protocol: sample\r\n"
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "\r\n"
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "\x30\x73\x74\x33\x52\x6C\x26\x71\x2D\x32\x5A\x55\x5E\x77\x65\x75"
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "\0Hello\xff";
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int handshake_length = strlen(kResponse);  // key3 doesn't contain \0.
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(handshake_length, handshake->ReadServerHandshake(
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kResponse, sizeof(kResponse) - 1));  // -1 for terminating \0
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(WebSocketHandshake::MODE_CONNECTED, handshake->mode());
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(WebSocketHandshakeTest, is_secure_false) {
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<WebSocketHandshake> handshake(
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new WebSocketHandshake(GURL("ws://example.com/demo"),
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "http://example.com",
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "ws://example.com/demo",
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "sample"));
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(handshake->is_secure());
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(WebSocketHandshakeTest, is_secure_true) {
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // wss:// is secure.
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<WebSocketHandshake> handshake(
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new WebSocketHandshake(GURL("wss://example.com/demo"),
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "http://example.com",
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "wss://example.com/demo",
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "sample"));
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(handshake->is_secure());
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(WebSocketHandshakeTest, CreateClientHandshakeMessage_ResourceName) {
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<WebSocketHandshake> handshake(
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new WebSocketHandshake(GURL("ws://example.com/Test?q=xxx&p=%20"),
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "http://example.com",
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "ws://example.com/demo",
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "sample"));
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Path and query should be preserved as-is.
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ("/Test?q=xxx&p=%20", GetResourceName(handshake.get()));
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(WebSocketHandshakeTest, CreateClientHandshakeMessage_Host) {
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<WebSocketHandshake> handshake(
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new WebSocketHandshake(GURL("ws://Example.Com/demo"),
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "http://Example.Com",
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "ws://Example.Com/demo",
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "sample"));
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Host should be lowercased
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ("example.com", GetHostFieldValue(handshake.get()));
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ("http://example.com", GetOriginFieldValue(handshake.get()));
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(WebSocketHandshakeTest, CreateClientHandshakeMessage_TrimPort80) {
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<WebSocketHandshake> handshake(
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new WebSocketHandshake(GURL("ws://example.com:80/demo"),
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "http://example.com",
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "ws://example.com/demo",
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "sample"));
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // :80 should be trimmed as it's the default port for ws://.
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ("example.com", GetHostFieldValue(handshake.get()));
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(WebSocketHandshakeTest, CreateClientHandshakeMessage_TrimPort443) {
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<WebSocketHandshake> handshake(
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new WebSocketHandshake(GURL("wss://example.com:443/demo"),
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "http://example.com",
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "wss://example.com/demo",
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "sample"));
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // :443 should be trimmed as it's the default port for wss://.
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ("example.com", GetHostFieldValue(handshake.get()));
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(WebSocketHandshakeTest,
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       CreateClientHandshakeMessage_NonDefaultPortForWs) {
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<WebSocketHandshake> handshake(
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new WebSocketHandshake(GURL("ws://example.com:8080/demo"),
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "http://example.com",
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "wss://example.com/demo",
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "sample"));
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // :8080 should be preserved as it's not the default port for ws://.
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ("example.com:8080", GetHostFieldValue(handshake.get()));
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(WebSocketHandshakeTest,
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch     CreateClientHandshakeMessage_NonDefaultPortForWss) {
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<WebSocketHandshake> handshake(
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new WebSocketHandshake(GURL("wss://example.com:4443/demo"),
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "http://example.com",
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "wss://example.com/demo",
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "sample"));
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // :4443 should be preserved as it's not the default port for wss://.
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ("example.com:4443", GetHostFieldValue(handshake.get()));
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(WebSocketHandshakeTest, CreateClientHandshakeMessage_WsBut443) {
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<WebSocketHandshake> handshake(
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new WebSocketHandshake(GURL("ws://example.com:443/demo"),
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "http://example.com",
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "ws://example.com/demo",
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "sample"));
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // :443 should be preserved as it's not the default port for ws://.
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ("example.com:443", GetHostFieldValue(handshake.get()));
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(WebSocketHandshakeTest, CreateClientHandshakeMessage_WssBut80) {
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<WebSocketHandshake> handshake(
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new WebSocketHandshake(GURL("wss://example.com:80/demo"),
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "http://example.com",
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "wss://example.com/demo",
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "sample"));
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // :80 should be preserved as it's not the default port for wss://.
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ("example.com:80", GetHostFieldValue(handshake.get()));
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace net
331