| // 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/logging.h" | |
| #include "net/http/http_util.h" | |
| namespace net { | |
| WebSocketExtensionParser::WebSocketExtensionParser() {} | |
| WebSocketExtensionParser::~WebSocketExtensionParser() {} | |
| bool WebSocketExtensionParser::Parse(const char* data, size_t size) { | |
| current_ = data; | |
| end_ = data + size; | |
| extensions_.clear(); | |
| bool failed = false; | |
| do { | |
| WebSocketExtension extension; | |
| if (!ConsumeExtension(&extension)) { | |
| failed = true; | |
| break; | |
| } | |
| extensions_.push_back(extension); | |
| ConsumeSpaces(); | |
| } while (ConsumeIfMatch(',')); | |
| if (!failed && current_ == end_) | |
| return true; | |
| extensions_.clear(); | |
| return false; | |
| } | |
| bool WebSocketExtensionParser::Consume(char c) { | |
| ConsumeSpaces(); | |
| if (current_ == end_ || c != *current_) | |
| return false; | |
| ++current_; | |
| return true; | |
| } | |
| bool WebSocketExtensionParser::ConsumeExtension(WebSocketExtension* extension) { | |
| base::StringPiece name; | |
| if (!ConsumeToken(&name)) | |
| return false; | |
| *extension = WebSocketExtension(name.as_string()); | |
| while (ConsumeIfMatch(';')) { | |
| WebSocketExtension::Parameter parameter((std::string())); | |
| if (!ConsumeExtensionParameter(¶meter)) | |
| return false; | |
| extension->Add(parameter); | |
| } | |
| return true; | |
| } | |
| bool WebSocketExtensionParser::ConsumeExtensionParameter( | |
| WebSocketExtension::Parameter* parameter) { | |
| base::StringPiece name, value; | |
| std::string value_string; | |
| if (!ConsumeToken(&name)) | |
| return false; | |
| if (!ConsumeIfMatch('=')) { | |
| *parameter = WebSocketExtension::Parameter(name.as_string()); | |
| return true; | |
| } | |
| if (Lookahead('\"')) { | |
| if (!ConsumeQuotedToken(&value_string)) | |
| return false; | |
| } else { | |
| if (!ConsumeToken(&value)) | |
| return false; | |
| value_string = value.as_string(); | |
| } | |
| *parameter = WebSocketExtension::Parameter(name.as_string(), value_string); | |
| return true; | |
| } | |
| bool WebSocketExtensionParser::ConsumeToken(base::StringPiece* token) { | |
| ConsumeSpaces(); | |
| const char* head = current_; | |
| while (current_ < end_ && HttpUtil::IsTokenChar(*current_)) | |
| ++current_; | |
| if (current_ == head) | |
| return false; | |
| *token = base::StringPiece(head, current_ - head); | |
| return true; | |
| } | |
| bool WebSocketExtensionParser::ConsumeQuotedToken(std::string* token) { | |
| if (!Consume('"')) | |
| return false; | |
| *token = ""; | |
| while (current_ < end_ && *current_ != '"') { | |
| if (*current_ == '\\') { | |
| ++current_; | |
| if (current_ == end_) | |
| return false; | |
| } | |
| if (!HttpUtil::IsTokenChar(*current_)) | |
| return false; | |
| *token += *current_; | |
| ++current_; | |
| } | |
| if (current_ == end_) | |
| return false; | |
| DCHECK_EQ(*current_, '"'); | |
| ++current_; | |
| return !token->empty(); | |
| } | |
| void WebSocketExtensionParser::ConsumeSpaces() { | |
| while (current_ < end_ && (*current_ == ' ' || *current_ == '\t')) | |
| ++current_; | |
| return; | |
| } | |
| bool WebSocketExtensionParser::Lookahead(char c) { | |
| const char* head = current_; | |
| bool result = Consume(c); | |
| current_ = head; | |
| return result; | |
| } | |
| bool WebSocketExtensionParser::ConsumeIfMatch(char c) { | |
| const char* head = current_; | |
| if (!Consume(c)) { | |
| current_ = head; | |
| return false; | |
| } | |
| return true; | |
| } | |
| } // namespace net |