xref: /aosp_15_r20/external/cronet/net/websockets/websocket_deflate_parameters.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2015 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "net/websockets/websocket_deflate_parameters.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <vector>  // for iterating over extension.parameters()
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
10*6777b538SAndroid Build Coastguard Worker 
11*6777b538SAndroid Build Coastguard Worker namespace net {
12*6777b538SAndroid Build Coastguard Worker 
13*6777b538SAndroid Build Coastguard Worker namespace {
14*6777b538SAndroid Build Coastguard Worker 
15*6777b538SAndroid Build Coastguard Worker const WebSocketDeflater::ContextTakeOverMode kTakeOverContext =
16*6777b538SAndroid Build Coastguard Worker     WebSocketDeflater::TAKE_OVER_CONTEXT;
17*6777b538SAndroid Build Coastguard Worker const WebSocketDeflater::ContextTakeOverMode kDoNotTakeOverContext =
18*6777b538SAndroid Build Coastguard Worker     WebSocketDeflater::DO_NOT_TAKE_OVER_CONTEXT;
19*6777b538SAndroid Build Coastguard Worker 
20*6777b538SAndroid Build Coastguard Worker constexpr char kServerNoContextTakeOver[] = "server_no_context_takeover";
21*6777b538SAndroid Build Coastguard Worker constexpr char kClientNoContextTakeOver[] = "client_no_context_takeover";
22*6777b538SAndroid Build Coastguard Worker constexpr char kServerMaxWindowBits[] = "server_max_window_bits";
23*6777b538SAndroid Build Coastguard Worker constexpr char kClientMaxWindowBits[] = "client_max_window_bits";
24*6777b538SAndroid Build Coastguard Worker constexpr char kExtensionName[] = "permessage-deflate";
25*6777b538SAndroid Build Coastguard Worker 
GetWindowBits(const std::string & value,int * window_bits)26*6777b538SAndroid Build Coastguard Worker bool GetWindowBits(const std::string& value, int* window_bits) {
27*6777b538SAndroid Build Coastguard Worker   return !value.empty() && value[0] != '0' &&
28*6777b538SAndroid Build Coastguard Worker          value.find_first_not_of("0123456789") == std::string::npos &&
29*6777b538SAndroid Build Coastguard Worker          base::StringToInt(value, window_bits);
30*6777b538SAndroid Build Coastguard Worker }
31*6777b538SAndroid Build Coastguard Worker 
DuplicateError(const std::string & name,std::string * failure_message)32*6777b538SAndroid Build Coastguard Worker bool DuplicateError(const std::string& name, std::string* failure_message) {
33*6777b538SAndroid Build Coastguard Worker   *failure_message =
34*6777b538SAndroid Build Coastguard Worker       "Received duplicate permessage-deflate extension parameter " + name;
35*6777b538SAndroid Build Coastguard Worker   return false;
36*6777b538SAndroid Build Coastguard Worker }
37*6777b538SAndroid Build Coastguard Worker 
InvalidError(const std::string & name,std::string * failure_message)38*6777b538SAndroid Build Coastguard Worker bool InvalidError(const std::string& name, std::string* failure_message) {
39*6777b538SAndroid Build Coastguard Worker   *failure_message = "Received invalid " + name + " parameter";
40*6777b538SAndroid Build Coastguard Worker   return false;
41*6777b538SAndroid Build Coastguard Worker }
42*6777b538SAndroid Build Coastguard Worker 
43*6777b538SAndroid Build Coastguard Worker }  // namespace
44*6777b538SAndroid Build Coastguard Worker 
AsExtension() const45*6777b538SAndroid Build Coastguard Worker WebSocketExtension WebSocketDeflateParameters::AsExtension() const {
46*6777b538SAndroid Build Coastguard Worker   WebSocketExtension e(kExtensionName);
47*6777b538SAndroid Build Coastguard Worker 
48*6777b538SAndroid Build Coastguard Worker   if (server_context_take_over_mode_ == kDoNotTakeOverContext)
49*6777b538SAndroid Build Coastguard Worker     e.Add(WebSocketExtension::Parameter(kServerNoContextTakeOver));
50*6777b538SAndroid Build Coastguard Worker   if (client_context_take_over_mode_ == kDoNotTakeOverContext)
51*6777b538SAndroid Build Coastguard Worker     e.Add(WebSocketExtension::Parameter(kClientNoContextTakeOver));
52*6777b538SAndroid Build Coastguard Worker   if (is_server_max_window_bits_specified()) {
53*6777b538SAndroid Build Coastguard Worker     DCHECK(server_max_window_bits_.has_value);
54*6777b538SAndroid Build Coastguard Worker     e.Add(WebSocketExtension::Parameter(
55*6777b538SAndroid Build Coastguard Worker         kServerMaxWindowBits, base::NumberToString(server_max_window_bits())));
56*6777b538SAndroid Build Coastguard Worker   }
57*6777b538SAndroid Build Coastguard Worker   if (is_client_max_window_bits_specified()) {
58*6777b538SAndroid Build Coastguard Worker     if (has_client_max_window_bits_value()) {
59*6777b538SAndroid Build Coastguard Worker       e.Add(WebSocketExtension::Parameter(
60*6777b538SAndroid Build Coastguard Worker           kClientMaxWindowBits,
61*6777b538SAndroid Build Coastguard Worker           base::NumberToString(client_max_window_bits())));
62*6777b538SAndroid Build Coastguard Worker     } else {
63*6777b538SAndroid Build Coastguard Worker       e.Add(WebSocketExtension::Parameter(kClientMaxWindowBits));
64*6777b538SAndroid Build Coastguard Worker     }
65*6777b538SAndroid Build Coastguard Worker   }
66*6777b538SAndroid Build Coastguard Worker 
67*6777b538SAndroid Build Coastguard Worker   return e;
68*6777b538SAndroid Build Coastguard Worker }
69*6777b538SAndroid Build Coastguard Worker 
IsValidAsRequest(std::string *) const70*6777b538SAndroid Build Coastguard Worker bool WebSocketDeflateParameters::IsValidAsRequest(std::string*) const {
71*6777b538SAndroid Build Coastguard Worker   if (server_max_window_bits_.is_specified) {
72*6777b538SAndroid Build Coastguard Worker     DCHECK(server_max_window_bits_.has_value);
73*6777b538SAndroid Build Coastguard Worker     DCHECK(IsValidWindowBits(server_max_window_bits_.bits));
74*6777b538SAndroid Build Coastguard Worker   }
75*6777b538SAndroid Build Coastguard Worker   if (client_max_window_bits_.is_specified &&
76*6777b538SAndroid Build Coastguard Worker       client_max_window_bits_.has_value) {
77*6777b538SAndroid Build Coastguard Worker     DCHECK(IsValidWindowBits(client_max_window_bits_.bits));
78*6777b538SAndroid Build Coastguard Worker   }
79*6777b538SAndroid Build Coastguard Worker   return true;
80*6777b538SAndroid Build Coastguard Worker }
81*6777b538SAndroid Build Coastguard Worker 
IsValidAsResponse(std::string * failure_message) const82*6777b538SAndroid Build Coastguard Worker bool WebSocketDeflateParameters::IsValidAsResponse(
83*6777b538SAndroid Build Coastguard Worker     std::string* failure_message) const {
84*6777b538SAndroid Build Coastguard Worker   if (server_max_window_bits_.is_specified) {
85*6777b538SAndroid Build Coastguard Worker     DCHECK(server_max_window_bits_.has_value);
86*6777b538SAndroid Build Coastguard Worker     DCHECK(IsValidWindowBits(server_max_window_bits_.bits));
87*6777b538SAndroid Build Coastguard Worker   }
88*6777b538SAndroid Build Coastguard Worker   if (client_max_window_bits_.is_specified) {
89*6777b538SAndroid Build Coastguard Worker     if (!client_max_window_bits_.has_value) {
90*6777b538SAndroid Build Coastguard Worker       *failure_message = "client_max_window_bits must have value";
91*6777b538SAndroid Build Coastguard Worker       return false;
92*6777b538SAndroid Build Coastguard Worker     }
93*6777b538SAndroid Build Coastguard Worker     DCHECK(IsValidWindowBits(client_max_window_bits_.bits));
94*6777b538SAndroid Build Coastguard Worker   }
95*6777b538SAndroid Build Coastguard Worker 
96*6777b538SAndroid Build Coastguard Worker   return true;
97*6777b538SAndroid Build Coastguard Worker }
98*6777b538SAndroid Build Coastguard Worker 
Initialize(const WebSocketExtension & extension,std::string * failure_message)99*6777b538SAndroid Build Coastguard Worker bool WebSocketDeflateParameters::Initialize(const WebSocketExtension& extension,
100*6777b538SAndroid Build Coastguard Worker                                             std::string* failure_message) {
101*6777b538SAndroid Build Coastguard Worker   *this = WebSocketDeflateParameters();
102*6777b538SAndroid Build Coastguard Worker 
103*6777b538SAndroid Build Coastguard Worker   if (extension.name() != kExtensionName) {
104*6777b538SAndroid Build Coastguard Worker     *failure_message = "extension name doesn't match";
105*6777b538SAndroid Build Coastguard Worker     return false;
106*6777b538SAndroid Build Coastguard Worker   }
107*6777b538SAndroid Build Coastguard Worker   for (const auto& p : extension.parameters()) {
108*6777b538SAndroid Build Coastguard Worker     if (p.name() == kServerNoContextTakeOver) {
109*6777b538SAndroid Build Coastguard Worker       if (server_context_take_over_mode() == kDoNotTakeOverContext)
110*6777b538SAndroid Build Coastguard Worker         return DuplicateError(p.name(), failure_message);
111*6777b538SAndroid Build Coastguard Worker       if (p.HasValue())
112*6777b538SAndroid Build Coastguard Worker         return InvalidError(p.name(), failure_message);
113*6777b538SAndroid Build Coastguard Worker       SetServerNoContextTakeOver();
114*6777b538SAndroid Build Coastguard Worker     } else if (p.name() == kClientNoContextTakeOver) {
115*6777b538SAndroid Build Coastguard Worker       if (client_context_take_over_mode() == kDoNotTakeOverContext)
116*6777b538SAndroid Build Coastguard Worker         return DuplicateError(p.name(), failure_message);
117*6777b538SAndroid Build Coastguard Worker       if (p.HasValue())
118*6777b538SAndroid Build Coastguard Worker         return InvalidError(p.name(), failure_message);
119*6777b538SAndroid Build Coastguard Worker       SetClientNoContextTakeOver();
120*6777b538SAndroid Build Coastguard Worker     } else if (p.name() == kServerMaxWindowBits) {
121*6777b538SAndroid Build Coastguard Worker       if (server_max_window_bits_.is_specified)
122*6777b538SAndroid Build Coastguard Worker         return DuplicateError(p.name(), failure_message);
123*6777b538SAndroid Build Coastguard Worker       int bits;
124*6777b538SAndroid Build Coastguard Worker       if (!GetWindowBits(p.value(), &bits) || !IsValidWindowBits(bits))
125*6777b538SAndroid Build Coastguard Worker         return InvalidError(p.name(), failure_message);
126*6777b538SAndroid Build Coastguard Worker       SetServerMaxWindowBits(bits);
127*6777b538SAndroid Build Coastguard Worker     } else if (p.name() == kClientMaxWindowBits) {
128*6777b538SAndroid Build Coastguard Worker       if (client_max_window_bits_.is_specified)
129*6777b538SAndroid Build Coastguard Worker         return DuplicateError(p.name(), failure_message);
130*6777b538SAndroid Build Coastguard Worker       if (p.value().empty()) {
131*6777b538SAndroid Build Coastguard Worker         SetClientMaxWindowBits();
132*6777b538SAndroid Build Coastguard Worker       } else {
133*6777b538SAndroid Build Coastguard Worker         int bits;
134*6777b538SAndroid Build Coastguard Worker         if (!GetWindowBits(p.value(), &bits) || !IsValidWindowBits(bits))
135*6777b538SAndroid Build Coastguard Worker           return InvalidError(p.name(), failure_message);
136*6777b538SAndroid Build Coastguard Worker         SetClientMaxWindowBits(bits);
137*6777b538SAndroid Build Coastguard Worker       }
138*6777b538SAndroid Build Coastguard Worker     } else {
139*6777b538SAndroid Build Coastguard Worker       *failure_message =
140*6777b538SAndroid Build Coastguard Worker           "Received an unexpected permessage-deflate extension parameter";
141*6777b538SAndroid Build Coastguard Worker       return false;
142*6777b538SAndroid Build Coastguard Worker     }
143*6777b538SAndroid Build Coastguard Worker   }
144*6777b538SAndroid Build Coastguard Worker   return true;
145*6777b538SAndroid Build Coastguard Worker }
146*6777b538SAndroid Build Coastguard Worker 
IsCompatibleWith(const WebSocketDeflateParameters & response) const147*6777b538SAndroid Build Coastguard Worker bool WebSocketDeflateParameters::IsCompatibleWith(
148*6777b538SAndroid Build Coastguard Worker     const WebSocketDeflateParameters& response) const {
149*6777b538SAndroid Build Coastguard Worker   const auto& request = *this;
150*6777b538SAndroid Build Coastguard Worker   DCHECK(request.IsValidAsRequest());
151*6777b538SAndroid Build Coastguard Worker   DCHECK(response.IsValidAsResponse());
152*6777b538SAndroid Build Coastguard Worker 
153*6777b538SAndroid Build Coastguard Worker   // server_no_context_take_over
154*6777b538SAndroid Build Coastguard Worker   if (request.server_context_take_over_mode() == kDoNotTakeOverContext &&
155*6777b538SAndroid Build Coastguard Worker       response.server_context_take_over_mode() == kTakeOverContext) {
156*6777b538SAndroid Build Coastguard Worker     return false;
157*6777b538SAndroid Build Coastguard Worker   }
158*6777b538SAndroid Build Coastguard Worker 
159*6777b538SAndroid Build Coastguard Worker   // No compatibility check is needed for client_no_context_take_over
160*6777b538SAndroid Build Coastguard Worker 
161*6777b538SAndroid Build Coastguard Worker   // server_max_window_bits
162*6777b538SAndroid Build Coastguard Worker   if (request.server_max_window_bits_.is_specified) {
163*6777b538SAndroid Build Coastguard Worker     DCHECK(request.server_max_window_bits_.has_value);
164*6777b538SAndroid Build Coastguard Worker     if (!response.server_max_window_bits_.is_specified)
165*6777b538SAndroid Build Coastguard Worker       return false;
166*6777b538SAndroid Build Coastguard Worker     DCHECK(response.server_max_window_bits_.has_value);
167*6777b538SAndroid Build Coastguard Worker     if (request.server_max_window_bits_.bits <
168*6777b538SAndroid Build Coastguard Worker         response.server_max_window_bits_.bits) {
169*6777b538SAndroid Build Coastguard Worker       return false;
170*6777b538SAndroid Build Coastguard Worker     }
171*6777b538SAndroid Build Coastguard Worker   }
172*6777b538SAndroid Build Coastguard Worker 
173*6777b538SAndroid Build Coastguard Worker   // client_max_window_bits
174*6777b538SAndroid Build Coastguard Worker   if (!request.client_max_window_bits_.is_specified &&
175*6777b538SAndroid Build Coastguard Worker       response.client_max_window_bits_.is_specified) {
176*6777b538SAndroid Build Coastguard Worker     return false;
177*6777b538SAndroid Build Coastguard Worker   }
178*6777b538SAndroid Build Coastguard Worker 
179*6777b538SAndroid Build Coastguard Worker   return true;
180*6777b538SAndroid Build Coastguard Worker }
181*6777b538SAndroid Build Coastguard Worker 
182*6777b538SAndroid Build Coastguard Worker }  // namespace net
183