• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()11 WebSocketExtensionParser::WebSocketExtensionParser() {}
12 
~WebSocketExtensionParser()13 WebSocketExtensionParser::~WebSocketExtensionParser() {}
14 
Parse(const char * data,size_t size)15 void 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)26 void 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)37 void 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(&parameter);
47     if (has_error_) return;
48     extension->Add(parameter);
49   }
50 }
51 
ConsumeExtensionParameter(WebSocketExtension::Parameter * parameter)52 void 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)75 void 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)90 void 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()116 void WebSocketExtensionParser::ConsumeSpaces() {
117   DCHECK(!has_error_);
118   while (current_ < end_ && (current_[0] == ' ' || current_[0] == '\t'))
119     ++current_;
120   return;
121 }
122 
Lookahead(char c)123 bool 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)134 bool 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)148 bool WebSocketExtensionParser::IsControl(char c) {
149   return (0 <= c && c <= 31) || c == 127;
150 }
151 
152 // static
IsSeparator(char c)153 bool WebSocketExtensionParser::IsSeparator(char c) {
154   const char separators[] = "()<>@,;:\\\"/[]?={} \t";
155   return strchr(separators, c) != NULL;
156 }
157 
158 }  // namespace net
159