| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_frame_parser.h" | 5 #include "net/websockets/websocket_frame_parser.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <limits> | 8 #include <limits> |
| 9 | 9 |
| 10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 const uint64 kPayloadLengthWithTwoByteExtendedLengthField = 126; | 29 const uint64 kPayloadLengthWithTwoByteExtendedLengthField = 126; |
| 30 const uint64 kPayloadLengthWithEightByteExtendedLengthField = 127; | 30 const uint64 kPayloadLengthWithEightByteExtendedLengthField = 127; |
| 31 | 31 |
| 32 } // Unnamed namespace. | 32 } // Unnamed namespace. |
| 33 | 33 |
| 34 namespace net { | 34 namespace net { |
| 35 | 35 |
| 36 WebSocketFrameParser::WebSocketFrameParser() | 36 WebSocketFrameParser::WebSocketFrameParser() |
| 37 : current_read_pos_(0), | 37 : current_read_pos_(0), |
| 38 frame_offset_(0), | 38 frame_offset_(0), |
| 39 websocket_error_(WEB_SOCKET_OK) { | 39 websocket_error_(kWebSocketNormalClosure) { |
| 40 std::fill(masking_key_.key, | 40 std::fill(masking_key_.key, |
| 41 masking_key_.key + WebSocketFrameHeader::kMaskingKeyLength, | 41 masking_key_.key + WebSocketFrameHeader::kMaskingKeyLength, |
| 42 '\0'); | 42 '\0'); |
| 43 } | 43 } |
| 44 | 44 |
| 45 WebSocketFrameParser::~WebSocketFrameParser() { | 45 WebSocketFrameParser::~WebSocketFrameParser() { |
| 46 } | 46 } |
| 47 | 47 |
| 48 bool WebSocketFrameParser::Decode( | 48 bool WebSocketFrameParser::Decode( |
| 49 const char* data, | 49 const char* data, |
| 50 size_t length, | 50 size_t length, |
| 51 ScopedVector<WebSocketFrameChunk>* frame_chunks) { | 51 ScopedVector<WebSocketFrameChunk>* frame_chunks) { |
| 52 if (websocket_error_ != WEB_SOCKET_OK) | 52 if (websocket_error_ != kWebSocketNormalClosure) |
| 53 return false; | 53 return false; |
| 54 if (!length) | 54 if (!length) |
| 55 return true; | 55 return true; |
| 56 | 56 |
| 57 // TODO(yutak): Remove copy. | 57 // TODO(yutak): Remove copy. |
| 58 buffer_.insert(buffer_.end(), data, data + length); | 58 buffer_.insert(buffer_.end(), data, data + length); |
| 59 | 59 |
| 60 while (current_read_pos_ < buffer_.size()) { | 60 while (current_read_pos_ < buffer_.size()) { |
| 61 bool first_chunk = false; | 61 bool first_chunk = false; |
| 62 if (!current_frame_header_.get()) { | 62 if (!current_frame_header_.get()) { |
| 63 DecodeFrameHeader(); | 63 DecodeFrameHeader(); |
| 64 if (websocket_error_ != WEB_SOCKET_OK) | 64 if (websocket_error_ != kWebSocketNormalClosure) |
| 65 return false; | 65 return false; |
| 66 // If frame header is incomplete, then carry over the remaining | 66 // If frame header is incomplete, then carry over the remaining |
| 67 // data to the next round of Decode(). | 67 // data to the next round of Decode(). |
| 68 if (!current_frame_header_.get()) | 68 if (!current_frame_header_.get()) |
| 69 break; | 69 break; |
| 70 first_chunk = true; | 70 first_chunk = true; |
| 71 } | 71 } |
| 72 | 72 |
| 73 scoped_ptr<WebSocketFrameChunk> frame_chunk = | 73 scoped_ptr<WebSocketFrameChunk> frame_chunk = |
| 74 DecodeFramePayload(first_chunk); | 74 DecodeFramePayload(first_chunk); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 bool masked = (second_byte & kMaskBit) != 0; | 122 bool masked = (second_byte & kMaskBit) != 0; |
| 123 uint64 payload_length = second_byte & kPayloadLengthMask; | 123 uint64 payload_length = second_byte & kPayloadLengthMask; |
| 124 if (payload_length == kPayloadLengthWithTwoByteExtendedLengthField) { | 124 if (payload_length == kPayloadLengthWithTwoByteExtendedLengthField) { |
| 125 if (end - current < 2) | 125 if (end - current < 2) |
| 126 return; | 126 return; |
| 127 uint16 payload_length_16; | 127 uint16 payload_length_16; |
| 128 ReadBigEndian(current, &payload_length_16); | 128 ReadBigEndian(current, &payload_length_16); |
| 129 current += 2; | 129 current += 2; |
| 130 payload_length = payload_length_16; | 130 payload_length = payload_length_16; |
| 131 if (payload_length <= kMaxPayloadLengthWithoutExtendedLengthField) | 131 if (payload_length <= kMaxPayloadLengthWithoutExtendedLengthField) |
| 132 websocket_error_ = WEB_SOCKET_ERR_PROTOCOL_ERROR; | 132 websocket_error_ = kWebSocketErrorProtocolError; |
| 133 } else if (payload_length == kPayloadLengthWithEightByteExtendedLengthField) { | 133 } else if (payload_length == kPayloadLengthWithEightByteExtendedLengthField) { |
| 134 if (end - current < 8) | 134 if (end - current < 8) |
| 135 return; | 135 return; |
| 136 ReadBigEndian(current, &payload_length); | 136 ReadBigEndian(current, &payload_length); |
| 137 current += 8; | 137 current += 8; |
| 138 if (payload_length <= kuint16max || | 138 if (payload_length <= kuint16max || |
| 139 payload_length > static_cast<uint64>(kint64max)) { | 139 payload_length > static_cast<uint64>(kint64max)) { |
| 140 websocket_error_ = WEB_SOCKET_ERR_PROTOCOL_ERROR; | 140 websocket_error_ = kWebSocketErrorProtocolError; |
| 141 } else if (payload_length > static_cast<uint64>(kint32max)) { | 141 } else if (payload_length > static_cast<uint64>(kint32max)) { |
| 142 websocket_error_ = WEB_SOCKET_ERR_MESSAGE_TOO_BIG; | 142 websocket_error_ = kWebSocketErrorMessageTooBig; |
| 143 } | 143 } |
| 144 } | 144 } |
| 145 if (websocket_error_ != WEB_SOCKET_OK) { | 145 if (websocket_error_ != kWebSocketNormalClosure) { |
| 146 buffer_.clear(); | 146 buffer_.clear(); |
| 147 current_read_pos_ = 0; | 147 current_read_pos_ = 0; |
| 148 current_frame_header_.reset(); | 148 current_frame_header_.reset(); |
| 149 frame_offset_ = 0; | 149 frame_offset_ = 0; |
| 150 return; | 150 return; |
| 151 } | 151 } |
| 152 | 152 |
| 153 if (masked) { | 153 if (masked) { |
| 154 if (end - current < kMaskingKeyLength) | 154 if (end - current < kMaskingKeyLength) |
| 155 return; | 155 return; |
| 156 std::copy(current, current + kMaskingKeyLength, masking_key_.key); | 156 std::copy(current, current + kMaskingKeyLength, masking_key_.key); |
| 157 current += kMaskingKeyLength; | 157 current += kMaskingKeyLength; |
| 158 } else { | 158 } else { |
| 159 std::fill(masking_key_.key, masking_key_.key + kMaskingKeyLength, '\0'); | 159 std::fill(masking_key_.key, masking_key_.key + kMaskingKeyLength, '\0'); |
| 160 } | 160 } |
| 161 | 161 |
| 162 current_frame_header_.reset(new WebSocketFrameHeader); | 162 current_frame_header_.reset(new WebSocketFrameHeader(opcode)); |
| 163 current_frame_header_->final = final; | 163 current_frame_header_->final = final; |
| 164 current_frame_header_->reserved1 = reserved1; | 164 current_frame_header_->reserved1 = reserved1; |
| 165 current_frame_header_->reserved2 = reserved2; | 165 current_frame_header_->reserved2 = reserved2; |
| 166 current_frame_header_->reserved3 = reserved3; | 166 current_frame_header_->reserved3 = reserved3; |
| 167 current_frame_header_->opcode = opcode; | |
| 168 current_frame_header_->masked = masked; | 167 current_frame_header_->masked = masked; |
| 169 current_frame_header_->payload_length = payload_length; | 168 current_frame_header_->payload_length = payload_length; |
| 170 current_read_pos_ += current - start; | 169 current_read_pos_ += current - start; |
| 171 DCHECK_EQ(0u, frame_offset_); | 170 DCHECK_EQ(0u, frame_offset_); |
| 172 } | 171 } |
| 173 | 172 |
| 174 scoped_ptr<WebSocketFrameChunk> WebSocketFrameParser::DecodeFramePayload( | 173 scoped_ptr<WebSocketFrameChunk> WebSocketFrameParser::DecodeFramePayload( |
| 175 bool first_chunk) { | 174 bool first_chunk) { |
| 176 const char* current = &buffer_.front() + current_read_pos_; | 175 const char* current = &buffer_.front() + current_read_pos_; |
| 177 const char* end = &buffer_.front() + buffer_.size(); | 176 const char* end = &buffer_.front() + buffer_.size(); |
| 178 uint64 next_size = std::min<uint64>( | 177 uint64 next_size = std::min<uint64>( |
| 179 end - current, | 178 end - current, |
| 180 current_frame_header_->payload_length - frame_offset_); | 179 current_frame_header_->payload_length - frame_offset_); |
| 181 // This check must pass because |payload_length| is already checked to be | 180 // This check must pass because |payload_length| is already checked to be |
| 182 // less than std::numeric_limits<int>::max() when the header is parsed. | 181 // less than std::numeric_limits<int>::max() when the header is parsed. |
| 183 DCHECK_LE(next_size, static_cast<uint64>(kint32max)); | 182 DCHECK_LE(next_size, static_cast<uint64>(kint32max)); |
| 184 | 183 |
| 185 scoped_ptr<WebSocketFrameChunk> frame_chunk(new WebSocketFrameChunk); | 184 scoped_ptr<WebSocketFrameChunk> frame_chunk(new WebSocketFrameChunk); |
| 186 if (first_chunk) { | 185 if (first_chunk) { |
| 187 frame_chunk->header.reset(new WebSocketFrameHeader(*current_frame_header_)); | 186 frame_chunk->header = current_frame_header_->Clone(); |
| 188 } | 187 } |
| 189 frame_chunk->final_chunk = false; | 188 frame_chunk->final_chunk = false; |
| 190 if (next_size) { | 189 if (next_size) { |
| 191 frame_chunk->data = new IOBufferWithSize(static_cast<int>(next_size)); | 190 frame_chunk->data = new IOBufferWithSize(static_cast<int>(next_size)); |
| 192 char* io_data = frame_chunk->data->data(); | 191 char* io_data = frame_chunk->data->data(); |
| 193 memcpy(io_data, current, next_size); | 192 memcpy(io_data, current, next_size); |
| 194 if (current_frame_header_->masked) { | 193 if (current_frame_header_->masked) { |
| 195 // The masking function is its own inverse, so we use the same function to | 194 // The masking function is its own inverse, so we use the same function to |
| 196 // unmask as to mask. | 195 // unmask as to mask. |
| 197 MaskWebSocketFramePayload(masking_key_, frame_offset_, | 196 MaskWebSocketFramePayload(masking_key_, frame_offset_, |
| 198 io_data, next_size); | 197 io_data, next_size); |
| 199 } | 198 } |
| 200 | 199 |
| 201 current_read_pos_ += next_size; | 200 current_read_pos_ += next_size; |
| 202 frame_offset_ += next_size; | 201 frame_offset_ += next_size; |
| 203 } | 202 } |
| 204 | 203 |
| 205 DCHECK_LE(frame_offset_, current_frame_header_->payload_length); | 204 DCHECK_LE(frame_offset_, current_frame_header_->payload_length); |
| 206 if (frame_offset_ == current_frame_header_->payload_length) { | 205 if (frame_offset_ == current_frame_header_->payload_length) { |
| 207 frame_chunk->final_chunk = true; | 206 frame_chunk->final_chunk = true; |
| 208 current_frame_header_.reset(); | 207 current_frame_header_.reset(); |
| 209 frame_offset_ = 0; | 208 frame_offset_ = 0; |
| 210 } | 209 } |
| 211 | 210 |
| 212 return frame_chunk.Pass(); | 211 return frame_chunk.Pass(); |
| 213 } | 212 } |
| 214 | 213 |
| 215 } // namespace net | 214 } // namespace net |
| OLD | NEW |