OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/websockets/websocket_extension_parser.h" | 5 #include "net/websockets/websocket_extension_parser.h" |
6 | 6 |
7 #include "base/strings/string_util.h" | 7 #include "base/logging.h" |
| 8 #include "net/http/http_util.h" |
8 | 9 |
9 namespace net { | 10 namespace net { |
10 | 11 |
11 WebSocketExtensionParser::WebSocketExtensionParser() {} | 12 WebSocketExtensionParser::WebSocketExtensionParser() {} |
12 | 13 |
13 WebSocketExtensionParser::~WebSocketExtensionParser() {} | 14 WebSocketExtensionParser::~WebSocketExtensionParser() {} |
14 | 15 |
15 bool WebSocketExtensionParser::Parse(const char* data, size_t size) { | 16 bool WebSocketExtensionParser::Parse(const char* data, size_t size) { |
16 current_ = data; | 17 current_ = data; |
17 end_ = data + size; | 18 end_ = data + size; |
18 extensions_.clear(); | 19 extensions_.clear(); |
19 | 20 |
20 bool failed = false; | 21 bool failed = false; |
21 | 22 |
22 while (true) { | 23 do { |
23 WebSocketExtension extension; | 24 WebSocketExtension extension; |
24 if (!ConsumeExtension(&extension)) { | 25 if (!ConsumeExtension(&extension)) { |
25 failed = true; | 26 failed = true; |
26 break; | 27 break; |
27 } | 28 } |
28 extensions_.push_back(extension); | 29 extensions_.push_back(extension); |
29 | 30 |
30 ConsumeSpaces(); | 31 ConsumeSpaces(); |
31 | 32 } while (ConsumeIfMatch(',')); |
32 if (!ConsumeIfMatch(',')) { | |
33 break; | |
34 } | |
35 } | |
36 | 33 |
37 if (!failed && current_ == end_) | 34 if (!failed && current_ == end_) |
38 return true; | 35 return true; |
39 | 36 |
40 extensions_.clear(); | 37 extensions_.clear(); |
41 return false; | 38 return false; |
42 } | 39 } |
43 | 40 |
44 bool WebSocketExtensionParser::Consume(char c) { | 41 bool WebSocketExtensionParser::Consume(char c) { |
45 ConsumeSpaces(); | 42 ConsumeSpaces(); |
46 if (current_ == end_ || c != current_[0]) { | 43 if (current_ == end_ || c != *current_) |
47 return false; | 44 return false; |
48 } | |
49 ++current_; | 45 ++current_; |
50 return true; | 46 return true; |
51 } | 47 } |
52 | 48 |
53 bool WebSocketExtensionParser::ConsumeExtension(WebSocketExtension* extension) { | 49 bool WebSocketExtensionParser::ConsumeExtension(WebSocketExtension* extension) { |
54 base::StringPiece name; | 50 base::StringPiece name; |
55 if (!ConsumeToken(&name)) | 51 if (!ConsumeToken(&name)) |
56 return false; | 52 return false; |
57 *extension = WebSocketExtension(name.as_string()); | 53 *extension = WebSocketExtension(name.as_string()); |
58 | 54 |
(...skipping 28 matching lines...) Expand all Loading... |
87 return false; | 83 return false; |
88 value_string = value.as_string(); | 84 value_string = value.as_string(); |
89 } | 85 } |
90 *parameter = WebSocketExtension::Parameter(name.as_string(), value_string); | 86 *parameter = WebSocketExtension::Parameter(name.as_string(), value_string); |
91 return true; | 87 return true; |
92 } | 88 } |
93 | 89 |
94 bool WebSocketExtensionParser::ConsumeToken(base::StringPiece* token) { | 90 bool WebSocketExtensionParser::ConsumeToken(base::StringPiece* token) { |
95 ConsumeSpaces(); | 91 ConsumeSpaces(); |
96 const char* head = current_; | 92 const char* head = current_; |
97 while (current_ < end_ && | 93 while (current_ < end_ && HttpUtil::IsTokenChar(*current_)) |
98 !IsControl(current_[0]) && !IsSeparator(current_[0])) | |
99 ++current_; | 94 ++current_; |
100 if (current_ == head) { | 95 if (current_ == head) |
101 return false; | 96 return false; |
102 } | |
103 *token = base::StringPiece(head, current_ - head); | 97 *token = base::StringPiece(head, current_ - head); |
104 return true; | 98 return true; |
105 } | 99 } |
106 | 100 |
107 bool WebSocketExtensionParser::ConsumeQuotedToken(std::string* token) { | 101 bool WebSocketExtensionParser::ConsumeQuotedToken(std::string* token) { |
108 if (!Consume('"')) | 102 if (!Consume('"')) |
109 return false; | 103 return false; |
110 | 104 |
111 *token = ""; | 105 *token = ""; |
112 while (current_ < end_ && !IsControl(current_[0])) { | 106 while (current_ < end_ && *current_ != '"') { |
113 if (UnconsumedBytes() >= 2 && current_[0] == '\\') { | 107 if (*current_ == '\\') { |
114 char next = current_[1]; | |
115 if (IsControl(next) || IsSeparator(next)) break; | |
116 *token += next; | |
117 current_ += 2; | |
118 } else if (IsSeparator(current_[0])) { | |
119 break; | |
120 } else { | |
121 *token += current_[0]; | |
122 ++current_; | 108 ++current_; |
| 109 if (current_ == end_) |
| 110 return false; |
123 } | 111 } |
| 112 if (!HttpUtil::IsTokenChar(*current_)) |
| 113 return false; |
| 114 *token += *current_; |
| 115 ++current_; |
124 } | 116 } |
125 // We can't use Consume here because we don't want to consume spaces. | 117 if (current_ == end_) |
126 if (current_ >= end_ || current_[0] != '"') | |
127 return false; | 118 return false; |
| 119 DCHECK_EQ(*current_, '"'); |
128 | 120 |
129 ++current_; | 121 ++current_; |
130 | 122 |
131 return !token->empty(); | 123 return !token->empty(); |
132 } | 124 } |
133 | 125 |
134 void WebSocketExtensionParser::ConsumeSpaces() { | 126 void WebSocketExtensionParser::ConsumeSpaces() { |
135 while (current_ < end_ && (current_[0] == ' ' || current_[0] == '\t')) | 127 while (current_ < end_ && (*current_ == ' ' || *current_ == '\t')) |
136 ++current_; | 128 ++current_; |
137 return; | 129 return; |
138 } | 130 } |
139 | 131 |
140 bool WebSocketExtensionParser::Lookahead(char c) { | 132 bool WebSocketExtensionParser::Lookahead(char c) { |
141 const char* head = current_; | 133 const char* head = current_; |
142 bool result = Consume(c); | 134 bool result = Consume(c); |
143 current_ = head; | 135 current_ = head; |
144 return result; | 136 return result; |
145 } | 137 } |
146 | 138 |
147 bool WebSocketExtensionParser::ConsumeIfMatch(char c) { | 139 bool WebSocketExtensionParser::ConsumeIfMatch(char c) { |
148 const char* head = current_; | 140 const char* head = current_; |
149 if (!Consume(c)) { | 141 if (!Consume(c)) { |
150 current_ = head; | 142 current_ = head; |
151 return false; | 143 return false; |
152 } | 144 } |
153 | 145 |
154 return true; | 146 return true; |
155 } | 147 } |
156 | 148 |
157 // static | |
158 bool WebSocketExtensionParser::IsControl(char c) { | |
159 return (0 <= c && c <= 31) || c == 127; | |
160 } | |
161 | |
162 // static | |
163 bool WebSocketExtensionParser::IsSeparator(char c) { | |
164 const char separators[] = "()<>@,;:\\\"/[]?={} \t"; | |
165 return strchr(separators, c) != NULL; | |
166 } | |
167 | |
168 } // namespace net | 149 } // namespace net |
OLD | NEW |