• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)17 bool 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)42 bool 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)50 bool 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(&parameter))
59       return false;
60     extension->Add(parameter);
61   }
62 
63   return true;
64 }
65 
ConsumeExtensionParameter(WebSocketExtension::Parameter * parameter)66 bool 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)91 bool 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)102 bool 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()127 void WebSocketExtensionParser::ConsumeSpaces() {
128   while (current_ < end_ && (*current_ == ' ' || *current_ == '\t'))
129     ++current_;
130   return;
131 }
132 
Lookahead(char c)133 bool 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)140 bool 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