| 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..560ba0d1789d9919f8bd32be8d3739b5af32e1fe
|
| --- /dev/null
|
| +++ b/net/websockets/websocket_extension_parser.cc
|
| @@ -0,0 +1,158 @@
|
| +// 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 {
|
| +
|
| +WebSocketExtensionParser::WebSocketExtensionParser() {}
|
| +
|
| +WebSocketExtensionParser::~WebSocketExtensionParser() {}
|
| +
|
| +void WebSocketExtensionParser::Parse(const char* data, size_t size) {
|
| + current_ = data;
|
| + end_ = data + size;
|
| + has_error_ = false;
|
| +
|
| + ConsumeExtension(&extension_);
|
| + if (has_error_) return;
|
| + ConsumeSpaces();
|
| + has_error_ = has_error_ || (current_ != end_);
|
| +}
|
| +
|
| +void WebSocketExtensionParser::Consume(char c) {
|
| + DCHECK(!has_error_);
|
| + ConsumeSpaces();
|
| + DCHECK(!has_error_);
|
| + if (current_ == end_ || c != current_[0]) {
|
| + has_error_ = true;
|
| + return;
|
| + }
|
| + ++current_;
|
| +}
|
| +
|
| +void WebSocketExtensionParser::ConsumeExtension(WebSocketExtension* extension) {
|
| + DCHECK(!has_error_);
|
| + base::StringPiece name;
|
| + ConsumeToken(&name);
|
| + if (has_error_) return;
|
| + *extension = WebSocketExtension(name.as_string());
|
| +
|
| + while (ConsumeIfMatch(';')) {
|
| + WebSocketExtension::Parameter parameter((std::string()));
|
| + ConsumeExtensionParameter(¶meter);
|
| + if (has_error_) return;
|
| + extension->Add(parameter);
|
| + }
|
| +}
|
| +
|
| +void WebSocketExtensionParser::ConsumeExtensionParameter(
|
| + WebSocketExtension::Parameter* parameter) {
|
| + DCHECK(!has_error_);
|
| + base::StringPiece name, value;
|
| + std::string value_string;
|
| +
|
| + ConsumeToken(&name);
|
| + if (has_error_) return;
|
| + if (!ConsumeIfMatch('=')) {
|
| + *parameter = WebSocketExtension::Parameter(name.as_string());
|
| + return;
|
| + }
|
| +
|
| + if (Lookahead('\"')) {
|
| + ConsumeQuotedToken(&value_string);
|
| + } else {
|
| + ConsumeToken(&value);
|
| + value_string = value.as_string();
|
| + }
|
| + if (has_error_) return;
|
| + *parameter = WebSocketExtension::Parameter(name.as_string(), value_string);
|
| +}
|
| +
|
| +void WebSocketExtensionParser::ConsumeToken(base::StringPiece* token) {
|
| + DCHECK(!has_error_);
|
| + ConsumeSpaces();
|
| + 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_);
|
| + Consume('"');
|
| + 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_;
|
| + }
|
| + }
|
| + // We can't use Consume here because we don't want to consume spaces.
|
| + if (current_ < end_ && current_[0] == '"')
|
| + ++current_;
|
| + else
|
| + has_error_ = true;
|
| + has_error_ = has_error_ || token->empty();
|
| +}
|
| +
|
| +void WebSocketExtensionParser::ConsumeSpaces() {
|
| + DCHECK(!has_error_);
|
| + while (current_ < end_ && (current_[0] == ' ' || current_[0] == '\t'))
|
| + ++current_;
|
| + return;
|
| +}
|
| +
|
| +bool WebSocketExtensionParser::Lookahead(char c) {
|
| + DCHECK(!has_error_);
|
| + const char* head = current_;
|
| +
|
| + Consume(c);
|
| + bool result = !has_error_;
|
| + current_ = head;
|
| + has_error_ = false;
|
| + return result;
|
| +}
|
| +
|
| +bool WebSocketExtensionParser::ConsumeIfMatch(char c) {
|
| + DCHECK(!has_error_);
|
| + const char* head = current_;
|
| +
|
| + Consume(c);
|
| + if (has_error_) {
|
| + current_ = head;
|
| + has_error_ = false;
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +// 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
|
|
|