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