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