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