Chromium Code Reviews| Index: net/websockets/websocket_deflate_parameters.cc |
| diff --git a/net/websockets/websocket_deflate_parameters.cc b/net/websockets/websocket_deflate_parameters.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..b125de49c15572c6008a8986808eec2e927e7691 |
| --- /dev/null |
| +++ b/net/websockets/websocket_deflate_parameters.cc |
| @@ -0,0 +1,182 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "net/websockets/websocket_deflate_parameters.h" |
| + |
| +#include "base/strings/string_number_conversions.h" |
| + |
| +namespace net { |
| + |
| +namespace { |
| + |
| +const char kServerNoContextTakeOver[] = "server_no_context_takeover"; |
| +const char kClientNoContextTakeOver[] = "client_no_context_takeover"; |
| +const char kServerMaxWindowBits[] = "server_max_window_bits"; |
| +const char kClientMaxWindowBits[] = "client_max_window_bits"; |
| +const char kExtensionName[] = "permessage-deflate"; |
| + |
| +bool GetWindowBits(const std::string& value, int* window_bits) { |
| + return !value.empty() && value[0] != '0' && |
| + value.find_first_not_of("0123456789") == std::string::npos && |
| + base::StringToInt(value, window_bits); |
| +} |
| + |
| +bool DuplicateError(const std::string& name, std::string* failure_message) { |
| + *failure_message = |
| + "Received duplicate permessage-deflate extension parameter " + name; |
| + return false; |
| +} |
| + |
| +bool InvalidError(const std::string& name, std::string* failure_message) { |
| + *failure_message = "Received invalid " + name + " parameter"; |
| + return false; |
| +} |
| + |
| +} // namespace |
| + |
| +WebSocketExtension WebSocketDeflateParameters::AsExtension() const { |
| + WebSocketExtension e(kExtensionName); |
| + |
| + if (server_context_take_over_mode_ == DO_NOT_TAKE_OVER_CONTEXT) |
| + e.Add(WebSocketExtension::Parameter(kServerNoContextTakeOver)); |
| + if (client_context_take_over_mode_ == DO_NOT_TAKE_OVER_CONTEXT) |
| + e.Add(WebSocketExtension::Parameter(kClientNoContextTakeOver)); |
| + if (is_server_max_window_bits_specified()) { |
| + DCHECK(server_max_window_bits_.has_value); |
| + e.Add(WebSocketExtension::Parameter( |
| + kServerMaxWindowBits, base::IntToString(server_max_window_bits()))); |
| + } |
| + if (is_client_max_window_bits_specified()) { |
| + if (has_client_max_window_bits_value()) { |
| + e.Add(WebSocketExtension::Parameter( |
| + kClientMaxWindowBits, base::IntToString(client_max_window_bits()))); |
| + } else { |
| + e.Add(WebSocketExtension::Parameter(kClientMaxWindowBits)); |
| + } |
| + } |
| + |
| + return e; |
| +} |
| + |
| +bool WebSocketDeflateParameters::IsValidAsRequest(std::string*) const { |
| + if (server_max_window_bits_.is_specified) { |
| + DCHECK(server_max_window_bits_.has_value); |
| + DCHECK(IsValidWindowBits(server_max_window_bits_.bits)); |
| + } |
| + if (client_max_window_bits_.is_specified && |
| + client_max_window_bits_.has_value) { |
| + DCHECK(IsValidWindowBits(client_max_window_bits_.bits)); |
| + } |
| + return true; |
| +} |
| + |
| +bool WebSocketDeflateParameters::IsValidAsResponse( |
| + std::string* failure_message) const { |
| + if (server_max_window_bits_.is_specified) { |
| + DCHECK(server_max_window_bits_.has_value); |
| + DCHECK(IsValidWindowBits(server_max_window_bits_.bits)); |
| + } |
| + if (client_max_window_bits_.is_specified) { |
| + if (!client_max_window_bits_.has_value) { |
| + *failure_message = "client_max_window_bits must have value"; |
| + return false; |
| + } |
| + DCHECK(IsValidWindowBits(client_max_window_bits_.bits)); |
| + } |
| + |
| + return true; |
| +} |
| + |
| +bool WebSocketDeflateParameters::Initialize(const WebSocketExtension& extension, |
| + std::string* failure_message) { |
| + *this = WebSocketDeflateParameters(); |
| + |
| + if (extension.name() != kExtensionName) { |
| + *failure_message = "extension name doesn't match"; |
| + return false; |
| + } |
| + for (const auto& p : extension.parameters()) { |
| + if (p.name() == kServerNoContextTakeOver) { |
| + if (server_context_take_over_mode() == DO_NOT_TAKE_OVER_CONTEXT) |
| + return DuplicateError(p.name(), failure_message); |
| + if (p.HasValue()) |
| + return InvalidError(p.name(), failure_message); |
| + SetServerNoContextTakeOver(); |
| + } else if (p.name() == kClientNoContextTakeOver) { |
| + if (client_context_take_over_mode() == DO_NOT_TAKE_OVER_CONTEXT) |
| + return DuplicateError(p.name(), failure_message); |
| + if (p.HasValue()) |
| + return InvalidError(p.name(), failure_message); |
| + SetClientNoContextTakeOver(); |
| + } else if (p.name() == kServerMaxWindowBits) { |
| + if (server_max_window_bits_.is_specified) |
| + return DuplicateError(p.name(), failure_message); |
| + int bits; |
| + if (!GetWindowBits(p.value(), &bits) || !IsValidWindowBits(bits)) |
| + return InvalidError(p.name(), failure_message); |
| + SetServerMaxWindowBits(bits); |
| + } else if (p.name() == kClientMaxWindowBits) { |
| + if (client_max_window_bits_.is_specified) |
| + return DuplicateError(p.name(), failure_message); |
| + if (p.value().empty()) { |
| + SetClientMaxWindowBits(); |
| + } else { |
| + int bits; |
| + if (!GetWindowBits(p.value(), &bits) || !IsValidWindowBits(bits)) |
| + return InvalidError(p.name(), failure_message); |
| + SetClientMaxWindowBits(bits); |
| + } |
| + } else { |
| + *failure_message = |
| + "Received an unexpected permessage-deflate extension parameter"; |
| + return false; |
| + } |
| + } |
| + return true; |
| +} |
| + |
| +bool WebSocketDeflateParameters::IsCompatibleWith( |
| + const WebSocketDeflateParameters& response) const { |
| + const auto& request = *this; |
| + DCHECK(request.IsValidAsRequest()); |
| + DCHECK(response.IsValidAsResponse()); |
| + |
| + // server_no_context_take_over |
| + if (request.server_context_take_over_mode() == DO_NOT_TAKE_OVER_CONTEXT && |
| + response.server_context_take_over_mode() == TAKE_OVER_CONTEXT) { |
| + return false; |
| + } |
| + |
| + // No compatibility check is needed for client_no_context_take_over |
| + |
| + // server_max_window_bits |
| + if (request.server_max_window_bits_.is_specified) { |
| + DCHECK(request.server_max_window_bits_.has_value); |
| + if (!response.server_max_window_bits_.is_specified) |
| + return false; |
| + DCHECK(response.server_max_window_bits_.has_value); |
| + if (request.server_max_window_bits_.bits < |
| + response.server_max_window_bits_.bits) { |
| + return false; |
| + } |
| + } |
| + |
| + // client_max_window_bits |
| + if (request.client_max_window_bits_.is_specified) { |
| + if (request.client_max_window_bits_.has_value && |
| + response.client_max_window_bits_.is_specified) { |
| + DCHECK(response.client_max_window_bits_.has_value); |
| + if (request.client_max_window_bits_.bits < |
| + response.client_max_window_bits_.bits) { |
| + return false; |
| + } |
| + } |
|
tyoshino (SeeGerritForStatus)
2015/09/10 09:06:19
L166-174 are unnecessary. The value part of the cl
yhirano
2015/09/10 11:20:13
Done.
|
| + } else if (response.client_max_window_bits_.is_specified) { |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +} // namespace net |