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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: net/websockets/websocket_extension_parser.cc
diff --git a/net/websockets/websocket_extension_parser.cc b/net/websockets/websocket_extension_parser.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ea9987b077e1055668bb4998488a167ebbcee433
--- /dev/null
+++ b/net/websockets/websocket_extension_parser.cc
@@ -0,0 +1,200 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/websockets/websocket_extension_parser.h"
+
+#include "base/strings/string_util.h"
+
+namespace net {
+
+// 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
+class WebSocketExtensionParser::CurrentPointerBackup {
+ public:
+ explicit CurrentPointerBackup(WebSocketExtensionParser* parser);
+ ~CurrentPointerBackup();
+
+ private:
+ WebSocketExtensionParser* parser_;
+ const char* original_head_;
+};
+
+WebSocketExtensionParser::CurrentPointerBackup::CurrentPointerBackup(
+ WebSocketExtensionParser* parser)
+ : parser_(parser), original_head_(parser->current_) {}
+
+WebSocketExtensionParser::CurrentPointerBackup::~CurrentPointerBackup() {
+ if (parser_->has_error_)
+ parser_->current_ = original_head_;
+}
+
+WebSocketExtensionParser::WebSocketExtensionParser() {}
+
+WebSocketExtensionParser::~WebSocketExtensionParser() {}
+
+void WebSocketExtensionParser::Parse(const char* data, size_t size) {
+ current_ = data;
+ end_ = &data[size];
+ extensions_.clear();
+ has_error_ = false;
+ CurrentPointerBackup backup(this);
+
+ ConsumeExtensionList();
+ has_error_ = has_error_ || (current_ != end_);
+ if (has_error_)
+ extensions_.clear();
+}
+
+void WebSocketExtensionParser::Consume(const char* data, size_t size) {
+ DCHECK(!has_error_);
+ CurrentPointerBackup backup(this);
+ ConsumeLWS();
+ DCHECK(!has_error_);
+ if (UnconsumedBytes() < size) {
+ has_error_ = true;
+ return;
+ }
+ if (memcmp(data, current_, size)) {
+ has_error_ = true;
+ return;
+ }
+ current_ += size;
+}
+
+void WebSocketExtensionParser::ConsumeExtensionList() {
+ DCHECK(!has_error_);
+ WebSocketExtension extension("");
+ ConsumeExtension(&extension);
+ if (has_error_) return;
+ do {
+ extensions_.push_back(extension);
+ ConsumeExtension(&extension);
+ } while (!has_error_);
+ has_error_ = false;
+}
+
+void WebSocketExtensionParser::ConsumeExtension(WebSocketExtension* extension) {
+ DCHECK(!has_error_);
+ CurrentPointerBackup backup(this);
+ base::StringPiece name;
+ ConsumeToken(&name);
+ if (has_error_) return;
+ *extension = WebSocketExtension(name.as_string());
+
+
+ while (true) {
+ Consume(";", 1);
+ if (has_error_) {
+ has_error_ = false;
+ return;
+ }
+ WebSocketExtension::Parameter parameter("");
+ ConsumeExtensionParameter(&parameter);
+ if (has_error_) return;
+ extension->Add(parameter);
+ }
+}
+
+void WebSocketExtensionParser::ConsumeExtensionParameter(
+ WebSocketExtension::Parameter* parameter) {
+ DCHECK(!has_error_);
+ CurrentPointerBackup backup(this);
+ base::StringPiece name, value;
+ std::string value_string;
+
+ ConsumeToken(&name);
+ if (has_error_) return;
+ Consume("=", 1);
+ if (has_error_) {
+ has_error_ = false;
+ *parameter = WebSocketExtension::Parameter(name.as_string());
+ return;
+ }
+
+ ConsumeToken(&value);
+ if (has_error_) {
+ has_error_ = false;
+ ConsumeQuotedToken(&value_string);
+ if (has_error_) return;
+ } else {
+ value_string = value.as_string();
+ }
+ *parameter = WebSocketExtension::Parameter(name.as_string(), value_string);
+}
+
+void WebSocketExtensionParser::ConsumeToken(base::StringPiece* token) {
+ DCHECK(!has_error_);
+ CurrentPointerBackup backup(this);
+ ConsumeLWS();
+ DCHECK(!has_error_);
+ const char* head = current_;
+ while (current_ < end_ &&
+ !IsControl(current_[0]) && !IsSeparator(current_[0]))
+ ++current_;
+ if (current_ == head) {
+ has_error_ = true;
+ return;
+ }
+ *token = base::StringPiece(head, current_ - head);
+}
+
+void WebSocketExtensionParser::ConsumeQuotedToken(std::string* token) {
+ DCHECK(!has_error_);
+ CurrentPointerBackup backup(this);
+ Consume("\"", 1);
+ if (has_error_) return;
+ *token = "";
+ while (current_ < end_ && !IsControl(current_[0])) {
+ if (UnconsumedBytes() >= 2 && current_[0] == '\\') {
+ char next = current_[1];
+ if (IsControl(next) || IsSeparator(next)) break;
+ *token += next;
+ current_ += 2;
+ } else if (IsSeparator(current_[0])) {
+ break;
+ } else {
+ *token += current_[0];
+ ++current_;
+ }
+ }
+ Consume("\"", 1);
+ has_error_ = has_error_ || token->empty();
+}
+
+// Unlike the "implied *LWS" specification in RFC2616, this parser
+// consumes *LWS, because there are no adjacent tokens in WebSocket
+// extension grammer.
+void WebSocketExtensionParser::ConsumeLWS() {
+ DCHECK(!has_error_);
+ size_t counter = 0;
+ while (current_ < end_) {
+ if (current_[0] == ' ' || current_[0] == '\t') {
+ while (current_ < end_ && (current_[0] == ' ' || current_[0] == '\t'))
+ ++current_;
+ } else if (UnconsumedBytes() >= 3 &&
+ current_[0] == '\r' && current_[1] == '\n' &&
+ (current_[2] == ' ' || current_[2] == '\t')) {
+ current_ += 2;
+ while (current_ < end_ && (current_[0] == ' ' || current_[0] == '\t'))
+ ++current_;
+ break;
+ } else {
+ break;
+ }
+ ++counter;
+ }
+ return;
+}
+
+// static
+bool WebSocketExtensionParser::IsControl(char c) {
+ return (0 <= c && c <= 31) || c == 127;
+}
+
+// static
+bool WebSocketExtensionParser::IsSeparator(char c) {
+ const char separators[] = "()<>@,;:\\\"/[]?={} \t";
+ return strchr(separators, c);
+}
+
+} // namespace net

Powered by Google App Engine
This is Rietveld 408576698