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 |