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