| Index: net/server/web_socket_encoder.cc
|
| diff --git a/net/server/web_socket_encoder.cc b/net/server/web_socket_encoder.cc
|
| index 1a5431affd8415a23e6ee6f3a553064d1447a803..5ce07e6c54bcfe6c5cdb10003bc49e41ac9151e3 100644
|
| --- a/net/server/web_socket_encoder.cc
|
| +++ b/net/server/web_socket_encoder.cc
|
| @@ -8,6 +8,8 @@
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/strings/stringprintf.h"
|
| #include "net/base/io_buffer.h"
|
| +#include "net/websockets/websocket_deflate_parameters.h"
|
| +#include "net/websockets/websocket_extension.h"
|
| #include "net/websockets/websocket_extension_parser.h"
|
|
|
| namespace net {
|
| @@ -180,144 +182,112 @@ void EncodeFrameHybi17(const std::string& message,
|
| } // anonymous namespace
|
|
|
| // static
|
| -WebSocketEncoder* WebSocketEncoder::CreateServer(
|
| +scoped_ptr<WebSocketEncoder> WebSocketEncoder::CreateServer() {
|
| + return make_scoped_ptr(new WebSocketEncoder(AsServer()));
|
| +}
|
| +
|
| +// static
|
| +scoped_ptr<WebSocketEncoder> WebSocketEncoder::CreateServer(
|
| const std::string& request_extensions,
|
| - std::string* response_extensions) {
|
| - bool deflate;
|
| - bool has_client_window_bits;
|
| - int client_window_bits;
|
| - int server_window_bits;
|
| - bool client_no_context_takeover;
|
| - bool server_no_context_takeover;
|
| - ParseExtensions(request_extensions, &deflate, &has_client_window_bits,
|
| - &client_window_bits, &server_window_bits,
|
| - &client_no_context_takeover, &server_no_context_takeover);
|
| -
|
| - if (deflate) {
|
| - *response_extensions = base::StringPrintf(
|
| - "permessage-deflate; server_max_window_bits=%d%s", server_window_bits,
|
| - server_no_context_takeover ? "; server_no_context_takeover" : "");
|
| - if (has_client_window_bits) {
|
| - base::StringAppendF(response_extensions, "; client_max_window_bits=%d",
|
| - client_window_bits);
|
| - } else {
|
| - DCHECK_EQ(client_window_bits, 15);
|
| + WebSocketDeflateParameters* deflate_parameters,
|
| + std::string* failure_message) {
|
| + WebSocketExtensionParser parser;
|
| + if (!parser.Parse(request_extensions)) {
|
| + *failure_message = "Failed to parse extensions header.";
|
| + return nullptr;
|
| + }
|
| +
|
| + WebSocketDeflateParameters offered, response;
|
| + for (size_t i = 0; i < parser.extensions().size(); ++i) {
|
| + const auto& extension = parser.extensions()[i];
|
| + // We only support "permessage-deflate" extension.
|
| + WebSocketDeflateParameters params;
|
| + if (!params.Initialize(extension, failure_message) ||
|
| + !params.IsValidAsRequest(failure_message)) {
|
| + return nullptr;
|
| }
|
| - return new WebSocketEncoder(true /* is_server */, server_window_bits,
|
| - client_window_bits, server_no_context_takeover);
|
| - } else {
|
| - *response_extensions = std::string();
|
| - return new WebSocketEncoder(true /* is_server */);
|
| + if (i == 0) {
|
| + // We choose the first parameters blindly.
|
| + offered = params;
|
| + }
|
| + }
|
| + response = offered;
|
| + if (offered.is_client_max_window_bits_specified() &&
|
| + !offered.has_client_max_window_bits_value()) {
|
| + // We need to choose one value for the response.
|
| + response.SetClientMaxWindowBits(8);
|
| + }
|
| + DCHECK(response.IsValidAsResponse());
|
| + DCHECK(offered.IsCompatibleWith(response));
|
| +
|
| + auto encoder = make_scoped_ptr(new WebSocketEncoder(AsServer(), response));
|
| + if (encoder->has_error_) {
|
| + // Failed to initialize deflater or inflater.
|
| + *failure_message = "Internal error.";
|
| + return nullptr;
|
| }
|
| + *deflate_parameters = response;
|
| + return encoder.Pass();
|
| }
|
|
|
| // static
|
| WebSocketEncoder* WebSocketEncoder::CreateClient(
|
| const std::string& response_extensions) {
|
| - bool deflate;
|
| - bool has_client_window_bits;
|
| - int client_window_bits;
|
| - int server_window_bits;
|
| - bool client_no_context_takeover;
|
| - bool server_no_context_takeover;
|
| - ParseExtensions(response_extensions, &deflate, &has_client_window_bits,
|
| - &client_window_bits, &server_window_bits,
|
| - &client_no_context_takeover, &server_no_context_takeover);
|
| -
|
| - if (deflate) {
|
| - return new WebSocketEncoder(false /* is_server */, client_window_bits,
|
| - server_window_bits, client_no_context_takeover);
|
| - } else {
|
| - return new WebSocketEncoder(false /* is_server */);
|
| - }
|
| -}
|
| -
|
| -// static
|
| -void WebSocketEncoder::ParseExtensions(const std::string& header_value,
|
| - bool* deflate,
|
| - bool* has_client_window_bits,
|
| - int* client_window_bits,
|
| - int* server_window_bits,
|
| - bool* client_no_context_takeover,
|
| - bool* server_no_context_takeover) {
|
| - *deflate = false;
|
| - *has_client_window_bits = false;
|
| - *client_window_bits = 15;
|
| - *server_window_bits = 15;
|
| - *client_no_context_takeover = false;
|
| - *server_no_context_takeover = false;
|
| -
|
| - if (header_value.empty())
|
| - return;
|
| + // TODO(yhirano): Add a way to return an error.
|
|
|
| WebSocketExtensionParser parser;
|
| - if (!parser.Parse(header_value))
|
| - return;
|
| - const std::vector<WebSocketExtension>& extensions = parser.extensions();
|
| - // TODO(tyoshino): Fail if this method is used for parsing a response and
|
| - // there are multiple permessage-deflate extensions or there are any unknown
|
| - // extensions.
|
| - for (const auto& extension : extensions) {
|
| - if (extension.name() != "permessage-deflate") {
|
| - continue;
|
| - }
|
| -
|
| - const std::vector<WebSocketExtension::Parameter>& parameters =
|
| - extension.parameters();
|
| - for (const auto& param : parameters) {
|
| - const std::string& name = param.name();
|
| - // TODO(tyoshino): Fail the connection when an invalid value is given.
|
| - if (name == "client_max_window_bits") {
|
| - *has_client_window_bits = true;
|
| - if (param.HasValue()) {
|
| - int bits = 0;
|
| - if (base::StringToInt(param.value(), &bits) && bits >= 8 &&
|
| - bits <= 15) {
|
| - *client_window_bits = bits;
|
| - }
|
| - }
|
| - }
|
| - if (name == "server_max_window_bits" && param.HasValue()) {
|
| - int bits = 0;
|
| - if (base::StringToInt(param.value(), &bits) && bits >= 8 && bits <= 15)
|
| - *server_window_bits = bits;
|
| - }
|
| - if (name == "client_no_context_takeover")
|
| - *client_no_context_takeover = true;
|
| - if (name == "server_no_context_takeover")
|
| - *server_no_context_takeover = true;
|
| - }
|
| - *deflate = true;
|
| + if (!parser.Parse(response_extensions)) {
|
| + // Parse error.
|
| + return new WebSocketEncoder(AsClient());
|
| + }
|
| + if (parser.extensions().size() != 1) {
|
| + // Only permessage-deflate extension is supported.
|
| + return new WebSocketEncoder(AsClient());
|
| + }
|
| + const auto& extension = parser.extensions()[0];
|
| + WebSocketDeflateParameters params;
|
| + std::string failure_message;
|
| + if (!params.Initialize(extension, &failure_message) ||
|
| + !params.IsValidAsResponse(&failure_message)) {
|
| + // Failed to parse params.
|
| + return new WebSocketEncoder(AsClient());
|
| + }
|
|
|
| - break;
|
| + scoped_ptr<WebSocketEncoder> encoder(
|
| + new WebSocketEncoder(AsClient(), params));
|
| + if (encoder->has_error_) {
|
| + // Failed to initialize deflater or inflater.
|
| + return new WebSocketEncoder(AsClient());
|
| }
|
| + return encoder.release();
|
| }
|
|
|
| -WebSocketEncoder::WebSocketEncoder(bool is_server) : is_server_(is_server) {
|
| -}
|
| +WebSocketEncoder::WebSocketEncoder(const AsServer&)
|
| + : is_server_(true), has_error_(false) {}
|
|
|
| -WebSocketEncoder::WebSocketEncoder(bool is_server,
|
| - int deflate_bits,
|
| - int inflate_bits,
|
| - bool no_context_takeover)
|
| - : is_server_(is_server) {
|
| - deflater_.reset(new WebSocketDeflater(
|
| - no_context_takeover ? WebSocketDeflater::DO_NOT_TAKE_OVER_CONTEXT
|
| - : WebSocketDeflater::TAKE_OVER_CONTEXT));
|
| - inflater_.reset(
|
| - new WebSocketInflater(kInflaterChunkSize, kInflaterChunkSize));
|
| -
|
| - if (!deflater_->Initialize(deflate_bits) ||
|
| - !inflater_->Initialize(inflate_bits)) {
|
| - // Disable deflate support.
|
| - deflater_.reset();
|
| - inflater_.reset();
|
| - }
|
| +WebSocketEncoder::WebSocketEncoder(const AsClient&)
|
| + : is_server_(false), has_error_(false) {}
|
| +
|
| +WebSocketEncoder::WebSocketEncoder(const AsServer& server,
|
| + const WebSocketDeflateParameters& params)
|
| + : is_server_(true),
|
| + deflater_(new WebSocketDeflater(params.server_context_take_over_mode())),
|
| + inflater_(new WebSocketInflater(kInflaterChunkSize, kInflaterChunkSize)) {
|
| + has_error_ = !deflater_->Initialize(params.PermissiveServerMaxWindowBits()) ||
|
| + !inflater_->Initialize(params.PermissiveClientMaxWindowBits());
|
| }
|
|
|
| -WebSocketEncoder::~WebSocketEncoder() {
|
| +WebSocketEncoder::WebSocketEncoder(const AsClient&,
|
| + const WebSocketDeflateParameters& params)
|
| + : is_server_(false),
|
| + deflater_(new WebSocketDeflater(params.client_context_take_over_mode())),
|
| + inflater_(new WebSocketInflater(kInflaterChunkSize, kInflaterChunkSize)) {
|
| + has_error_ = !deflater_->Initialize(params.PermissiveClientMaxWindowBits()) ||
|
| + !inflater_->Initialize(params.PermissiveServerMaxWindowBits());
|
| }
|
|
|
| +WebSocketEncoder::~WebSocketEncoder() {}
|
| +
|
| WebSocket::ParseResult WebSocketEncoder::DecodeFrame(
|
| const base::StringPiece& frame,
|
| int* bytes_consumed,
|
|
|