• 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 #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)23 bool 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)48 bool 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)56 bool 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(&parameter))
65       return false;
66     extension->Add(parameter);
67   }
68 
69   return true;
70 }
71 
ConsumeExtensionParameter(WebSocketExtension::Parameter * parameter)72 bool 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)97 bool 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)108 bool 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()133 void WebSocketExtensionParser::ConsumeSpaces() {
134   while (current_ < end_ && (*current_ == ' ' || *current_ == '\t'))
135     ++current_;
136   return;
137 }
138 
Lookahead(char c)139 bool 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)146 bool 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