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_extension_parser.h"
6 
7 #include <string>
8 
9 #include "base/stl_util.h"
10 #include "net/websockets/websocket_extension.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 
13 namespace net {
14 
15 namespace {
16 
TEST(WebSocketExtensionParserTest,ParseEmpty)17 TEST(WebSocketExtensionParserTest, ParseEmpty) {
18   WebSocketExtensionParser parser;
19   EXPECT_FALSE(parser.Parse("", 0));
20 
21   EXPECT_EQ(0U, parser.extensions().size());
22 }
23 
TEST(WebSocketExtensionParserTest,ParseSimple)24 TEST(WebSocketExtensionParserTest, ParseSimple) {
25   WebSocketExtensionParser parser;
26   WebSocketExtension expected("foo");
27 
28   EXPECT_TRUE(parser.Parse("foo"));
29 
30   ASSERT_EQ(1U, parser.extensions().size());
31   EXPECT_TRUE(expected.Equals(parser.extensions()[0]));
32 }
33 
TEST(WebSocketExtensionParserTest,ParseMoreThanOnce)34 TEST(WebSocketExtensionParserTest, ParseMoreThanOnce) {
35   WebSocketExtensionParser parser;
36   WebSocketExtension expected("foo");
37 
38   EXPECT_TRUE(parser.Parse("foo"));
39   ASSERT_EQ(1U, parser.extensions().size());
40   EXPECT_TRUE(expected.Equals(parser.extensions()[0]));
41 
42   EXPECT_FALSE(parser.Parse(""));
43   EXPECT_EQ(0U, parser.extensions().size());
44 
45   EXPECT_TRUE(parser.Parse("foo"));
46   ASSERT_EQ(1U, parser.extensions().size());
47   EXPECT_TRUE(expected.Equals(parser.extensions()[0]));
48 }
49 
TEST(WebSocketExtensionParserTest,ParseOneExtensionWithOneParamWithoutValue)50 TEST(WebSocketExtensionParserTest, ParseOneExtensionWithOneParamWithoutValue) {
51   WebSocketExtensionParser parser;
52   WebSocketExtension expected("foo");
53   expected.Add(WebSocketExtension::Parameter("bar"));
54 
55   EXPECT_TRUE(parser.Parse("\tfoo ; bar"));
56 
57   ASSERT_EQ(1U, parser.extensions().size());
58   EXPECT_TRUE(expected.Equals(parser.extensions()[0]));
59 }
60 
TEST(WebSocketExtensionParserTest,ParseOneExtensionWithOneParamWithValue)61 TEST(WebSocketExtensionParserTest, ParseOneExtensionWithOneParamWithValue) {
62   WebSocketExtensionParser parser;
63   WebSocketExtension expected("foo");
64   expected.Add(WebSocketExtension::Parameter("bar", "baz"));
65 
66   EXPECT_TRUE(parser.Parse("foo ; bar= baz\t"));
67 
68   ASSERT_EQ(1U, parser.extensions().size());
69   EXPECT_TRUE(expected.Equals(parser.extensions()[0]));
70 }
71 
TEST(WebSocketExtensionParserTest,ParseOneExtensionWithParams)72 TEST(WebSocketExtensionParserTest, ParseOneExtensionWithParams) {
73   WebSocketExtensionParser parser;
74   WebSocketExtension expected("foo");
75   expected.Add(WebSocketExtension::Parameter("bar", "baz"));
76   expected.Add(WebSocketExtension::Parameter("hoge", "fuga"));
77 
78   EXPECT_TRUE(parser.Parse("foo ; bar= baz;\t \thoge\t\t=fuga"));
79 
80   ASSERT_EQ(1U, parser.extensions().size());
81   EXPECT_TRUE(expected.Equals(parser.extensions()[0]));
82 }
83 
TEST(WebSocketExtensionParserTest,ParseTwoExtensions)84 TEST(WebSocketExtensionParserTest, ParseTwoExtensions) {
85   WebSocketExtensionParser parser;
86 
87   WebSocketExtension expected0("foo");
88   expected0.Add(WebSocketExtension::Parameter("alpha", "x"));
89 
90   WebSocketExtension expected1("bar");
91   expected1.Add(WebSocketExtension::Parameter("beta", "y"));
92 
93   EXPECT_TRUE(parser.Parse(" foo ; alpha = x , bar ; beta = y "));
94 
95   ASSERT_EQ(2U, parser.extensions().size());
96 
97   EXPECT_TRUE(expected0.Equals(parser.extensions()[0]));
98   EXPECT_TRUE(expected1.Equals(parser.extensions()[1]));
99 }
100 
TEST(WebSocketExtensionParserTest,InvalidPatterns)101 TEST(WebSocketExtensionParserTest, InvalidPatterns) {
102   const char* const patterns[] = {
103       ",",                    // just a comma
104       " , ",                  // just a comma with surrounding spaces
105       "foo,",                 // second extension is incomplete (empty)
106       "foo , ",               // second extension is incomplete (space)
107       "foo,;",                // second extension is incomplete (semicolon)
108       "foo;, bar",            // first extension is incomplete
109       "fo\ao",                // control in extension name
110       "fo\x01o",              // control in extension name
111       "fo<o",                 // separator in extension name
112       "foo/",                 // separator in extension name
113       ";bar",                 // empty extension name
114       "foo bar",              // missing ';'
115       "foo;",                 // extension parameter without name and value
116       "foo; b\ar",            // control in parameter name
117       "foo; b\x7fr",          // control in parameter name
118       "foo; b[r",             // separator in parameter name
119       "foo; ba:",             // separator in parameter name
120       "foo; =baz",            // empty parameter name
121       "foo; bar=",            // empty parameter value
122       "foo; =",               // empty parameter name and value
123       "foo; bar=b\x02z",      // control in parameter value
124       "foo; bar=b@z",         // separator in parameter value
125       "foo; bar=b\\z",        // separator in parameter value
126       "foo; bar=b?z",         // separator in parameter value
127       "\"foo\"",              // quoted extension name
128       "foo; \"bar\"",         // quoted parameter name
129       "foo; bar=\"\a2\"",     // control in quoted parameter value
130       "foo; bar=\"b@z\"",     // separator in quoted parameter value
131       "foo; bar=\"b\\\\z\"",  // separator in quoted parameter value
132       "foo; bar=\"\"",        // quoted empty parameter value
133       "foo; bar=\"baz",       // unterminated quoted string
134       "foo; bar=\"baz \"",    // space in quoted string
135       "foo; bar baz",         // missing '='
136       "foo; bar - baz",  // '-' instead of '=' (note: "foo; bar-baz" is valid).
137       "foo; bar=\r\nbaz",   // CRNL not followed by a space
138       "foo; bar=\r\n baz",  // CRNL followed by a space
139       "f\xFFpp",            // 8-bit character in extension name
140       "foo; b\xFFr=baz"     // 8-bit character in parameter name
141       "foo; bar=b\xFF"      // 8-bit character in parameter value
142       "foo; bar=\"b\xFF\""  // 8-bit character in quoted parameter value
143       "foo; bar=\"baz\\"    // ends with backslash
144   };
145 
146   for (size_t i = 0; i < base::size(patterns); ++i) {
147     WebSocketExtensionParser parser;
148     EXPECT_FALSE(parser.Parse(patterns[i]));
149     EXPECT_EQ(0U, parser.extensions().size());
150   }
151 }
152 
TEST(WebSocketExtensionParserTest,QuotedParameterValue)153 TEST(WebSocketExtensionParserTest, QuotedParameterValue) {
154   WebSocketExtensionParser parser;
155   WebSocketExtension expected("foo");
156   expected.Add(WebSocketExtension::Parameter("bar", "baz"));
157 
158   EXPECT_TRUE(parser.Parse("foo; bar = \"ba\\z\" "));
159 
160   ASSERT_EQ(1U, parser.extensions().size());
161   EXPECT_TRUE(expected.Equals(parser.extensions()[0]));
162 }
163 
164 // This is a regression test for crbug.com/647156
TEST(WebSocketExtensionParserTest,InvalidToken)165 TEST(WebSocketExtensionParserTest, InvalidToken) {
166   static const char kInvalidInput[] = "\304;\304!*777\377=\377\254\377";
167   WebSocketExtensionParser parser;
168   EXPECT_FALSE(parser.Parse(kInvalidInput));
169 }
170 
171 }  // namespace
172 
173 }  // namespace net
174