1 // Copyright 2013 The Chromium Authors 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 <string_view> 8 9 #include "base/check_op.h" 10 #include "net/http/http_util.h" 11 12 namespace net { 13 14 WebSocketExtensionParser::WebSocketExtensionParser() = default; 15 16 WebSocketExtensionParser::~WebSocketExtensionParser() = default; 17 Parse(const char * data,size_t size)18bool WebSocketExtensionParser::Parse(const char* data, size_t size) { 19 current_ = data; 20 end_ = data + size; 21 extensions_.clear(); 22 23 bool failed = false; 24 25 do { 26 WebSocketExtension extension; 27 if (!ConsumeExtension(&extension)) { 28 failed = true; 29 break; 30 } 31 extensions_.push_back(extension); 32 33 ConsumeSpaces(); 34 } while (ConsumeIfMatch(',')); 35 36 if (!failed && current_ == end_) 37 return true; 38 39 extensions_.clear(); 40 return false; 41 } 42 Consume(char c)43bool WebSocketExtensionParser::Consume(char c) { 44 ConsumeSpaces(); 45 if (current_ == end_ || c != *current_) 46 return false; 47 ++current_; 48 return true; 49 } 50 ConsumeExtension(WebSocketExtension * extension)51bool WebSocketExtensionParser::ConsumeExtension(WebSocketExtension* extension) { 52 std::string_view name; 53 if (!ConsumeToken(&name)) 54 return false; 55 *extension = WebSocketExtension(std::string(name)); 56 57 while (ConsumeIfMatch(';')) { 58 WebSocketExtension::Parameter parameter((std::string())); 59 if (!ConsumeExtensionParameter(¶meter)) 60 return false; 61 extension->Add(parameter); 62 } 63 64 return true; 65 } 66 ConsumeExtensionParameter(WebSocketExtension::Parameter * parameter)67bool WebSocketExtensionParser::ConsumeExtensionParameter( 68 WebSocketExtension::Parameter* parameter) { 69 std::string_view name, value; 70 std::string value_string; 71 72 if (!ConsumeToken(&name)) 73 return false; 74 75 if (!ConsumeIfMatch('=')) { 76 *parameter = WebSocketExtension::Parameter(std::string(name)); 77 return true; 78 } 79 80 if (Lookahead('\"')) { 81 if (!ConsumeQuotedToken(&value_string)) 82 return false; 83 } else { 84 if (!ConsumeToken(&value)) 85 return false; 86 value_string = std::string(value); 87 } 88 *parameter = WebSocketExtension::Parameter(std::string(name), value_string); 89 return true; 90 } 91 ConsumeToken(std::string_view * token)92bool WebSocketExtensionParser::ConsumeToken(std::string_view* token) { 93 ConsumeSpaces(); 94 const char* head = current_; 95 while (current_ < end_ && HttpUtil::IsTokenChar(*current_)) 96 ++current_; 97 if (current_ == head) 98 return false; 99 *token = std::string_view(head, current_ - head); 100 return true; 101 } 102 ConsumeQuotedToken(std::string * token)103bool WebSocketExtensionParser::ConsumeQuotedToken(std::string* token) { 104 if (!Consume('"')) 105 return false; 106 107 *token = ""; 108 while (current_ < end_ && *current_ != '"') { 109 if (*current_ == '\\') { 110 ++current_; 111 if (current_ == end_) 112 return false; 113 } 114 if (!HttpUtil::IsTokenChar(*current_)) 115 return false; 116 *token += *current_; 117 ++current_; 118 } 119 if (current_ == end_) 120 return false; 121 DCHECK_EQ(*current_, '"'); 122 123 ++current_; 124 125 return !token->empty(); 126 } 127 ConsumeSpaces()128void WebSocketExtensionParser::ConsumeSpaces() { 129 while (current_ < end_ && (*current_ == ' ' || *current_ == '\t')) 130 ++current_; 131 return; 132 } 133 Lookahead(char c)134bool WebSocketExtensionParser::Lookahead(char c) { 135 const char* head = current_; 136 bool result = Consume(c); 137 current_ = head; 138 return result; 139 } 140 ConsumeIfMatch(char c)141bool WebSocketExtensionParser::ConsumeIfMatch(char c) { 142 const char* head = current_; 143 if (!Consume(c)) { 144 current_ = head; 145 return false; 146 } 147 148 return true; 149 } 150 151 } // namespace net 152