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 <vector> |
| 8 |
7 #include "base/logging.h" | 9 #include "base/logging.h" |
8 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
9 #include "base/strings/stringprintf.h" | 11 #include "base/strings/stringprintf.h" |
10 #include "net/base/io_buffer.h" | 12 #include "net/base/io_buffer.h" |
| 13 #include "net/websockets/websocket_deflate_parameters.h" |
| 14 #include "net/websockets/websocket_extension.h" |
11 #include "net/websockets/websocket_extension_parser.h" | 15 #include "net/websockets/websocket_extension_parser.h" |
12 | 16 |
13 namespace net { | 17 namespace net { |
14 | 18 |
15 const char WebSocketEncoder::kClientExtensions[] = | 19 const char WebSocketEncoder::kClientExtensions[] = |
16 "Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits"; | 20 "Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits"; |
17 | 21 |
18 namespace { | 22 namespace { |
19 | 23 |
20 const int kInflaterChunkSize = 16 * 1024; | 24 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]); | 177 frame.push_back(data[i] ^ mask_bytes[i % kMaskingKeyWidthInBytes]); |
174 } else { | 178 } else { |
175 frame.insert(frame.end(), data, data + data_length); | 179 frame.insert(frame.end(), data, data + data_length); |
176 } | 180 } |
177 *output = std::string(&frame[0], frame.size()); | 181 *output = std::string(&frame[0], frame.size()); |
178 } | 182 } |
179 | 183 |
180 } // anonymous namespace | 184 } // anonymous namespace |
181 | 185 |
182 // static | 186 // static |
183 WebSocketEncoder* WebSocketEncoder::CreateServer( | 187 scoped_ptr<WebSocketEncoder> WebSocketEncoder::CreateServer() { |
184 const std::string& request_extensions, | 188 return make_scoped_ptr(new WebSocketEncoder(FOR_SERVER, nullptr, nullptr)); |
185 std::string* response_extensions) { | 189 } |
186 bool deflate; | |
187 bool has_client_window_bits; | |
188 int client_window_bits; | |
189 int server_window_bits; | |
190 bool client_no_context_takeover; | |
191 bool server_no_context_takeover; | |
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 | 190 |
196 if (deflate) { | 191 // static |
197 *response_extensions = base::StringPrintf( | 192 scoped_ptr<WebSocketEncoder> WebSocketEncoder::CreateServer( |
198 "permessage-deflate; server_max_window_bits=%d%s", server_window_bits, | 193 const std::string& extensions, |
199 server_no_context_takeover ? "; server_no_context_takeover" : ""); | 194 WebSocketDeflateParameters* deflate_parameters) { |
200 if (has_client_window_bits) { | 195 WebSocketExtensionParser parser; |
201 base::StringAppendF(response_extensions, "; client_max_window_bits=%d", | 196 if (!parser.Parse(extensions)) { |
202 client_window_bits); | 197 // Failed to parse Sec-WebSocket-Extensions header. We MUST fail the |
203 } else { | 198 // connection. |
204 DCHECK_EQ(client_window_bits, 15); | 199 return nullptr; |
| 200 } |
| 201 |
| 202 for (const auto& extension : parser.extensions()) { |
| 203 std::string failure_message; |
| 204 WebSocketDeflateParameters offer; |
| 205 if (!offer.Initialize(extension, &failure_message) || |
| 206 !offer.IsValidAsRequest(&failure_message)) { |
| 207 // We decline unknown / malformed extensions. |
| 208 continue; |
205 } | 209 } |
206 return new WebSocketEncoder(true /* is_server */, server_window_bits, | 210 |
207 client_window_bits, server_no_context_takeover); | 211 WebSocketDeflateParameters response = offer; |
208 } else { | 212 if (offer.is_client_max_window_bits_specified() && |
209 *response_extensions = std::string(); | 213 !offer.has_client_max_window_bits_value()) { |
210 return new WebSocketEncoder(true /* is_server */); | 214 // We need to choose one value for the response. |
| 215 response.SetClientMaxWindowBits(15); |
| 216 } |
| 217 DCHECK(response.IsValidAsResponse()); |
| 218 DCHECK(offer.IsCompatibleWith(response)); |
| 219 auto deflater = make_scoped_ptr( |
| 220 new WebSocketDeflater(response.server_context_take_over_mode())); |
| 221 auto inflater = make_scoped_ptr( |
| 222 new WebSocketInflater(kInflaterChunkSize, kInflaterChunkSize)); |
| 223 if (!deflater->Initialize(response.PermissiveServerMaxWindowBits()) || |
| 224 !inflater->Initialize(response.PermissiveClientMaxWindowBits())) { |
| 225 // For some reason we cannot accept the parameters. |
| 226 continue; |
| 227 } |
| 228 *deflate_parameters = response; |
| 229 return make_scoped_ptr( |
| 230 new WebSocketEncoder(FOR_SERVER, deflater.Pass(), inflater.Pass())); |
211 } | 231 } |
| 232 |
| 233 // We cannot find an acceptable offer. |
| 234 return make_scoped_ptr(new WebSocketEncoder(FOR_SERVER, nullptr, nullptr)); |
212 } | 235 } |
213 | 236 |
214 // static | 237 // static |
215 WebSocketEncoder* WebSocketEncoder::CreateClient( | 238 WebSocketEncoder* WebSocketEncoder::CreateClient( |
216 const std::string& response_extensions) { | 239 const std::string& response_extensions) { |
217 bool deflate; | 240 // 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 | 241 |
227 if (deflate) { | 242 WebSocketExtensionParser parser; |
228 return new WebSocketEncoder(false /* is_server */, client_window_bits, | 243 if (!parser.Parse(response_extensions)) { |
229 server_window_bits, client_no_context_takeover); | 244 // Parse error. Note that there are two cases here. |
230 } else { | 245 // 1) There is no Sec-WebSocket-Extensions header. |
231 return new WebSocketEncoder(false /* is_server */); | 246 // 2) There is a malformed Sec-WebSocketExtensions header. |
| 247 // We should return a deflate-disabled encoder for the former case and |
| 248 // fail the connection for the latter case. |
| 249 return new WebSocketEncoder(FOR_CLIENT, nullptr, nullptr); |
232 } | 250 } |
| 251 if (parser.extensions().size() != 1) { |
| 252 // Only permessage-deflate extension is supported. |
| 253 // TODO (yhirano): Fail the connection. |
| 254 return new WebSocketEncoder(FOR_CLIENT, nullptr, nullptr); |
| 255 } |
| 256 const auto& extension = parser.extensions()[0]; |
| 257 WebSocketDeflateParameters params; |
| 258 std::string failure_message; |
| 259 if (!params.Initialize(extension, &failure_message) || |
| 260 !params.IsValidAsResponse(&failure_message)) { |
| 261 // TODO (yhirano): Fail the connection. |
| 262 return new WebSocketEncoder(FOR_CLIENT, nullptr, nullptr); |
| 263 } |
| 264 |
| 265 auto deflater = make_scoped_ptr( |
| 266 new WebSocketDeflater(params.client_context_take_over_mode())); |
| 267 auto inflater = make_scoped_ptr( |
| 268 new WebSocketInflater(kInflaterChunkSize, kInflaterChunkSize)); |
| 269 if (!deflater->Initialize(params.PermissiveClientMaxWindowBits()) || |
| 270 !inflater->Initialize(params.PermissiveServerMaxWindowBits())) { |
| 271 // TODO (yhirano): Fail the connection. |
| 272 return new WebSocketEncoder(FOR_CLIENT, nullptr, nullptr); |
| 273 } |
| 274 |
| 275 return new WebSocketEncoder(FOR_CLIENT, deflater.Pass(), inflater.Pass()); |
233 } | 276 } |
234 | 277 |
235 // static | 278 WebSocketEncoder::WebSocketEncoder(Type type, |
236 void WebSocketEncoder::ParseExtensions(const std::string& header_value, | 279 scoped_ptr<WebSocketDeflater> deflater, |
237 bool* deflate, | 280 scoped_ptr<WebSocketInflater> inflater) |
238 bool* has_client_window_bits, | 281 : type_(type), deflater_(deflater.Pass()), inflater_(inflater.Pass()) {} |
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 | 282 |
250 if (header_value.empty()) | 283 WebSocketEncoder::~WebSocketEncoder() {} |
251 return; | |
252 | |
253 WebSocketExtensionParser parser; | |
254 if (!parser.Parse(header_value)) | |
255 return; | |
256 const std::vector<WebSocketExtension>& extensions = parser.extensions(); | |
257 // TODO(tyoshino): Fail if this method is used for parsing a response and | |
258 // there are multiple permessage-deflate extensions or there are any unknown | |
259 // extensions. | |
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 } | |
295 | |
296 WebSocketEncoder::WebSocketEncoder(bool is_server) : is_server_(is_server) { | |
297 } | |
298 | |
299 WebSocketEncoder::WebSocketEncoder(bool is_server, | |
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 | 284 |
321 WebSocket::ParseResult WebSocketEncoder::DecodeFrame( | 285 WebSocket::ParseResult WebSocketEncoder::DecodeFrame( |
322 const base::StringPiece& frame, | 286 const base::StringPiece& frame, |
323 int* bytes_consumed, | 287 int* bytes_consumed, |
324 std::string* output) { | 288 std::string* output) { |
325 bool compressed; | 289 bool compressed; |
326 WebSocket::ParseResult result = | 290 WebSocket::ParseResult result = DecodeFrameHybi17( |
327 DecodeFrameHybi17(frame, is_server_, bytes_consumed, output, &compressed); | 291 frame, type_ == FOR_SERVER, bytes_consumed, output, &compressed); |
328 if (result == WebSocket::FRAME_OK && compressed) { | 292 if (result == WebSocket::FRAME_OK && compressed) { |
329 if (!Inflate(output)) | 293 if (!Inflate(output)) |
330 result = WebSocket::FRAME_ERROR; | 294 result = WebSocket::FRAME_ERROR; |
331 } | 295 } |
332 return result; | 296 return result; |
333 } | 297 } |
334 | 298 |
335 void WebSocketEncoder::EncodeFrame(const std::string& frame, | 299 void WebSocketEncoder::EncodeFrame(const std::string& frame, |
336 int masking_key, | 300 int masking_key, |
337 std::string* output) { | 301 std::string* output) { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 return false; | 340 return false; |
377 scoped_refptr<IOBufferWithSize> buffer = | 341 scoped_refptr<IOBufferWithSize> buffer = |
378 deflater_->GetOutput(deflater_->CurrentOutputSize()); | 342 deflater_->GetOutput(deflater_->CurrentOutputSize()); |
379 if (!buffer.get()) | 343 if (!buffer.get()) |
380 return false; | 344 return false; |
381 *output = std::string(buffer->data(), buffer->size()); | 345 *output = std::string(buffer->data(), buffer->size()); |
382 return true; | 346 return true; |
383 } | 347 } |
384 | 348 |
385 } // namespace net | 349 } // namespace net |
OLD | NEW |