Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1070)

Side by Side Diff: net/server/web_socket_encoder.cc

Issue 1340523002: Fix WebSocketServer extension parser. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@ws-constructor-fix
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/server/web_socket_encoder.h ('k') | net/server/web_socket_encoder_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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()) ||
dgozman 2015/09/11 17:49:36 Why don't you just pass |is_server|, |inflater| an
yhirano 2015/09/15 06:25:57 Done. I generally don't like |true /* is_server */
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
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
OLDNEW
« no previous file with comments | « net/server/web_socket_encoder.h ('k') | net/server/web_socket_encoder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698