| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/server/web_socket_encoder.h" | 5 #include "net/server/web_socket_encoder.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/strings/string_number_conversions.h" | 8 #include "base/strings/string_number_conversions.h" |
| 9 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
| 10 #include "net/base/io_buffer.h" | 10 #include "net/base/io_buffer.h" |
| 11 #include "net/websockets/websocket_deflate_parameters.h" |
| 12 #include "net/websockets/websocket_extension.h" |
| 11 #include "net/websockets/websocket_extension_parser.h" | 13 #include "net/websockets/websocket_extension_parser.h" |
| 12 | 14 |
| 13 namespace net { | 15 namespace net { |
| 14 | 16 |
| 15 const char WebSocketEncoder::kClientExtensions[] = | 17 const char WebSocketEncoder::kClientExtensions[] = |
| 16 "Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits"; | 18 "Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits"; |
| 17 | 19 |
| 18 namespace { | 20 namespace { |
| 19 | 21 |
| 20 const int kInflaterChunkSize = 16 * 1024; | 22 const int kInflaterChunkSize = 16 * 1024; |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 173 frame.push_back(data[i] ^ mask_bytes[i % kMaskingKeyWidthInBytes]); | 175 frame.push_back(data[i] ^ mask_bytes[i % kMaskingKeyWidthInBytes]); |
| 174 } else { | 176 } else { |
| 175 frame.insert(frame.end(), data, data + data_length); | 177 frame.insert(frame.end(), data, data + data_length); |
| 176 } | 178 } |
| 177 *output = std::string(&frame[0], frame.size()); | 179 *output = std::string(&frame[0], frame.size()); |
| 178 } | 180 } |
| 179 | 181 |
| 180 } // anonymous namespace | 182 } // anonymous namespace |
| 181 | 183 |
| 182 // static | 184 // static |
| 183 WebSocketEncoder* WebSocketEncoder::CreateServer( | 185 scoped_ptr<WebSocketEncoder> WebSocketEncoder::CreateServer() { |
| 186 return make_scoped_ptr(new WebSocketEncoder(AsServer())); |
| 187 } |
| 188 |
| 189 // static |
| 190 scoped_ptr<WebSocketEncoder> WebSocketEncoder::CreateServer( |
| 184 const std::string& request_extensions, | 191 const std::string& request_extensions, |
| 185 std::string* response_extensions) { | 192 WebSocketDeflateParameters* deflate_parameters, |
| 186 bool deflate; | 193 std::string* failure_message) { |
| 187 bool has_client_window_bits; | 194 WebSocketExtensionParser parser; |
| 188 int client_window_bits; | 195 if (!parser.Parse(request_extensions)) { |
| 189 int server_window_bits; | 196 *failure_message = "Failed to parse extensions header."; |
| 190 bool client_no_context_takeover; | 197 return nullptr; |
| 191 bool server_no_context_takeover; | 198 } |
| 192 ParseExtensions(request_extensions, &deflate, &has_client_window_bits, | |
| 193 &client_window_bits, &server_window_bits, | |
| 194 &client_no_context_takeover, &server_no_context_takeover); | |
| 195 | 199 |
| 196 if (deflate) { | 200 WebSocketDeflateParameters offered, response; |
| 197 *response_extensions = base::StringPrintf( | 201 for (size_t i = 0; i < parser.extensions().size(); ++i) { |
| 198 "permessage-deflate; server_max_window_bits=%d%s", server_window_bits, | 202 const auto& extension = parser.extensions()[i]; |
| 199 server_no_context_takeover ? "; server_no_context_takeover" : ""); | 203 // We only support "permessage-deflate" extension. |
| 200 if (has_client_window_bits) { | 204 WebSocketDeflateParameters params; |
| 201 base::StringAppendF(response_extensions, "; client_max_window_bits=%d", | 205 if (!params.Initialize(extension, failure_message) || |
| 202 client_window_bits); | 206 !params.IsValidAsRequest(failure_message)) { |
| 203 } else { | 207 return nullptr; |
| 204 DCHECK_EQ(client_window_bits, 15); | |
| 205 } | 208 } |
| 206 return new WebSocketEncoder(true /* is_server */, server_window_bits, | 209 if (i == 0) { |
| 207 client_window_bits, server_no_context_takeover); | 210 // We choose the first parameters blindly. |
| 208 } else { | 211 offered = params; |
| 209 *response_extensions = std::string(); | 212 } |
| 210 return new WebSocketEncoder(true /* is_server */); | |
| 211 } | 213 } |
| 214 response = offered; |
| 215 if (offered.is_client_max_window_bits_specified() && |
| 216 !offered.has_client_max_window_bits_value()) { |
| 217 // We need to choose one value for the response. |
| 218 response.SetClientMaxWindowBits(8); |
| 219 } |
| 220 DCHECK(response.IsValidAsResponse()); |
| 221 DCHECK(offered.IsCompatibleWith(response)); |
| 222 |
| 223 auto encoder = make_scoped_ptr(new WebSocketEncoder(AsServer(), response)); |
| 224 if (encoder->has_error_) { |
| 225 // Failed to initialize deflater or inflater. |
| 226 *failure_message = "Internal error."; |
| 227 return nullptr; |
| 228 } |
| 229 *deflate_parameters = response; |
| 230 return encoder.Pass(); |
| 212 } | 231 } |
| 213 | 232 |
| 214 // static | 233 // static |
| 215 WebSocketEncoder* WebSocketEncoder::CreateClient( | 234 WebSocketEncoder* WebSocketEncoder::CreateClient( |
| 216 const std::string& response_extensions) { | 235 const std::string& response_extensions) { |
| 217 bool deflate; | 236 // TODO(yhirano): Add a way to return an error. |
| 218 bool has_client_window_bits; | |
| 219 int client_window_bits; | |
| 220 int server_window_bits; | |
| 221 bool client_no_context_takeover; | |
| 222 bool server_no_context_takeover; | |
| 223 ParseExtensions(response_extensions, &deflate, &has_client_window_bits, | |
| 224 &client_window_bits, &server_window_bits, | |
| 225 &client_no_context_takeover, &server_no_context_takeover); | |
| 226 | 237 |
| 227 if (deflate) { | 238 WebSocketExtensionParser parser; |
| 228 return new WebSocketEncoder(false /* is_server */, client_window_bits, | 239 if (!parser.Parse(response_extensions)) { |
| 229 server_window_bits, client_no_context_takeover); | 240 // Parse error. |
| 230 } else { | 241 return new WebSocketEncoder(AsClient()); |
| 231 return new WebSocketEncoder(false /* is_server */); | |
| 232 } | 242 } |
| 243 if (parser.extensions().size() != 1) { |
| 244 // Only permessage-deflate extension is supported. |
| 245 return new WebSocketEncoder(AsClient()); |
| 246 } |
| 247 const auto& extension = parser.extensions()[0]; |
| 248 WebSocketDeflateParameters params; |
| 249 std::string failure_message; |
| 250 if (!params.Initialize(extension, &failure_message) || |
| 251 !params.IsValidAsResponse(&failure_message)) { |
| 252 // Failed to parse params. |
| 253 return new WebSocketEncoder(AsClient()); |
| 254 } |
| 255 |
| 256 scoped_ptr<WebSocketEncoder> encoder( |
| 257 new WebSocketEncoder(AsClient(), params)); |
| 258 if (encoder->has_error_) { |
| 259 // Failed to initialize deflater or inflater. |
| 260 return new WebSocketEncoder(AsClient()); |
| 261 } |
| 262 return encoder.release(); |
| 233 } | 263 } |
| 234 | 264 |
| 235 // static | 265 WebSocketEncoder::WebSocketEncoder(const AsServer&) |
| 236 void WebSocketEncoder::ParseExtensions(const std::string& header_value, | 266 : is_server_(true), has_error_(false) {} |
| 237 bool* deflate, | |
| 238 bool* has_client_window_bits, | |
| 239 int* client_window_bits, | |
| 240 int* server_window_bits, | |
| 241 bool* client_no_context_takeover, | |
| 242 bool* server_no_context_takeover) { | |
| 243 *deflate = false; | |
| 244 *has_client_window_bits = false; | |
| 245 *client_window_bits = 15; | |
| 246 *server_window_bits = 15; | |
| 247 *client_no_context_takeover = false; | |
| 248 *server_no_context_takeover = false; | |
| 249 | 267 |
| 250 if (header_value.empty()) | 268 WebSocketEncoder::WebSocketEncoder(const AsClient&) |
| 251 return; | 269 : is_server_(false), has_error_(false) {} |
| 252 | 270 |
| 253 WebSocketExtensionParser parser; | 271 WebSocketEncoder::WebSocketEncoder(const AsServer& server, |
| 254 if (!parser.Parse(header_value)) | 272 const WebSocketDeflateParameters& params) |
| 255 return; | 273 : is_server_(true), |
| 256 const std::vector<WebSocketExtension>& extensions = parser.extensions(); | 274 deflater_(new WebSocketDeflater(params.server_context_take_over_mode())), |
| 257 // TODO(tyoshino): Fail if this method is used for parsing a response and | 275 inflater_(new WebSocketInflater(kInflaterChunkSize, kInflaterChunkSize)) { |
| 258 // there are multiple permessage-deflate extensions or there are any unknown | 276 has_error_ = !deflater_->Initialize(params.PermissiveServerMaxWindowBits()) || |
| 259 // extensions. | 277 !inflater_->Initialize(params.PermissiveClientMaxWindowBits()); |
| 260 for (const auto& extension : extensions) { | |
| 261 if (extension.name() != "permessage-deflate") { | |
| 262 continue; | |
| 263 } | |
| 264 | |
| 265 const std::vector<WebSocketExtension::Parameter>& parameters = | |
| 266 extension.parameters(); | |
| 267 for (const auto& param : parameters) { | |
| 268 const std::string& name = param.name(); | |
| 269 // TODO(tyoshino): Fail the connection when an invalid value is given. | |
| 270 if (name == "client_max_window_bits") { | |
| 271 *has_client_window_bits = true; | |
| 272 if (param.HasValue()) { | |
| 273 int bits = 0; | |
| 274 if (base::StringToInt(param.value(), &bits) && bits >= 8 && | |
| 275 bits <= 15) { | |
| 276 *client_window_bits = bits; | |
| 277 } | |
| 278 } | |
| 279 } | |
| 280 if (name == "server_max_window_bits" && param.HasValue()) { | |
| 281 int bits = 0; | |
| 282 if (base::StringToInt(param.value(), &bits) && bits >= 8 && bits <= 15) | |
| 283 *server_window_bits = bits; | |
| 284 } | |
| 285 if (name == "client_no_context_takeover") | |
| 286 *client_no_context_takeover = true; | |
| 287 if (name == "server_no_context_takeover") | |
| 288 *server_no_context_takeover = true; | |
| 289 } | |
| 290 *deflate = true; | |
| 291 | |
| 292 break; | |
| 293 } | |
| 294 } | 278 } |
| 295 | 279 |
| 296 WebSocketEncoder::WebSocketEncoder(bool is_server) : is_server_(is_server) { | 280 WebSocketEncoder::WebSocketEncoder(const AsClient&, |
| 281 const WebSocketDeflateParameters& params) |
| 282 : is_server_(false), |
| 283 deflater_(new WebSocketDeflater(params.client_context_take_over_mode())), |
| 284 inflater_(new WebSocketInflater(kInflaterChunkSize, kInflaterChunkSize)) { |
| 285 has_error_ = !deflater_->Initialize(params.PermissiveClientMaxWindowBits()) || |
| 286 !inflater_->Initialize(params.PermissiveServerMaxWindowBits()); |
| 297 } | 287 } |
| 298 | 288 |
| 299 WebSocketEncoder::WebSocketEncoder(bool is_server, | 289 WebSocketEncoder::~WebSocketEncoder() {} |
| 300 int deflate_bits, | |
| 301 int inflate_bits, | |
| 302 bool no_context_takeover) | |
| 303 : is_server_(is_server) { | |
| 304 deflater_.reset(new WebSocketDeflater( | |
| 305 no_context_takeover ? WebSocketDeflater::DO_NOT_TAKE_OVER_CONTEXT | |
| 306 : WebSocketDeflater::TAKE_OVER_CONTEXT)); | |
| 307 inflater_.reset( | |
| 308 new WebSocketInflater(kInflaterChunkSize, kInflaterChunkSize)); | |
| 309 | |
| 310 if (!deflater_->Initialize(deflate_bits) || | |
| 311 !inflater_->Initialize(inflate_bits)) { | |
| 312 // Disable deflate support. | |
| 313 deflater_.reset(); | |
| 314 inflater_.reset(); | |
| 315 } | |
| 316 } | |
| 317 | |
| 318 WebSocketEncoder::~WebSocketEncoder() { | |
| 319 } | |
| 320 | 290 |
| 321 WebSocket::ParseResult WebSocketEncoder::DecodeFrame( | 291 WebSocket::ParseResult WebSocketEncoder::DecodeFrame( |
| 322 const base::StringPiece& frame, | 292 const base::StringPiece& frame, |
| 323 int* bytes_consumed, | 293 int* bytes_consumed, |
| 324 std::string* output) { | 294 std::string* output) { |
| 325 bool compressed; | 295 bool compressed; |
| 326 WebSocket::ParseResult result = | 296 WebSocket::ParseResult result = |
| 327 DecodeFrameHybi17(frame, is_server_, bytes_consumed, output, &compressed); | 297 DecodeFrameHybi17(frame, is_server_, bytes_consumed, output, &compressed); |
| 328 if (result == WebSocket::FRAME_OK && compressed) { | 298 if (result == WebSocket::FRAME_OK && compressed) { |
| 329 if (!Inflate(output)) | 299 if (!Inflate(output)) |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 376 return false; | 346 return false; |
| 377 scoped_refptr<IOBufferWithSize> buffer = | 347 scoped_refptr<IOBufferWithSize> buffer = |
| 378 deflater_->GetOutput(deflater_->CurrentOutputSize()); | 348 deflater_->GetOutput(deflater_->CurrentOutputSize()); |
| 379 if (!buffer.get()) | 349 if (!buffer.get()) |
| 380 return false; | 350 return false; |
| 381 *output = std::string(buffer->data(), buffer->size()); | 351 *output = std::string(buffer->data(), buffer->size()); |
| 382 return true; | 352 return true; |
| 383 } | 353 } |
| 384 | 354 |
| 385 } // namespace net | 355 } // namespace net |
| OLD | NEW |