mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-12-01 01:36:09 +03:00
180 lines
6.1 KiB
C++
180 lines
6.1 KiB
C++
|
// 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 WebSocketDeflater::ContextTakeOverMode kTakeOverContext =
|
||
|
WebSocketDeflater::TAKE_OVER_CONTEXT;
|
||
|
const WebSocketDeflater::ContextTakeOverMode kDoNotTakeOverContext =
|
||
|
WebSocketDeflater::DO_NOT_TAKE_OVER_CONTEXT;
|
||
|
|
||
|
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_ == kDoNotTakeOverContext)
|
||
|
e.Add(WebSocketExtension::Parameter(kServerNoContextTakeOver));
|
||
|
if (client_context_take_over_mode_ == kDoNotTakeOverContext)
|
||
|
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() == kDoNotTakeOverContext)
|
||
|
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() == kDoNotTakeOverContext)
|
||
|
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() == kDoNotTakeOverContext &&
|
||
|
response.server_context_take_over_mode() == kTakeOverContext) {
|
||
|
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 &&
|
||
|
response.client_max_window_bits_.is_specified) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
} // namespace net
|