Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(83)

Side by Side Diff: net/websockets/websocket_extension_parser.cc

Issue 23872029: Implement WebSocketExtensionParser (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 // Restore the current pointer if the parser has an error.
12 class WebSocketExtensionParser::CurrentPointerBackup {
Adam Rice 2013/09/17 07:45:58 Sorry my comment was not clear enough. The parser
yhirano 2013/09/17 09:17:39 Done.
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() {
Adam Rice 2013/09/17 07:45:58 We only need to parse one extension at a time, so
yhirano 2013/09/17 09:17:39 Done.
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 while (ConsumeIfMatch(";", 1)) {
85 WebSocketExtension::Parameter parameter("");
86 ConsumeExtensionParameter(&parameter);
87 if (has_error_) return;
88 extension->Add(parameter);
89 }
90 }
91
92 void WebSocketExtensionParser::ConsumeExtensionParameter(
93 WebSocketExtension::Parameter* parameter) {
94 DCHECK(!has_error_);
95 CurrentPointerBackup backup(this);
96 base::StringPiece name, value;
97 std::string value_string;
98
99 ConsumeToken(&name);
100 if (has_error_) return;
101 if (!ConsumeIfMatch("=", 1)) {
102 *parameter = WebSocketExtension::Parameter(name.as_string());
103 return;
104 }
105
106 if (Lookahead("\"", 1)) {
107 ConsumeQuotedToken(&value_string);
108 } else {
109 ConsumeToken(&value);
110 value_string = value.as_string();
111 }
112 if (has_error_) return;
113 *parameter = WebSocketExtension::Parameter(name.as_string(), value_string);
114 }
115
116 void WebSocketExtensionParser::ConsumeToken(base::StringPiece* token) {
117 DCHECK(!has_error_);
118 CurrentPointerBackup backup(this);
119 ConsumeLWS();
120 DCHECK(!has_error_);
121 const char* head = current_;
122 while (current_ < end_ &&
123 !IsControl(current_[0]) && !IsSeparator(current_[0]))
124 ++current_;
125 if (current_ == head) {
126 has_error_ = true;
127 return;
128 }
129 *token = base::StringPiece(head, current_ - head);
130 }
131
132 void WebSocketExtensionParser::ConsumeQuotedToken(std::string* token) {
133 DCHECK(!has_error_);
134 CurrentPointerBackup backup(this);
135 Consume("\"", 1);
136 if (has_error_) return;
137 *token = "";
138 while (current_ < end_ && !IsControl(current_[0])) {
139 if (UnconsumedBytes() >= 2 && current_[0] == '\\') {
140 char next = current_[1];
141 if (IsControl(next) || IsSeparator(next)) break;
142 *token += next;
143 current_ += 2;
144 } else if (IsSeparator(current_[0])) {
145 break;
146 } else {
147 *token += current_[0];
148 ++current_;
149 }
150 }
151 Consume("\"", 1);
152 has_error_ = has_error_ || token->empty();
153 }
154
155 // Unlike the "implied *LWS" specification in RFC2616, this parser
156 // consumes *LWS, because there are no adjacent tokens in WebSocket
157 // extension grammer.
158 void WebSocketExtensionParser::ConsumeLWS() {
159 DCHECK(!has_error_);
160 size_t counter = 0;
161 while (current_ < end_) {
162 if (current_[0] == ' ' || current_[0] == '\t') {
163 while (current_ < end_ && (current_[0] == ' ' || current_[0] == '\t'))
164 ++current_;
165 } else if (UnconsumedBytes() >= 3 &&
166 current_[0] == '\r' && current_[1] == '\n' &&
Adam Rice 2013/09/17 07:45:58 Line coalescing is implemented by HttpResponseHead
yhirano 2013/09/17 09:17:39 Done.
167 (current_[2] == ' ' || current_[2] == '\t')) {
168 current_ += 2;
169 while (current_ < end_ && (current_[0] == ' ' || current_[0] == '\t'))
170 ++current_;
171 break;
172 } else {
173 break;
174 }
175 ++counter;
176 }
177 return;
178 }
179
180 bool WebSocketExtensionParser::Lookahead(const char* data, size_t size) {
Adam Rice 2013/09/17 07:45:58 Having "size" makes this method much more complica
yhirano 2013/09/17 09:17:39 I like this prototype because we can check an erro
181 DCHECK(!has_error_);
182 const char* head = current_;
183
184 ConsumeLWS();
185 if (!has_error_)
186 Consume(data, size);
187
188 bool result = !has_error_;
189 current_ = head;
190 has_error_ = false;
191 return result;
192 }
193
194 bool WebSocketExtensionParser::ConsumeIfMatch(const char* data, size_t size) {
195 DCHECK(!has_error_);
196 const char* head = current_;
197
198 ConsumeLWS();
199 if (!has_error_)
200 Consume(data, size);
201
202 if (has_error_) {
203 current_ = head;
204 has_error_ = false;
205 return false;
206 }
207 return true;
208 }
209
210 // static
211 bool WebSocketExtensionParser::IsControl(char c) {
212 return (0 <= c && c <= 31) || c == 127;
213 }
214
215 // static
216 bool WebSocketExtensionParser::IsSeparator(char c) {
217 const char separators[] = "()<>@,;:\\\"/[]?={} \t";
218 return strchr(separators, c);
219 }
220
221 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698