1 // Copyright 2013 The Chromium Authors. All rights reserved. 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/strings/string_util.h" 8 9 namespace net { 10 WebSocketExtensionParser()11WebSocketExtensionParser::WebSocketExtensionParser() {} 12 ~WebSocketExtensionParser()13WebSocketExtensionParser::~WebSocketExtensionParser() {} 14 Parse(const char * data,size_t size)15void WebSocketExtensionParser::Parse(const char* data, size_t size) { 16 current_ = data; 17 end_ = data + size; 18 has_error_ = false; 19 20 ConsumeExtension(&extension_); 21 if (has_error_) return; 22 ConsumeSpaces(); 23 has_error_ = has_error_ || (current_ != end_); 24 } 25 Consume(char c)26void WebSocketExtensionParser::Consume(char c) { 27 DCHECK(!has_error_); 28 ConsumeSpaces(); 29 DCHECK(!has_error_); 30 if (current_ == end_ || c != current_[0]) { 31 has_error_ = true; 32 return; 33 } 34 ++current_; 35 } 36 ConsumeExtension(WebSocketExtension * extension)37void WebSocketExtensionParser::ConsumeExtension(WebSocketExtension* extension) { 38 DCHECK(!has_error_); 39 base::StringPiece name; 40 ConsumeToken(&name); 41 if (has_error_) return; 42 *extension = WebSocketExtension(name.as_string()); 43 44 while (ConsumeIfMatch(';')) { 45 WebSocketExtension::Parameter parameter((std::string())); 46 ConsumeExtensionParameter(¶meter); 47 if (has_error_) return; 48 extension->Add(parameter); 49 } 50 } 51 ConsumeExtensionParameter(WebSocketExtension::Parameter * parameter)52void WebSocketExtensionParser::ConsumeExtensionParameter( 53 WebSocketExtension::Parameter* parameter) { 54 DCHECK(!has_error_); 55 base::StringPiece name, value; 56 std::string value_string; 57 58 ConsumeToken(&name); 59 if (has_error_) return; 60 if (!ConsumeIfMatch('=')) { 61 *parameter = WebSocketExtension::Parameter(name.as_string()); 62 return; 63 } 64 65 if (Lookahead('\"')) { 66 ConsumeQuotedToken(&value_string); 67 } else { 68 ConsumeToken(&value); 69 value_string = value.as_string(); 70 } 71 if (has_error_) return; 72 *parameter = WebSocketExtension::Parameter(name.as_string(), value_string); 73 } 74 ConsumeToken(base::StringPiece * token)75void WebSocketExtensionParser::ConsumeToken(base::StringPiece* token) { 76 DCHECK(!has_error_); 77 ConsumeSpaces(); 78 DCHECK(!has_error_); 79 const char* head = current_; 80 while (current_ < end_ && 81 !IsControl(current_[0]) && !IsSeparator(current_[0])) 82 ++current_; 83 if (current_ == head) { 84 has_error_ = true; 85 return; 86 } 87 *token = base::StringPiece(head, current_ - head); 88 } 89 ConsumeQuotedToken(std::string * token)90void WebSocketExtensionParser::ConsumeQuotedToken(std::string* token) { 91 DCHECK(!has_error_); 92 Consume('"'); 93 if (has_error_) return; 94 *token = ""; 95 while (current_ < end_ && !IsControl(current_[0])) { 96 if (UnconsumedBytes() >= 2 && current_[0] == '\\') { 97 char next = current_[1]; 98 if (IsControl(next) || IsSeparator(next)) break; 99 *token += next; 100 current_ += 2; 101 } else if (IsSeparator(current_[0])) { 102 break; 103 } else { 104 *token += current_[0]; 105 ++current_; 106 } 107 } 108 // We can't use Consume here because we don't want to consume spaces. 109 if (current_ < end_ && current_[0] == '"') 110 ++current_; 111 else 112 has_error_ = true; 113 has_error_ = has_error_ || token->empty(); 114 } 115 ConsumeSpaces()116void WebSocketExtensionParser::ConsumeSpaces() { 117 DCHECK(!has_error_); 118 while (current_ < end_ && (current_[0] == ' ' || current_[0] == '\t')) 119 ++current_; 120 return; 121 } 122 Lookahead(char c)123bool WebSocketExtensionParser::Lookahead(char c) { 124 DCHECK(!has_error_); 125 const char* head = current_; 126 127 Consume(c); 128 bool result = !has_error_; 129 current_ = head; 130 has_error_ = false; 131 return result; 132 } 133 ConsumeIfMatch(char c)134bool WebSocketExtensionParser::ConsumeIfMatch(char c) { 135 DCHECK(!has_error_); 136 const char* head = current_; 137 138 Consume(c); 139 if (has_error_) { 140 current_ = head; 141 has_error_ = false; 142 return false; 143 } 144 return true; 145 } 146 147 // static IsControl(char c)148bool WebSocketExtensionParser::IsControl(char c) { 149 return (0 <= c && c <= 31) || c == 127; 150 } 151 152 // static IsSeparator(char c)153bool WebSocketExtensionParser::IsSeparator(char c) { 154 const char separators[] = "()<>@,;:\\\"/[]?={} \t"; 155 return strchr(separators, c) != NULL; 156 } 157 158 } // namespace net 159