1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/websockets/websocket_deflate_parameters.h"
7 #include "base/strings/string_number_conversions.h"
13 const WebSocketDeflater::ContextTakeOverMode kTakeOverContext
=
14 WebSocketDeflater::TAKE_OVER_CONTEXT
;
15 const WebSocketDeflater::ContextTakeOverMode kDoNotTakeOverContext
=
16 WebSocketDeflater::DO_NOT_TAKE_OVER_CONTEXT
;
18 const char kServerNoContextTakeOver
[] = "server_no_context_takeover";
19 const char kClientNoContextTakeOver
[] = "client_no_context_takeover";
20 const char kServerMaxWindowBits
[] = "server_max_window_bits";
21 const char kClientMaxWindowBits
[] = "client_max_window_bits";
22 const char kExtensionName
[] = "permessage-deflate";
24 bool GetWindowBits(const std::string
& value
, int* window_bits
) {
25 return !value
.empty() && value
[0] != '0' &&
26 value
.find_first_not_of("0123456789") == std::string::npos
&&
27 base::StringToInt(value
, window_bits
);
30 bool DuplicateError(const std::string
& name
, std::string
* failure_message
) {
32 "Received duplicate permessage-deflate extension parameter " + name
;
36 bool InvalidError(const std::string
& name
, std::string
* failure_message
) {
37 *failure_message
= "Received invalid " + name
+ " parameter";
43 WebSocketExtension
WebSocketDeflateParameters::AsExtension() const {
44 WebSocketExtension
e(kExtensionName
);
46 if (server_context_take_over_mode_
== kDoNotTakeOverContext
)
47 e
.Add(WebSocketExtension::Parameter(kServerNoContextTakeOver
));
48 if (client_context_take_over_mode_
== kDoNotTakeOverContext
)
49 e
.Add(WebSocketExtension::Parameter(kClientNoContextTakeOver
));
50 if (is_server_max_window_bits_specified()) {
51 DCHECK(server_max_window_bits_
.has_value
);
52 e
.Add(WebSocketExtension::Parameter(
53 kServerMaxWindowBits
, base::IntToString(server_max_window_bits())));
55 if (is_client_max_window_bits_specified()) {
56 if (has_client_max_window_bits_value()) {
57 e
.Add(WebSocketExtension::Parameter(
58 kClientMaxWindowBits
, base::IntToString(client_max_window_bits())));
60 e
.Add(WebSocketExtension::Parameter(kClientMaxWindowBits
));
67 bool WebSocketDeflateParameters::IsValidAsRequest(std::string
*) const {
68 if (server_max_window_bits_
.is_specified
) {
69 DCHECK(server_max_window_bits_
.has_value
);
70 DCHECK(IsValidWindowBits(server_max_window_bits_
.bits
));
72 if (client_max_window_bits_
.is_specified
&&
73 client_max_window_bits_
.has_value
) {
74 DCHECK(IsValidWindowBits(client_max_window_bits_
.bits
));
79 bool WebSocketDeflateParameters::IsValidAsResponse(
80 std::string
* failure_message
) const {
81 if (server_max_window_bits_
.is_specified
) {
82 DCHECK(server_max_window_bits_
.has_value
);
83 DCHECK(IsValidWindowBits(server_max_window_bits_
.bits
));
85 if (client_max_window_bits_
.is_specified
) {
86 if (!client_max_window_bits_
.has_value
) {
87 *failure_message
= "client_max_window_bits must have value";
90 DCHECK(IsValidWindowBits(client_max_window_bits_
.bits
));
96 bool WebSocketDeflateParameters::Initialize(const WebSocketExtension
& extension
,
97 std::string
* failure_message
) {
98 *this = WebSocketDeflateParameters();
100 if (extension
.name() != kExtensionName
) {
101 *failure_message
= "extension name doesn't match";
104 for (const auto& p
: extension
.parameters()) {
105 if (p
.name() == kServerNoContextTakeOver
) {
106 if (server_context_take_over_mode() == kDoNotTakeOverContext
)
107 return DuplicateError(p
.name(), failure_message
);
109 return InvalidError(p
.name(), failure_message
);
110 SetServerNoContextTakeOver();
111 } else if (p
.name() == kClientNoContextTakeOver
) {
112 if (client_context_take_over_mode() == kDoNotTakeOverContext
)
113 return DuplicateError(p
.name(), failure_message
);
115 return InvalidError(p
.name(), failure_message
);
116 SetClientNoContextTakeOver();
117 } else if (p
.name() == kServerMaxWindowBits
) {
118 if (server_max_window_bits_
.is_specified
)
119 return DuplicateError(p
.name(), failure_message
);
121 if (!GetWindowBits(p
.value(), &bits
) || !IsValidWindowBits(bits
))
122 return InvalidError(p
.name(), failure_message
);
123 SetServerMaxWindowBits(bits
);
124 } else if (p
.name() == kClientMaxWindowBits
) {
125 if (client_max_window_bits_
.is_specified
)
126 return DuplicateError(p
.name(), failure_message
);
127 if (p
.value().empty()) {
128 SetClientMaxWindowBits();
131 if (!GetWindowBits(p
.value(), &bits
) || !IsValidWindowBits(bits
))
132 return InvalidError(p
.name(), failure_message
);
133 SetClientMaxWindowBits(bits
);
137 "Received an unexpected permessage-deflate extension parameter";
144 bool WebSocketDeflateParameters::IsCompatibleWith(
145 const WebSocketDeflateParameters
& response
) const {
146 const auto& request
= *this;
147 DCHECK(request
.IsValidAsRequest());
148 DCHECK(response
.IsValidAsResponse());
150 // server_no_context_take_over
151 if (request
.server_context_take_over_mode() == kDoNotTakeOverContext
&&
152 response
.server_context_take_over_mode() == kTakeOverContext
) {
156 // No compatibility check is needed for client_no_context_take_over
158 // server_max_window_bits
159 if (request
.server_max_window_bits_
.is_specified
) {
160 DCHECK(request
.server_max_window_bits_
.has_value
);
161 if (!response
.server_max_window_bits_
.is_specified
)
163 DCHECK(response
.server_max_window_bits_
.has_value
);
164 if (request
.server_max_window_bits_
.bits
<
165 response
.server_max_window_bits_
.bits
) {
170 // client_max_window_bits
171 if (!request
.client_max_window_bits_
.is_specified
&&
172 response
.client_max_window_bits_
.is_specified
) {