1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/websockets/websocket_handshake_handler.h"
6
7#include <string>
8#include <vector>
9
10#include "base/basictypes.h"
11#include "base/strings/string_util.h"
12#include "base/strings/stringprintf.h"
13#include "net/http/http_response_headers.h"
14#include "net/http/http_util.h"
15#include "url/gurl.h"
16
17#include "testing/gtest/include/gtest/gtest.h"
18
19namespace {
20
21const char* const kCookieHeaders[] = {
22  "cookie", "cookie2"
23};
24
25const char* const kSetCookieHeaders[] = {
26  "set-cookie", "set-cookie2"
27};
28
29}  // namespace
30
31namespace net {
32
33TEST(WebSocketHandshakeRequestHandlerTest, SimpleRequest) {
34  WebSocketHandshakeRequestHandler handler;
35
36  static const char kHandshakeRequestMessage[] =
37      "GET /demo HTTP/1.1\r\n"
38      "Host: example.com\r\n"
39      "Upgrade: websocket\r\n"
40      "Connection: Upgrade\r\n"
41      "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
42      "Sec-WebSocket-Origin: http://example.com\r\n"
43      "Sec-WebSocket-Protocol: sample\r\n"
44      "Sec-WebSocket-Version: 13\r\n"
45      "\r\n";
46
47  EXPECT_TRUE(handler.ParseRequest(kHandshakeRequestMessage,
48                                   strlen(kHandshakeRequestMessage)));
49
50  handler.RemoveHeaders(kCookieHeaders, arraysize(kCookieHeaders));
51
52  EXPECT_EQ(kHandshakeRequestMessage, handler.GetRawRequest());
53}
54
55TEST(WebSocketHandshakeRequestHandlerTest, ReplaceRequestCookies) {
56  WebSocketHandshakeRequestHandler handler;
57
58  static const char kHandshakeRequestMessage[] =
59      "GET /demo HTTP/1.1\r\n"
60      "Host: example.com\r\n"
61      "Upgrade: websocket\r\n"
62      "Connection: Upgrade\r\n"
63      "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
64      "Sec-WebSocket-Origin: http://example.com\r\n"
65      "Sec-WebSocket-Protocol: sample\r\n"
66      "Sec-WebSocket-Version: 13\r\n"
67      "Cookie: WK-websocket-test=1\r\n"
68      "\r\n";
69
70  EXPECT_TRUE(handler.ParseRequest(kHandshakeRequestMessage,
71                                   strlen(kHandshakeRequestMessage)));
72
73  handler.RemoveHeaders(kCookieHeaders, arraysize(kCookieHeaders));
74
75  handler.AppendHeaderIfMissing("Cookie",
76                                "WK-websocket-test=1; "
77                                "WK-websocket-test-httponly=1");
78
79  static const char kHandshakeRequestExpectedMessage[] =
80      "GET /demo HTTP/1.1\r\n"
81      "Host: example.com\r\n"
82      "Upgrade: websocket\r\n"
83      "Connection: Upgrade\r\n"
84      "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
85      "Sec-WebSocket-Origin: http://example.com\r\n"
86      "Sec-WebSocket-Protocol: sample\r\n"
87      "Sec-WebSocket-Version: 13\r\n"
88      "Cookie: WK-websocket-test=1; WK-websocket-test-httponly=1\r\n"
89      "\r\n";
90
91  EXPECT_EQ(kHandshakeRequestExpectedMessage, handler.GetRawRequest());
92}
93
94TEST(WebSocketHandshakeResponseHandlerTest, SimpleResponse) {
95  WebSocketHandshakeResponseHandler handler;
96
97  static const char kHandshakeResponseMessage[] =
98      "HTTP/1.1 101 Switching Protocols\r\n"
99      "Upgrade: websocket\r\n"
100      "Connection: Upgrade\r\n"
101      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
102      "Sec-WebSocket-Protocol: sample\r\n"
103      "\r\n";
104
105  EXPECT_EQ(strlen(kHandshakeResponseMessage),
106            handler.ParseRawResponse(kHandshakeResponseMessage,
107                                     strlen(kHandshakeResponseMessage)));
108  EXPECT_TRUE(handler.HasResponse());
109
110  handler.RemoveHeaders(kCookieHeaders, arraysize(kCookieHeaders));
111
112  EXPECT_EQ(kHandshakeResponseMessage, handler.GetResponse());
113}
114
115TEST(WebSocketHandshakeResponseHandlerTest, ReplaceResponseCookies) {
116  WebSocketHandshakeResponseHandler handler;
117
118  static const char kHandshakeResponseMessage[] =
119      "HTTP/1.1 101 Switching Protocols\r\n"
120      "Upgrade: websocket\r\n"
121      "Connection: Upgrade\r\n"
122      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
123      "Sec-WebSocket-Protocol: sample\r\n"
124      "Set-Cookie: WK-websocket-test-1\r\n"
125      "Set-Cookie: WK-websocket-test-httponly=1; HttpOnly\r\n"
126      "\r\n";
127
128  EXPECT_EQ(strlen(kHandshakeResponseMessage),
129            handler.ParseRawResponse(kHandshakeResponseMessage,
130                                     strlen(kHandshakeResponseMessage)));
131  EXPECT_TRUE(handler.HasResponse());
132  std::vector<std::string> cookies;
133  handler.GetHeaders(kSetCookieHeaders, arraysize(kSetCookieHeaders), &cookies);
134  ASSERT_EQ(2U, cookies.size());
135  EXPECT_EQ("WK-websocket-test-1", cookies[0]);
136  EXPECT_EQ("WK-websocket-test-httponly=1; HttpOnly", cookies[1]);
137  handler.RemoveHeaders(kSetCookieHeaders, arraysize(kSetCookieHeaders));
138
139  static const char kHandshakeResponseExpectedMessage[] =
140      "HTTP/1.1 101 Switching Protocols\r\n"
141      "Upgrade: websocket\r\n"
142      "Connection: Upgrade\r\n"
143      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
144      "Sec-WebSocket-Protocol: sample\r\n"
145      "\r\n";
146
147  EXPECT_EQ(kHandshakeResponseExpectedMessage, handler.GetResponse());
148}
149
150TEST(WebSocketHandshakeResponseHandlerTest, BadResponse) {
151  WebSocketHandshakeResponseHandler handler;
152
153  static const char kBadMessage[] = "\n\n\r\net-Location: w";
154  EXPECT_EQ(2U, handler.ParseRawResponse(kBadMessage, strlen(kBadMessage)));
155  EXPECT_TRUE(handler.HasResponse());
156  EXPECT_EQ("\n\n", handler.GetResponse());
157}
158
159TEST(WebSocketHandshakeResponseHandlerTest, BadResponse2) {
160  WebSocketHandshakeResponseHandler handler;
161
162  static const char kBadMessage[] = "\n\r\n\r\net-Location: w";
163  EXPECT_EQ(3U, handler.ParseRawResponse(kBadMessage, strlen(kBadMessage)));
164  EXPECT_TRUE(handler.HasResponse());
165  EXPECT_EQ("\n\r\n", handler.GetResponse());
166}
167
168TEST(WebSocketHandshakeHandlerTest, HttpRequestResponse) {
169  WebSocketHandshakeRequestHandler request_handler;
170
171  static const char kHandshakeRequestMessage[] =
172      "GET /demo HTTP/1.1\r\n"
173      "Host: example.com\r\n"
174      "Upgrade: websocket\r\n"
175      "Connection: Upgrade\r\n"
176      "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
177      "Sec-WebSocket-Origin: http://example.com\r\n"
178      "Sec-WebSocket-Protocol: sample\r\n"
179      "Sec-WebSocket-Version: 13\r\n"
180      "\r\n";
181
182  EXPECT_TRUE(request_handler.ParseRequest(kHandshakeRequestMessage,
183                                           strlen(kHandshakeRequestMessage)));
184
185  GURL url("ws://example.com/demo");
186  std::string challenge;
187  const HttpRequestInfo& request_info =
188      request_handler.GetRequestInfo(url, &challenge);
189
190  EXPECT_EQ(url, request_info.url);
191  EXPECT_EQ("GET", request_info.method);
192  EXPECT_FALSE(request_info.extra_headers.HasHeader("Upgrade"));
193  EXPECT_FALSE(request_info.extra_headers.HasHeader("Connection"));
194  EXPECT_FALSE(request_info.extra_headers.HasHeader("Sec-WebSocket-Key"));
195  std::string value;
196  EXPECT_TRUE(request_info.extra_headers.GetHeader("Host", &value));
197  EXPECT_EQ("example.com", value);
198  EXPECT_TRUE(request_info.extra_headers.GetHeader("Sec-WebSocket-Origin",
199                                                   &value));
200  EXPECT_EQ("http://example.com", value);
201  EXPECT_TRUE(request_info.extra_headers.GetHeader("Sec-WebSocket-Protocol",
202                                                   &value));
203  EXPECT_EQ("sample", value);
204
205  EXPECT_EQ("dGhlIHNhbXBsZSBub25jZQ==", challenge);
206
207  static const char kHandshakeResponseHeader[] =
208      "HTTP/1.1 101 Switching Protocols\r\n"
209      "Sec-WebSocket-Protocol: sample\r\n";
210
211  std::string raw_headers =
212      HttpUtil::AssembleRawHeaders(kHandshakeResponseHeader,
213                                   strlen(kHandshakeResponseHeader));
214  HttpResponseInfo response_info;
215  response_info.headers = new HttpResponseHeaders(raw_headers);
216
217  EXPECT_TRUE(StartsWithASCII(response_info.headers->GetStatusLine(),
218                              "HTTP/1.1 101 ", false));
219  EXPECT_FALSE(response_info.headers->HasHeader("Upgrade"));
220  EXPECT_FALSE(response_info.headers->HasHeader("Connection"));
221  EXPECT_FALSE(response_info.headers->HasHeader("Sec-WebSocket-Accept"));
222  EXPECT_TRUE(response_info.headers->HasHeaderValue("Sec-WebSocket-Protocol",
223                                                    "sample"));
224
225  WebSocketHandshakeResponseHandler response_handler;
226
227  EXPECT_TRUE(response_handler.ParseResponseInfo(response_info, challenge));
228  EXPECT_TRUE(response_handler.HasResponse());
229
230  static const char kHandshakeResponseExpectedMessage[] =
231      "HTTP/1.1 101 Switching Protocols\r\n"
232      "Upgrade: websocket\r\n"
233      "Connection: Upgrade\r\n"
234      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
235      "Sec-WebSocket-Protocol: sample\r\n"
236      "\r\n";
237
238  EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse());
239}
240
241}  // namespace net
242