OLD | NEW |
---|---|
(Empty) | |
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 "base/strings/string_util.h" | |
8 | |
9 namespace net { | |
10 | |
11 // Backup the head pointer if the parser has error. | |
Adam Rice
2013/09/17 04:30:33
I think this grammar can be parsed with single-cha
yhirano
2013/09/17 06:03:31
I deleted some |has_error_ = false| statements.
Th
| |
12 class WebSocketExtensionParser::CurrentPointerBackup { | |
13 public: | |
14 explicit CurrentPointerBackup(WebSocketExtensionParser* parser); | |
15 ~CurrentPointerBackup(); | |
16 | |
17 private: | |
18 WebSocketExtensionParser* parser_; | |
19 const char* original_head_; | |
20 }; | |
21 | |
22 WebSocketExtensionParser::CurrentPointerBackup::CurrentPointerBackup( | |
23 WebSocketExtensionParser* parser) | |
24 : parser_(parser), original_head_(parser->current_) {} | |
25 | |
26 WebSocketExtensionParser::CurrentPointerBackup::~CurrentPointerBackup() { | |
27 if (parser_->has_error_) | |
28 parser_->current_ = original_head_; | |
29 } | |
30 | |
31 WebSocketExtensionParser::WebSocketExtensionParser() {} | |
32 | |
33 WebSocketExtensionParser::~WebSocketExtensionParser() {} | |
34 | |
35 void WebSocketExtensionParser::Parse(const char* data, size_t size) { | |
36 current_ = data; | |
37 end_ = &data[size]; | |
38 extensions_.clear(); | |
39 has_error_ = false; | |
40 CurrentPointerBackup backup(this); | |
41 | |
42 ConsumeExtensionList(); | |
43 has_error_ = has_error_ || (current_ != end_); | |
44 if (has_error_) | |
45 extensions_.clear(); | |
46 } | |
47 | |
48 void WebSocketExtensionParser::Consume(const char* data, size_t size) { | |
49 DCHECK(!has_error_); | |
50 CurrentPointerBackup backup(this); | |
51 ConsumeLWS(); | |
52 DCHECK(!has_error_); | |
53 if (UnconsumedBytes() < size) { | |
54 has_error_ = true; | |
55 return; | |
56 } | |
57 if (memcmp(data, current_, size)) { | |
58 has_error_ = true; | |
59 return; | |
60 } | |
61 current_ += size; | |
62 } | |
63 | |
64 void WebSocketExtensionParser::ConsumeExtensionList() { | |
65 DCHECK(!has_error_); | |
66 WebSocketExtension extension(""); | |
67 ConsumeExtension(&extension); | |
68 if (has_error_) return; | |
69 do { | |
70 extensions_.push_back(extension); | |
71 ConsumeExtension(&extension); | |
72 } while (!has_error_); | |
73 has_error_ = false; | |
74 } | |
75 | |
76 void WebSocketExtensionParser::ConsumeExtension(WebSocketExtension* extension) { | |
77 DCHECK(!has_error_); | |
78 CurrentPointerBackup backup(this); | |
79 base::StringPiece name; | |
80 ConsumeToken(&name); | |
81 if (has_error_) return; | |
82 *extension = WebSocketExtension(name.as_string()); | |
83 | |
84 | |
85 while (true) { | |
86 Consume(";", 1); | |
87 if (has_error_) { | |
88 has_error_ = false; | |
89 return; | |
90 } | |
91 WebSocketExtension::Parameter parameter(""); | |
92 ConsumeExtensionParameter(¶meter); | |
93 if (has_error_) return; | |
94 extension->Add(parameter); | |
95 } | |
96 } | |
97 | |
98 void WebSocketExtensionParser::ConsumeExtensionParameter( | |
99 WebSocketExtension::Parameter* parameter) { | |
100 DCHECK(!has_error_); | |
101 CurrentPointerBackup backup(this); | |
102 base::StringPiece name, value; | |
103 std::string value_string; | |
104 | |
105 ConsumeToken(&name); | |
106 if (has_error_) return; | |
107 Consume("=", 1); | |
108 if (has_error_) { | |
109 has_error_ = false; | |
110 *parameter = WebSocketExtension::Parameter(name.as_string()); | |
111 return; | |
112 } | |
113 | |
114 ConsumeToken(&value); | |
115 if (has_error_) { | |
116 has_error_ = false; | |
117 ConsumeQuotedToken(&value_string); | |
118 if (has_error_) return; | |
119 } else { | |
120 value_string = value.as_string(); | |
121 } | |
122 *parameter = WebSocketExtension::Parameter(name.as_string(), value_string); | |
123 } | |
124 | |
125 void WebSocketExtensionParser::ConsumeToken(base::StringPiece* token) { | |
126 DCHECK(!has_error_); | |
127 CurrentPointerBackup backup(this); | |
128 ConsumeLWS(); | |
129 DCHECK(!has_error_); | |
130 const char* head = current_; | |
131 while (current_ < end_ && | |
132 !IsControl(current_[0]) && !IsSeparator(current_[0])) | |
133 ++current_; | |
134 if (current_ == head) { | |
135 has_error_ = true; | |
136 return; | |
137 } | |
138 *token = base::StringPiece(head, current_ - head); | |
139 } | |
140 | |
141 void WebSocketExtensionParser::ConsumeQuotedToken(std::string* token) { | |
142 DCHECK(!has_error_); | |
143 CurrentPointerBackup backup(this); | |
144 Consume("\"", 1); | |
145 if (has_error_) return; | |
146 *token = ""; | |
147 while (current_ < end_ && !IsControl(current_[0])) { | |
148 if (UnconsumedBytes() >= 2 && current_[0] == '\\') { | |
149 char next = current_[1]; | |
150 if (IsControl(next) || IsSeparator(next)) break; | |
151 *token += next; | |
152 current_ += 2; | |
153 } else if (IsSeparator(current_[0])) { | |
154 break; | |
155 } else { | |
156 *token += current_[0]; | |
157 ++current_; | |
158 } | |
159 } | |
160 Consume("\"", 1); | |
161 has_error_ = has_error_ || token->empty(); | |
162 } | |
163 | |
164 // Unlike the "implied *LWS" specification in RFC2616, this parser | |
165 // consumes *LWS, because there are no adjacent tokens in WebSocket | |
166 // extension grammer. | |
167 void WebSocketExtensionParser::ConsumeLWS() { | |
168 DCHECK(!has_error_); | |
169 size_t counter = 0; | |
170 while (current_ < end_) { | |
171 if (current_[0] == ' ' || current_[0] == '\t') { | |
172 while (current_ < end_ && (current_[0] == ' ' || current_[0] == '\t')) | |
173 ++current_; | |
174 } else if (UnconsumedBytes() >= 3 && | |
175 current_[0] == '\r' && current_[1] == '\n' && | |
176 (current_[2] == ' ' || current_[2] == '\t')) { | |
177 current_ += 2; | |
178 while (current_ < end_ && (current_[0] == ' ' || current_[0] == '\t')) | |
179 ++current_; | |
180 break; | |
181 } else { | |
182 break; | |
183 } | |
184 ++counter; | |
185 } | |
186 return; | |
187 } | |
188 | |
189 // static | |
190 bool WebSocketExtensionParser::IsControl(char c) { | |
191 return (0 <= c && c <= 31) || c == 127; | |
192 } | |
193 | |
194 // static | |
195 bool WebSocketExtensionParser::IsSeparator(char c) { | |
196 const char separators[] = "()<>@,;:\\\"/[]?={} \t"; | |
197 return strchr(separators, c); | |
198 } | |
199 | |
200 } // namespace net | |
OLD | NEW |