| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/websockets/websocket_basic_stream.h" | 5 #include "net/websockets/websocket_basic_stream.h" |
| 6 | 6 |
| 7 #include <stdint.h> |
| 7 #include <algorithm> | 8 #include <algorithm> |
| 8 #include <limits> | 9 #include <limits> |
| 9 #include <string> | 10 #include <string> |
| 10 #include <vector> | 11 #include <vector> |
| 11 | 12 |
| 12 #include "base/basictypes.h" | 13 #include "base/basictypes.h" |
| 13 #include "base/bind.h" | 14 #include "base/bind.h" |
| 14 #include "base/logging.h" | 15 #include "base/logging.h" |
| 15 #include "base/numerics/safe_conversions.h" | 16 #include "base/numerics/safe_conversions.h" |
| 16 #include "net/base/io_buffer.h" | 17 #include "net/base/io_buffer.h" |
| 17 #include "net/base/net_errors.h" | 18 #include "net/base/net_errors.h" |
| 18 #include "net/socket/client_socket_handle.h" | 19 #include "net/socket/client_socket_handle.h" |
| 19 #include "net/websockets/websocket_errors.h" | 20 #include "net/websockets/websocket_errors.h" |
| 20 #include "net/websockets/websocket_frame.h" | 21 #include "net/websockets/websocket_frame.h" |
| 21 #include "net/websockets/websocket_frame_parser.h" | 22 #include "net/websockets/websocket_frame_parser.h" |
| 22 | 23 |
| 23 namespace net { | 24 namespace net { |
| 24 | 25 |
| 25 namespace { | 26 namespace { |
| 26 | 27 |
| 27 // This uses type uint64 to match the definition of | 28 // This uses type uint64_t to match the definition of |
| 28 // WebSocketFrameHeader::payload_length in websocket_frame.h. | 29 // WebSocketFrameHeader::payload_length in websocket_frame.h. |
| 29 const uint64 kMaxControlFramePayload = 125; | 30 const uint64_t kMaxControlFramePayload = 125; |
| 30 | 31 |
| 31 // The number of bytes to attempt to read at a time. | 32 // The number of bytes to attempt to read at a time. |
| 32 // TODO(ricea): See if there is a better number or algorithm to fulfill our | 33 // TODO(ricea): See if there is a better number or algorithm to fulfill our |
| 33 // requirements: | 34 // requirements: |
| 34 // 1. We would like to use minimal memory on low-bandwidth or idle connections | 35 // 1. We would like to use minimal memory on low-bandwidth or idle connections |
| 35 // 2. We would like to read as close to line speed as possible on | 36 // 2. We would like to read as close to line speed as possible on |
| 36 // high-bandwidth connections | 37 // high-bandwidth connections |
| 37 // 3. We can't afford to cause jank on the IO thread by copying large buffers | 38 // 3. We can't afford to cause jank on the IO thread by copying large buffers |
| 38 // around | 39 // around |
| 39 // 4. We would like to hit any sweet-spots that might exist in terms of network | 40 // 4. We would like to hit any sweet-spots that might exist in terms of network |
| 40 // packet sizes / encryption block sizes / IPC alignment issues, etc. | 41 // packet sizes / encryption block sizes / IPC alignment issues, etc. |
| 41 const int kReadBufferSize = 32 * 1024; | 42 const int kReadBufferSize = 32 * 1024; |
| 42 | 43 |
| 43 typedef ScopedVector<WebSocketFrame>::const_iterator WebSocketFrameIterator; | 44 typedef ScopedVector<WebSocketFrame>::const_iterator WebSocketFrameIterator; |
| 44 | 45 |
| 45 // Returns the total serialized size of |frames|. This function assumes that | 46 // Returns the total serialized size of |frames|. This function assumes that |
| 46 // |frames| will be serialized with mask field. This function forces the | 47 // |frames| will be serialized with mask field. This function forces the |
| 47 // masked bit of the frames on. | 48 // masked bit of the frames on. |
| 48 int CalculateSerializedSizeAndTurnOnMaskBit( | 49 int CalculateSerializedSizeAndTurnOnMaskBit( |
| 49 ScopedVector<WebSocketFrame>* frames) { | 50 ScopedVector<WebSocketFrame>* frames) { |
| 50 const uint64 kMaximumTotalSize = std::numeric_limits<int>::max(); | 51 const uint64_t kMaximumTotalSize = std::numeric_limits<int>::max(); |
| 51 | 52 |
| 52 uint64 total_size = 0; | 53 uint64_t total_size = 0; |
| 53 for (WebSocketFrameIterator it = frames->begin(); it != frames->end(); ++it) { | 54 for (WebSocketFrameIterator it = frames->begin(); it != frames->end(); ++it) { |
| 54 WebSocketFrame* frame = *it; | 55 WebSocketFrame* frame = *it; |
| 55 // Force the masked bit on. | 56 // Force the masked bit on. |
| 56 frame->header.masked = true; | 57 frame->header.masked = true; |
| 57 // We enforce flow control so the renderer should never be able to force us | 58 // We enforce flow control so the renderer should never be able to force us |
| 58 // to cache anywhere near 2GB of frames. | 59 // to cache anywhere near 2GB of frames. |
| 59 uint64 frame_size = frame->header.payload_length + | 60 uint64_t frame_size = frame->header.payload_length + |
| 60 GetWebSocketFrameHeaderSize(frame->header); | 61 GetWebSocketFrameHeaderSize(frame->header); |
| 61 CHECK_LE(frame_size, kMaximumTotalSize - total_size) | 62 CHECK_LE(frame_size, kMaximumTotalSize - total_size) |
| 62 << "Aborting to prevent overflow"; | 63 << "Aborting to prevent overflow"; |
| 63 total_size += frame_size; | 64 total_size += frame_size; |
| 64 } | 65 } |
| 65 return static_cast<int>(total_size); | 66 return static_cast<int>(total_size); |
| 66 } | 67 } |
| 67 | 68 |
| 68 } // namespace | 69 } // namespace |
| 69 | 70 |
| 70 WebSocketBasicStream::WebSocketBasicStream( | 71 WebSocketBasicStream::WebSocketBasicStream( |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 150 WebSocketMaskingKey mask = generate_websocket_masking_key_(); | 151 WebSocketMaskingKey mask = generate_websocket_masking_key_(); |
| 151 int result = | 152 int result = |
| 152 WriteWebSocketFrameHeader(frame->header, &mask, dest, remaining_size); | 153 WriteWebSocketFrameHeader(frame->header, &mask, dest, remaining_size); |
| 153 DCHECK_NE(ERR_INVALID_ARGUMENT, result) | 154 DCHECK_NE(ERR_INVALID_ARGUMENT, result) |
| 154 << "WriteWebSocketFrameHeader() says that " << remaining_size | 155 << "WriteWebSocketFrameHeader() says that " << remaining_size |
| 155 << " is not enough to write the header in. This should not happen."; | 156 << " is not enough to write the header in. This should not happen."; |
| 156 CHECK_GE(result, 0) << "Potentially security-critical check failed"; | 157 CHECK_GE(result, 0) << "Potentially security-critical check failed"; |
| 157 dest += result; | 158 dest += result; |
| 158 remaining_size -= result; | 159 remaining_size -= result; |
| 159 | 160 |
| 160 CHECK_LE(frame->header.payload_length, static_cast<uint64>(remaining_size)); | 161 CHECK_LE(frame->header.payload_length, |
| 162 static_cast<uint64_t>(remaining_size)); |
| 161 const int frame_size = static_cast<int>(frame->header.payload_length); | 163 const int frame_size = static_cast<int>(frame->header.payload_length); |
| 162 if (frame_size > 0) { | 164 if (frame_size > 0) { |
| 163 const char* const frame_data = frame->data->data(); | 165 const char* const frame_data = frame->data->data(); |
| 164 std::copy(frame_data, frame_data + frame_size, dest); | 166 std::copy(frame_data, frame_data + frame_size, dest); |
| 165 MaskWebSocketFramePayload(mask, 0, dest, frame_size); | 167 MaskWebSocketFramePayload(mask, 0, dest, frame_size); |
| 166 dest += frame_size; | 168 dest += frame_size; |
| 167 remaining_size -= frame_size; | 169 remaining_size -= frame_size; |
| 168 } | 170 } |
| 169 } | 171 } |
| 170 DCHECK_EQ(0, remaining_size) << "Buffer size calculation was wrong; " | 172 DCHECK_EQ(0, remaining_size) << "Buffer size calculation was wrong; " |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 342 DCHECK(is_final_chunk); | 344 DCHECK(is_final_chunk); |
| 343 *frame = CreateFrame(is_final_chunk, body); | 345 *frame = CreateFrame(is_final_chunk, body); |
| 344 return OK; | 346 return OK; |
| 345 } | 347 } |
| 346 } | 348 } |
| 347 | 349 |
| 348 // Apply basic sanity checks to the |payload_length| field from the frame | 350 // Apply basic sanity checks to the |payload_length| field from the frame |
| 349 // header. A check for exact equality can only be used when the whole frame | 351 // header. A check for exact equality can only be used when the whole frame |
| 350 // arrives in one chunk. | 352 // arrives in one chunk. |
| 351 DCHECK_GE(current_frame_header_->payload_length, | 353 DCHECK_GE(current_frame_header_->payload_length, |
| 352 base::checked_cast<uint64>(chunk_size)); | 354 base::checked_cast<uint64_t>(chunk_size)); |
| 353 DCHECK(!is_first_chunk || !is_final_chunk || | 355 DCHECK(!is_first_chunk || !is_final_chunk || |
| 354 current_frame_header_->payload_length == | 356 current_frame_header_->payload_length == |
| 355 base::checked_cast<uint64>(chunk_size)); | 357 base::checked_cast<uint64_t>(chunk_size)); |
| 356 | 358 |
| 357 // Convert the chunk to a complete frame. | 359 // Convert the chunk to a complete frame. |
| 358 *frame = CreateFrame(is_final_chunk, data_buffer); | 360 *frame = CreateFrame(is_final_chunk, data_buffer); |
| 359 return OK; | 361 return OK; |
| 360 } | 362 } |
| 361 | 363 |
| 362 scoped_ptr<WebSocketFrame> WebSocketBasicStream::CreateFrame( | 364 scoped_ptr<WebSocketFrame> WebSocketBasicStream::CreateFrame( |
| 363 bool is_final_chunk, | 365 bool is_final_chunk, |
| 364 const scoped_refptr<IOBufferWithSize>& data) { | 366 const scoped_refptr<IOBufferWithSize>& data) { |
| 365 scoped_ptr<WebSocketFrame> result_frame; | 367 scoped_ptr<WebSocketFrame> result_frame; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 415 const CompletionCallback& callback, | 417 const CompletionCallback& callback, |
| 416 int result) { | 418 int result) { |
| 417 result = HandleReadResult(result, frames); | 419 result = HandleReadResult(result, frames); |
| 418 if (result == ERR_IO_PENDING) | 420 if (result == ERR_IO_PENDING) |
| 419 result = ReadFrames(frames, callback); | 421 result = ReadFrames(frames, callback); |
| 420 if (result != ERR_IO_PENDING) | 422 if (result != ERR_IO_PENDING) |
| 421 callback.Run(result); | 423 callback.Run(result); |
| 422 } | 424 } |
| 423 | 425 |
| 424 } // namespace net | 426 } // namespace net |
| OLD | NEW |