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