• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2010 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 <string>
6 #include <vector>
7 
8 #include "base/basictypes.h"
9 #include "base/string_util.h"
10 #include "googleurl/src/gurl.h"
11 #include "net/http/http_response_headers.h"
12 #include "net/http/http_util.h"
13 #include "net/websockets/websocket_handshake_handler.h"
14 
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "testing/platform_test.h"
18 
19 namespace {
20 
21 const char* const kCookieHeaders[] = {
22   "cookie", "cookie2"
23 };
24 
25 const char* const kSetCookieHeaders[] = {
26   "set-cookie", "set-cookie2"
27 };
28 
29 }
30 
31 namespace net {
32 
TEST(WebSocketHandshakeRequestHandlerTest,SimpleRequest)33 TEST(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       "Connection: Upgrade\r\n"
40       "Sec-WebSocket-Key2: 12998 5 Y3 1  .P00\r\n"
41       "Sec-WebSocket-Protocol: sample\r\n"
42       "Upgrade: WebSocket\r\n"
43       "Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5\r\n"
44       "Origin: http://example.com\r\n"
45       "\r\n"
46       "^n:ds[4U";
47 
48   EXPECT_TRUE(handler.ParseRequest(kHandshakeRequestMessage,
49                                    strlen(kHandshakeRequestMessage)));
50 
51   handler.RemoveHeaders(kCookieHeaders, arraysize(kCookieHeaders));
52 
53   EXPECT_EQ(kHandshakeRequestMessage, handler.GetRawRequest());
54 }
55 
TEST(WebSocketHandshakeRequestHandlerTest,ReplaceRequestCookies)56 TEST(WebSocketHandshakeRequestHandlerTest, ReplaceRequestCookies) {
57   WebSocketHandshakeRequestHandler handler;
58 
59   static const char* kHandshakeRequestMessage =
60       "GET /demo HTTP/1.1\r\n"
61       "Host: example.com\r\n"
62       "Connection: Upgrade\r\n"
63       "Sec-WebSocket-Key2: 12998 5 Y3 1  .P00\r\n"
64       "Sec-WebSocket-Protocol: sample\r\n"
65       "Upgrade: WebSocket\r\n"
66       "Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5\r\n"
67       "Origin: http://example.com\r\n"
68       "Cookie: WK-websocket-test=1\r\n"
69       "\r\n"
70       "^n:ds[4U";
71 
72   EXPECT_TRUE(handler.ParseRequest(kHandshakeRequestMessage,
73                                    strlen(kHandshakeRequestMessage)));
74 
75   handler.RemoveHeaders(kCookieHeaders, arraysize(kCookieHeaders));
76 
77   handler.AppendHeaderIfMissing("Cookie",
78                                 "WK-websocket-test=1; "
79                                 "WK-websocket-test-httponly=1");
80 
81   static const char* kHandshakeRequestExpectedMessage =
82       "GET /demo HTTP/1.1\r\n"
83       "Host: example.com\r\n"
84       "Connection: Upgrade\r\n"
85       "Sec-WebSocket-Key2: 12998 5 Y3 1  .P00\r\n"
86       "Sec-WebSocket-Protocol: sample\r\n"
87       "Upgrade: WebSocket\r\n"
88       "Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5\r\n"
89       "Origin: http://example.com\r\n"
90       "Cookie: WK-websocket-test=1; WK-websocket-test-httponly=1\r\n"
91       "\r\n"
92       "^n:ds[4U";
93 
94   EXPECT_EQ(kHandshakeRequestExpectedMessage, handler.GetRawRequest());
95 }
96 
TEST(WebSocketHandshakeResponseHandlerTest,SimpleResponse)97 TEST(WebSocketHandshakeResponseHandlerTest, SimpleResponse) {
98   WebSocketHandshakeResponseHandler handler;
99 
100   static const char* kHandshakeResponseMessage =
101       "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
102       "Upgrade: WebSocket\r\n"
103       "Connection: Upgrade\r\n"
104       "Sec-WebSocket-Origin: http://example.com\r\n"
105       "Sec-WebSocket-Location: ws://example.com/demo\r\n"
106       "Sec-WebSocket-Protocol: sample\r\n"
107       "\r\n"
108       "8jKS'y:G*Co,Wxa-";
109 
110   EXPECT_EQ(strlen(kHandshakeResponseMessage),
111             handler.ParseRawResponse(kHandshakeResponseMessage,
112                                      strlen(kHandshakeResponseMessage)));
113   EXPECT_TRUE(handler.HasResponse());
114 
115   handler.RemoveHeaders(kCookieHeaders, arraysize(kCookieHeaders));
116 
117   EXPECT_EQ(kHandshakeResponseMessage, handler.GetResponse());
118 }
119 
TEST(WebSocketHandshakeResponseHandlerTest,ReplaceResponseCookies)120 TEST(WebSocketHandshakeResponseHandlerTest, ReplaceResponseCookies) {
121   WebSocketHandshakeResponseHandler handler;
122 
123   static const char* kHandshakeResponseMessage =
124       "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
125       "Upgrade: WebSocket\r\n"
126       "Connection: Upgrade\r\n"
127       "Sec-WebSocket-Origin: http://example.com\r\n"
128       "Sec-WebSocket-Location: ws://example.com/demo\r\n"
129       "Sec-WebSocket-Protocol: sample\r\n"
130       "Set-Cookie: WK-websocket-test-1\r\n"
131       "Set-Cookie: WK-websocket-test-httponly=1; HttpOnly\r\n"
132       "\r\n"
133       "8jKS'y:G*Co,Wxa-";
134 
135   EXPECT_EQ(strlen(kHandshakeResponseMessage),
136             handler.ParseRawResponse(kHandshakeResponseMessage,
137                                      strlen(kHandshakeResponseMessage)));
138   EXPECT_TRUE(handler.HasResponse());
139   std::vector<std::string> cookies;
140   handler.GetHeaders(kSetCookieHeaders, arraysize(kSetCookieHeaders), &cookies);
141   ASSERT_EQ(2U, cookies.size());
142   EXPECT_EQ("WK-websocket-test-1", cookies[0]);
143   EXPECT_EQ("WK-websocket-test-httponly=1; HttpOnly", cookies[1]);
144   handler.RemoveHeaders(kSetCookieHeaders, arraysize(kSetCookieHeaders));
145 
146   static const char* kHandshakeResponseExpectedMessage =
147       "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
148       "Upgrade: WebSocket\r\n"
149       "Connection: Upgrade\r\n"
150       "Sec-WebSocket-Origin: http://example.com\r\n"
151       "Sec-WebSocket-Location: ws://example.com/demo\r\n"
152       "Sec-WebSocket-Protocol: sample\r\n"
153       "\r\n"
154       "8jKS'y:G*Co,Wxa-";
155 
156   EXPECT_EQ(kHandshakeResponseExpectedMessage, handler.GetResponse());
157 }
158 
TEST(WebSocketHandshakeResponseHandlerTest,BadResponse)159 TEST(WebSocketHandshakeResponseHandlerTest, BadResponse) {
160   WebSocketHandshakeResponseHandler handler;
161 
162   static const char* kBadMessage = "\n\n\r\net-Location: w";
163   EXPECT_EQ(strlen(kBadMessage),
164             handler.ParseRawResponse(kBadMessage, strlen(kBadMessage)));
165   EXPECT_TRUE(handler.HasResponse());
166   EXPECT_EQ(kBadMessage, handler.GetResponse());
167 }
168 
TEST(WebSocketHandshakeResponseHandlerTest,BadResponse2)169 TEST(WebSocketHandshakeResponseHandlerTest, BadResponse2) {
170   WebSocketHandshakeResponseHandler handler;
171 
172   static const char* kBadMessage = "\n\r\n\r\net-Location: w";
173   EXPECT_EQ(strlen(kBadMessage),
174             handler.ParseRawResponse(kBadMessage, strlen(kBadMessage)));
175   EXPECT_TRUE(handler.HasResponse());
176   EXPECT_EQ(kBadMessage, handler.GetResponse());
177 }
178 
TEST(WebSocketHandshakeHandlerTest,HttpRequestResponse)179 TEST(WebSocketHandshakeHandlerTest, HttpRequestResponse) {
180   WebSocketHandshakeRequestHandler request_handler;
181 
182   static const char* kHandshakeRequestMessage =
183       "GET /demo HTTP/1.1\r\n"
184       "Host: example.com\r\n"
185       "Connection: Upgrade\r\n"
186       "Sec-WebSocket-Key2: 12998 5 Y3 1  .P00\r\n"
187       "Sec-WebSocket-Protocol: sample\r\n"
188       "Upgrade: WebSocket\r\n"
189       "Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5\r\n"
190       "Origin: http://example.com\r\n"
191       "\r\n"
192       "^n:ds[4U";
193 
194   EXPECT_TRUE(request_handler.ParseRequest(kHandshakeRequestMessage,
195                                            strlen(kHandshakeRequestMessage)));
196 
197   GURL url("ws://example.com/demo");
198   std::string challenge;
199   const HttpRequestInfo& request_info =
200       request_handler.GetRequestInfo(url, &challenge);
201 
202   EXPECT_EQ(url, request_info.url);
203   EXPECT_EQ("GET", request_info.method);
204   EXPECT_FALSE(request_info.extra_headers.HasHeader("Upgrade"));
205   EXPECT_FALSE(request_info.extra_headers.HasHeader("Connection"));
206   EXPECT_FALSE(request_info.extra_headers.HasHeader("Sec-WebSocket-Key1"));
207   EXPECT_FALSE(request_info.extra_headers.HasHeader("Sec-WebSocket-Key2"));
208   std::string value;
209   EXPECT_TRUE(request_info.extra_headers.GetHeader("Host", &value));
210   EXPECT_EQ("example.com", value);
211   EXPECT_TRUE(request_info.extra_headers.GetHeader("Origin", &value));
212   EXPECT_EQ("http://example.com", value);
213   EXPECT_TRUE(request_info.extra_headers.GetHeader("Sec-WebSocket-Protocol",
214                                                    &value));
215   EXPECT_EQ("sample", value);
216 
217   const char expected_challenge[] = "\x31\x6e\x41\x13\x0f\x7e\xd6\x3c^n:ds[4U";
218 
219   EXPECT_EQ(expected_challenge, challenge);
220 
221   static const char* kHandshakeResponseHeader =
222       "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
223       "Sec-WebSocket-Origin: http://example.com\r\n"
224       "Sec-WebSocket-Location: ws://example.com/demo\r\n"
225       "Sec-WebSocket-Protocol: sample\r\n";
226 
227   std::string raw_headers =
228       HttpUtil::AssembleRawHeaders(kHandshakeResponseHeader,
229                                    strlen(kHandshakeResponseHeader));
230   HttpResponseInfo response_info;
231   response_info.headers = new HttpResponseHeaders(raw_headers);
232 
233   EXPECT_TRUE(StartsWithASCII(response_info.headers->GetStatusLine(),
234                               "HTTP/1.1 101 ", false));
235   EXPECT_FALSE(response_info.headers->HasHeader("Upgrade"));
236   EXPECT_FALSE(response_info.headers->HasHeader("Connection"));
237   EXPECT_TRUE(response_info.headers->HasHeaderValue("Sec-WebSocket-Origin",
238                                                     "http://example.com"));
239   EXPECT_TRUE(response_info.headers->HasHeaderValue("Sec-WebSocket-Location",
240                                                     "ws://example.com/demo"));
241   EXPECT_TRUE(response_info.headers->HasHeaderValue("Sec-WebSocket-Protocol",
242                                                     "sample"));
243 
244   WebSocketHandshakeResponseHandler response_handler;
245   EXPECT_TRUE(response_handler.ParseResponseInfo(response_info, challenge));
246   EXPECT_TRUE(response_handler.HasResponse());
247 
248   static const char* kHandshakeResponseExpectedMessage =
249       "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
250       "Upgrade: WebSocket\r\n"
251       "Connection: Upgrade\r\n"
252       "Sec-WebSocket-Origin: http://example.com\r\n"
253       "Sec-WebSocket-Location: ws://example.com/demo\r\n"
254       "Sec-WebSocket-Protocol: sample\r\n"
255       "\r\n"
256       "8jKS'y:G*Co,Wxa-";
257 
258   EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse());
259 }
260 
TEST(WebSocketHandshakeHandlerTest,SpdyRequestResponse)261 TEST(WebSocketHandshakeHandlerTest, SpdyRequestResponse) {
262   WebSocketHandshakeRequestHandler request_handler;
263 
264   static const char* kHandshakeRequestMessage =
265       "GET /demo HTTP/1.1\r\n"
266       "Host: example.com\r\n"
267       "Connection: Upgrade\r\n"
268       "Sec-WebSocket-Key2: 12998 5 Y3 1  .P00\r\n"
269       "Sec-WebSocket-Protocol: sample\r\n"
270       "Upgrade: WebSocket\r\n"
271       "X-bogus-header: X\r\n"
272       "Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5\r\n"
273       "Origin: http://example.com\r\n"
274       "X-bogus-header: Y\r\n"
275       "\r\n"
276       "^n:ds[4U";
277 
278   EXPECT_TRUE(request_handler.ParseRequest(kHandshakeRequestMessage,
279                                            strlen(kHandshakeRequestMessage)));
280 
281   GURL url("ws://example.com/demo");
282   std::string challenge;
283   spdy::SpdyHeaderBlock headers;
284   ASSERT_TRUE(request_handler.GetRequestHeaderBlock(url, &headers, &challenge));
285 
286   EXPECT_EQ(url.spec(), headers["url"]);
287   EXPECT_TRUE(headers.find("upgrade") == headers.end());
288   EXPECT_TRUE(headers.find("Upgrade") == headers.end());
289   EXPECT_TRUE(headers.find("connection") == headers.end());
290   EXPECT_TRUE(headers.find("Connection") == headers.end());
291   EXPECT_TRUE(headers.find("Sec-WebSocket-Key1") == headers.end());
292   EXPECT_TRUE(headers.find("sec-websocket-key1") == headers.end());
293   EXPECT_TRUE(headers.find("Sec-WebSocket-Key2") == headers.end());
294   EXPECT_TRUE(headers.find("sec-websocket-key2") == headers.end());
295   EXPECT_EQ("example.com", headers["host"]);
296   EXPECT_EQ("http://example.com", headers["origin"]);
297   EXPECT_EQ("sample", headers["sec-websocket-protocol"]);
298   const char bogus_header[] = "X\0Y";
299   std::string bogus_header_str(bogus_header, sizeof(bogus_header) - 1);
300   EXPECT_EQ(bogus_header_str, headers["x-bogus-header"]);
301 
302   const char expected_challenge[] = "\x31\x6e\x41\x13\x0f\x7e\xd6\x3c^n:ds[4U";
303 
304   EXPECT_EQ(expected_challenge, challenge);
305 
306   headers.clear();
307 
308   headers["sec-websocket-origin"] = "http://example.com";
309   headers["sec-websocket-location"] = "ws://example.com/demo";
310   headers["sec-websocket-protocol"] = "sample";
311 
312   WebSocketHandshakeResponseHandler response_handler;
313   EXPECT_TRUE(response_handler.ParseResponseHeaderBlock(headers, challenge));
314   EXPECT_TRUE(response_handler.HasResponse());
315 
316   // Note that order of sec-websocket-* is sensitive with hash_map order.
317   static const char* kHandshakeResponseExpectedMessage =
318       "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
319       "Upgrade: WebSocket\r\n"
320       "Connection: Upgrade\r\n"
321       "sec-websocket-location: ws://example.com/demo\r\n"
322       "sec-websocket-origin: http://example.com\r\n"
323       "sec-websocket-protocol: sample\r\n"
324       "\r\n"
325       "8jKS'y:G*Co,Wxa-";
326 
327   EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse());
328 }
329 
330 
TEST(WebSocketHandshakeHandlerTest,SpdyRequestResponseWithCookies)331 TEST(WebSocketHandshakeHandlerTest, SpdyRequestResponseWithCookies) {
332   WebSocketHandshakeRequestHandler request_handler;
333 
334   // Note that websocket won't use multiple headers in request now.
335   static const char* kHandshakeRequestMessage =
336       "GET /demo HTTP/1.1\r\n"
337       "Host: example.com\r\n"
338       "Connection: Upgrade\r\n"
339       "Sec-WebSocket-Key2: 12998 5 Y3 1  .P00\r\n"
340       "Sec-WebSocket-Protocol: sample\r\n"
341       "Upgrade: WebSocket\r\n"
342       "Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5\r\n"
343       "Origin: http://example.com\r\n"
344       "Cookie: WK-websocket-test=1; WK-websocket-test-httponly=1\r\n"
345       "\r\n"
346       "^n:ds[4U";
347 
348   EXPECT_TRUE(request_handler.ParseRequest(kHandshakeRequestMessage,
349                                            strlen(kHandshakeRequestMessage)));
350 
351   GURL url("ws://example.com/demo");
352   std::string challenge;
353   spdy::SpdyHeaderBlock headers;
354   ASSERT_TRUE(request_handler.GetRequestHeaderBlock(url, &headers, &challenge));
355 
356   EXPECT_EQ(url.spec(), headers["url"]);
357   EXPECT_TRUE(headers.find("upgrade") == headers.end());
358   EXPECT_TRUE(headers.find("Upgrade") == headers.end());
359   EXPECT_TRUE(headers.find("connection") == headers.end());
360   EXPECT_TRUE(headers.find("Connection") == headers.end());
361   EXPECT_TRUE(headers.find("Sec-WebSocket-Key1") == headers.end());
362   EXPECT_TRUE(headers.find("sec-websocket-key1") == headers.end());
363   EXPECT_TRUE(headers.find("Sec-WebSocket-Key2") == headers.end());
364   EXPECT_TRUE(headers.find("sec-websocket-key2") == headers.end());
365   EXPECT_EQ("example.com", headers["host"]);
366   EXPECT_EQ("http://example.com", headers["origin"]);
367   EXPECT_EQ("sample", headers["sec-websocket-protocol"]);
368   EXPECT_EQ("WK-websocket-test=1; WK-websocket-test-httponly=1",
369             headers["cookie"]);
370 
371   const char expected_challenge[] = "\x31\x6e\x41\x13\x0f\x7e\xd6\x3c^n:ds[4U";
372 
373   EXPECT_EQ(expected_challenge, challenge);
374 
375   headers.clear();
376 
377   headers["sec-websocket-origin"] = "http://example.com";
378   headers["sec-websocket-location"] = "ws://example.com/demo";
379   headers["sec-websocket-protocol"] = "sample";
380   std::string cookie = "WK-websocket-test=1";
381   cookie.append(1, '\0');
382   cookie += "WK-websocket-test-httponly=1; HttpOnly";
383   headers["set-cookie"] = cookie;
384 
385   WebSocketHandshakeResponseHandler response_handler;
386   EXPECT_TRUE(response_handler.ParseResponseHeaderBlock(headers, challenge));
387   EXPECT_TRUE(response_handler.HasResponse());
388 
389   // Note that order of sec-websocket-* is sensitive with hash_map order.
390   static const char* kHandshakeResponseExpectedMessage =
391       "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
392       "Upgrade: WebSocket\r\n"
393       "Connection: Upgrade\r\n"
394       "sec-websocket-location: ws://example.com/demo\r\n"
395       "sec-websocket-origin: http://example.com\r\n"
396       "sec-websocket-protocol: sample\r\n"
397       "set-cookie: WK-websocket-test=1\r\n"
398       "set-cookie: WK-websocket-test-httponly=1; HttpOnly\r\n"
399       "\r\n"
400       "8jKS'y:G*Co,Wxa-";
401 
402   EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse());
403 }
404 
405 }  // namespace net
406