Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / websockets / websocket_deflate_parameters.cc
blobee448a7f8c8224ba56645f8928c3fbc43a0a9de1
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"
9 namespace net {
11 namespace {
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) {
31 *failure_message =
32 "Received duplicate permessage-deflate extension parameter " + name;
33 return false;
36 bool InvalidError(const std::string& name, std::string* failure_message) {
37 *failure_message = "Received invalid " + name + " parameter";
38 return false;
41 } // namespace
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())));
59 } else {
60 e.Add(WebSocketExtension::Parameter(kClientMaxWindowBits));
64 return e;
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));
76 return true;
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";
88 return false;
90 DCHECK(IsValidWindowBits(client_max_window_bits_.bits));
93 return true;
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";
102 return false;
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);
108 if (p.HasValue())
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);
114 if (p.HasValue())
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);
120 int bits;
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();
129 } else {
130 int bits;
131 if (!GetWindowBits(p.value(), &bits) || !IsValidWindowBits(bits))
132 return InvalidError(p.name(), failure_message);
133 SetClientMaxWindowBits(bits);
135 } else {
136 *failure_message =
137 "Received an unexpected permessage-deflate extension parameter";
138 return false;
141 return true;
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) {
153 return false;
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)
162 return false;
163 DCHECK(response.server_max_window_bits_.has_value);
164 if (request.server_max_window_bits_.bits <
165 response.server_max_window_bits_.bits) {
166 return false;
170 // client_max_window_bits
171 if (!request.client_max_window_bits_.is_specified &&
172 response.client_max_window_bits_.is_specified) {
173 return false;
176 return true;
179 } // namespace net