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()) || |
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 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 |