We started redesigning GpuMemoryBuffer interface to handle multiple buffers [0].
[chromium-blink-merge.git] / net / quic / crypto / crypto_framer.cc
blob7f81f3639775c24e15b2e515a6a80ae5cd34d4d3
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
3 // found in the LICENSE file.
5 #include "net/quic/crypto/crypto_framer.h"
7 #include "net/quic/crypto/crypto_protocol.h"
8 #include "net/quic/quic_data_reader.h"
9 #include "net/quic/quic_data_writer.h"
11 using base::StringPiece;
12 using std::pair;
13 using std::vector;
15 namespace net {
17 namespace {
19 const size_t kQuicTagSize = sizeof(uint32);
20 const size_t kCryptoEndOffsetSize = sizeof(uint32);
21 const size_t kNumEntriesSize = sizeof(uint16);
23 // OneShotVisitor is a framer visitor that records a single handshake message.
24 class OneShotVisitor : public CryptoFramerVisitorInterface {
25 public:
26 OneShotVisitor() : error_(false) {}
28 void OnError(CryptoFramer* framer) override { error_ = true; }
30 void OnHandshakeMessage(const CryptoHandshakeMessage& message) override {
31 out_.reset(new CryptoHandshakeMessage(message));
34 bool error() const { return error_; }
36 CryptoHandshakeMessage* release() { return out_.release(); }
38 private:
39 scoped_ptr<CryptoHandshakeMessage> out_;
40 bool error_;
43 } // namespace
45 CryptoFramer::CryptoFramer()
46 : visitor_(nullptr),
47 num_entries_(0),
48 values_len_(0) {
49 Clear();
52 CryptoFramer::~CryptoFramer() {}
54 // static
55 CryptoHandshakeMessage* CryptoFramer::ParseMessage(StringPiece in) {
56 OneShotVisitor visitor;
57 CryptoFramer framer;
59 framer.set_visitor(&visitor);
60 if (!framer.ProcessInput(in) || visitor.error() ||
61 framer.InputBytesRemaining()) {
62 return nullptr;
65 return visitor.release();
68 bool CryptoFramer::ProcessInput(StringPiece input) {
69 DCHECK_EQ(QUIC_NO_ERROR, error_);
70 if (error_ != QUIC_NO_ERROR) {
71 return false;
73 error_ = Process(input);
74 if (error_ != QUIC_NO_ERROR) {
75 visitor_->OnError(this);
76 return false;
79 return true;
82 // static
83 QuicData* CryptoFramer::ConstructHandshakeMessage(
84 const CryptoHandshakeMessage& message) {
85 size_t num_entries = message.tag_value_map().size();
86 size_t pad_length = 0;
87 bool need_pad_tag = false;
88 bool need_pad_value = false;
90 size_t len = message.size();
91 if (len < message.minimum_size()) {
92 need_pad_tag = true;
93 need_pad_value = true;
94 num_entries++;
96 size_t delta = message.minimum_size() - len;
97 const size_t overhead = kQuicTagSize + kCryptoEndOffsetSize;
98 if (delta > overhead) {
99 pad_length = delta - overhead;
101 len += overhead + pad_length;
104 if (num_entries > kMaxEntries) {
105 return nullptr;
108 scoped_ptr<char[]> buffer(new char[len]);
109 QuicDataWriter writer(len, buffer.get());
110 if (!writer.WriteUInt32(message.tag())) {
111 DCHECK(false) << "Failed to write message tag.";
112 return nullptr;
114 if (!writer.WriteUInt16(static_cast<uint16>(num_entries))) {
115 DCHECK(false) << "Failed to write size.";
116 return nullptr;
118 if (!writer.WriteUInt16(0)) {
119 DCHECK(false) << "Failed to write padding.";
120 return nullptr;
123 uint32 end_offset = 0;
124 // Tags and offsets
125 for (QuicTagValueMap::const_iterator it = message.tag_value_map().begin();
126 it != message.tag_value_map().end(); ++it) {
127 if (it->first == kPAD && need_pad_tag) {
128 // Existing PAD tags are only checked when padding needs to be added
129 // because parts of the code may need to reserialize received messages
130 // and those messages may, legitimately include padding.
131 DCHECK(false) << "Message needed padding but already contained a PAD tag";
132 return nullptr;
135 if (it->first > kPAD && need_pad_tag) {
136 need_pad_tag = false;
137 if (!WritePadTag(&writer, pad_length, &end_offset)) {
138 return nullptr;
142 if (!writer.WriteUInt32(it->first)) {
143 DCHECK(false) << "Failed to write tag.";
144 return nullptr;
146 end_offset += it->second.length();
147 if (!writer.WriteUInt32(end_offset)) {
148 DCHECK(false) << "Failed to write end offset.";
149 return nullptr;
153 if (need_pad_tag) {
154 if (!WritePadTag(&writer, pad_length, &end_offset)) {
155 return nullptr;
159 // Values
160 for (QuicTagValueMap::const_iterator it = message.tag_value_map().begin();
161 it != message.tag_value_map().end(); ++it) {
162 if (it->first > kPAD && need_pad_value) {
163 need_pad_value = false;
164 if (!writer.WriteRepeatedByte('-', pad_length)) {
165 DCHECK(false) << "Failed to write padding.";
166 return nullptr;
170 if (!writer.WriteBytes(it->second.data(), it->second.length())) {
171 DCHECK(false) << "Failed to write value.";
172 return nullptr;
176 if (need_pad_value) {
177 if (!writer.WriteRepeatedByte('-', pad_length)) {
178 DCHECK(false) << "Failed to write padding.";
179 return nullptr;
183 return new QuicData(buffer.release(), len, true);
186 void CryptoFramer::Clear() {
187 message_.Clear();
188 tags_and_lengths_.clear();
189 error_ = QUIC_NO_ERROR;
190 state_ = STATE_READING_TAG;
193 QuicErrorCode CryptoFramer::Process(StringPiece input) {
194 // Add this data to the buffer.
195 buffer_.append(input.data(), input.length());
196 QuicDataReader reader(buffer_.data(), buffer_.length());
198 switch (state_) {
199 case STATE_READING_TAG:
200 if (reader.BytesRemaining() < kQuicTagSize) {
201 break;
203 QuicTag message_tag;
204 reader.ReadUInt32(&message_tag);
205 message_.set_tag(message_tag);
206 state_ = STATE_READING_NUM_ENTRIES;
207 case STATE_READING_NUM_ENTRIES:
208 if (reader.BytesRemaining() < kNumEntriesSize + sizeof(uint16)) {
209 break;
211 reader.ReadUInt16(&num_entries_);
212 if (num_entries_ > kMaxEntries) {
213 return QUIC_CRYPTO_TOO_MANY_ENTRIES;
215 uint16 padding;
216 reader.ReadUInt16(&padding);
218 tags_and_lengths_.reserve(num_entries_);
219 state_ = STATE_READING_TAGS_AND_LENGTHS;
220 values_len_ = 0;
221 case STATE_READING_TAGS_AND_LENGTHS: {
222 if (reader.BytesRemaining() <
223 num_entries_ * (kQuicTagSize + kCryptoEndOffsetSize)) {
224 break;
227 uint32 last_end_offset = 0;
228 for (unsigned i = 0; i < num_entries_; ++i) {
229 QuicTag tag;
230 reader.ReadUInt32(&tag);
231 if (i > 0 && tag <= tags_and_lengths_[i-1].first) {
232 if (tag == tags_and_lengths_[i-1].first) {
233 return QUIC_CRYPTO_DUPLICATE_TAG;
235 return QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
238 uint32 end_offset;
239 reader.ReadUInt32(&end_offset);
241 if (end_offset < last_end_offset) {
242 return QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
244 tags_and_lengths_.push_back(std::make_pair(
245 tag, static_cast<size_t>(end_offset - last_end_offset)));
246 last_end_offset = end_offset;
248 values_len_ = last_end_offset;
249 state_ = STATE_READING_VALUES;
251 case STATE_READING_VALUES:
252 if (reader.BytesRemaining() < values_len_) {
253 break;
255 for (vector<pair<QuicTag, size_t> >::const_iterator
256 it = tags_and_lengths_.begin(); it != tags_and_lengths_.end();
257 it++) {
258 StringPiece value;
259 reader.ReadStringPiece(&value, it->second);
260 message_.SetStringPiece(it->first, value);
262 visitor_->OnHandshakeMessage(message_);
263 Clear();
264 state_ = STATE_READING_TAG;
265 break;
267 // Save any remaining data.
268 buffer_ = reader.PeekRemainingPayload().as_string();
269 return QUIC_NO_ERROR;
272 // static
273 bool CryptoFramer::WritePadTag(QuicDataWriter* writer,
274 size_t pad_length,
275 uint32* end_offset) {
276 if (!writer->WriteUInt32(kPAD)) {
277 DCHECK(false) << "Failed to write tag.";
278 return false;
280 *end_offset += pad_length;
281 if (!writer->WriteUInt32(*end_offset)) {
282 DCHECK(false) << "Failed to write end offset.";
283 return false;
285 return true;
288 } // namespace net