Lots of random cleanups, mostly for native_theme_win.cc:
[chromium-blink-merge.git] / net / quic / crypto / crypto_framer.cc
blob5cb16743e6905ad927a14ad1944237985b67ee63
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::make_pair;
13 using std::pair;
14 using std::vector;
16 namespace net {
18 namespace {
20 const size_t kQuicTagSize = sizeof(uint32);
21 const size_t kCryptoEndOffsetSize = sizeof(uint32);
22 const size_t kNumEntriesSize = sizeof(uint16);
24 // OneShotVisitor is a framer visitor that records a single handshake message.
25 class OneShotVisitor : public CryptoFramerVisitorInterface {
26 public:
27 OneShotVisitor() : error_(false) {}
29 virtual void OnError(CryptoFramer* framer) OVERRIDE { error_ = true; }
31 virtual void OnHandshakeMessage(
32 const CryptoHandshakeMessage& message) OVERRIDE {
33 out_.reset(new CryptoHandshakeMessage(message));
36 bool error() const { return error_; }
38 CryptoHandshakeMessage* release() { return out_.release(); }
40 private:
41 scoped_ptr<CryptoHandshakeMessage> out_;
42 bool error_;
45 } // namespace
47 CryptoFramer::CryptoFramer()
48 : visitor_(NULL),
49 num_entries_(0),
50 values_len_(0) {
51 Clear();
54 CryptoFramer::~CryptoFramer() {}
56 // static
57 CryptoHandshakeMessage* CryptoFramer::ParseMessage(StringPiece in) {
58 OneShotVisitor visitor;
59 CryptoFramer framer;
61 framer.set_visitor(&visitor);
62 if (!framer.ProcessInput(in) || visitor.error() ||
63 framer.InputBytesRemaining()) {
64 return NULL;
67 return visitor.release();
70 bool CryptoFramer::ProcessInput(StringPiece input) {
71 DCHECK_EQ(QUIC_NO_ERROR, error_);
72 if (error_ != QUIC_NO_ERROR) {
73 return false;
75 error_ = Process(input);
76 if (error_ != QUIC_NO_ERROR) {
77 visitor_->OnError(this);
78 return false;
81 return true;
84 // static
85 QuicData* CryptoFramer::ConstructHandshakeMessage(
86 const CryptoHandshakeMessage& message) {
87 size_t num_entries = message.tag_value_map().size();
88 size_t pad_length = 0;
89 bool need_pad_tag = false;
90 bool need_pad_value = false;
92 size_t len = message.size();
93 if (len < message.minimum_size()) {
94 need_pad_tag = true;
95 need_pad_value = true;
96 num_entries++;
98 size_t delta = message.minimum_size() - len;
99 const size_t overhead = kQuicTagSize + kCryptoEndOffsetSize;
100 if (delta > overhead) {
101 pad_length = delta - overhead;
103 len += overhead + pad_length;
106 if (num_entries > kMaxEntries) {
107 return NULL;
111 QuicDataWriter writer(len);
112 if (!writer.WriteUInt32(message.tag())) {
113 DCHECK(false) << "Failed to write message tag.";
114 return NULL;
116 if (!writer.WriteUInt16(num_entries)) {
117 DCHECK(false) << "Failed to write size.";
118 return NULL;
120 if (!writer.WriteUInt16(0)) {
121 DCHECK(false) << "Failed to write padding.";
122 return NULL;
125 uint32 end_offset = 0;
126 // Tags and offsets
127 for (QuicTagValueMap::const_iterator it = message.tag_value_map().begin();
128 it != message.tag_value_map().end(); ++it) {
129 if (it->first == kPAD && need_pad_tag) {
130 // Existing PAD tags are only checked when padding needs to be added
131 // because parts of the code may need to reserialize received messages
132 // and those messages may, legitimately include padding.
133 DCHECK(false) << "Message needed padding but already contained a PAD tag";
134 return NULL;
137 if (it->first > kPAD && need_pad_tag) {
138 need_pad_tag = false;
139 if (!WritePadTag(&writer, pad_length, &end_offset)) {
140 return NULL;
144 if (!writer.WriteUInt32(it->first)) {
145 DCHECK(false) << "Failed to write tag.";
146 return NULL;
148 end_offset += it->second.length();
149 if (!writer.WriteUInt32(end_offset)) {
150 DCHECK(false) << "Failed to write end offset.";
151 return NULL;
155 if (need_pad_tag) {
156 if (!WritePadTag(&writer, pad_length, &end_offset)) {
157 return NULL;
161 // Values
162 for (QuicTagValueMap::const_iterator it = message.tag_value_map().begin();
163 it != message.tag_value_map().end(); ++it) {
164 if (it->first > kPAD && need_pad_value) {
165 need_pad_value = false;
166 if (!writer.WriteRepeatedByte('-', pad_length)) {
167 DCHECK(false) << "Failed to write padding.";
168 return NULL;
172 if (!writer.WriteBytes(it->second.data(), it->second.length())) {
173 DCHECK(false) << "Failed to write value.";
174 return NULL;
178 if (need_pad_value) {
179 if (!writer.WriteRepeatedByte('-', pad_length)) {
180 DCHECK(false) << "Failed to write padding.";
181 return NULL;
185 return new QuicData(writer.take(), len, true);
188 void CryptoFramer::Clear() {
189 message_.Clear();
190 tags_and_lengths_.clear();
191 error_ = QUIC_NO_ERROR;
192 state_ = STATE_READING_TAG;
195 QuicErrorCode CryptoFramer::Process(StringPiece input) {
196 // Add this data to the buffer.
197 buffer_.append(input.data(), input.length());
198 QuicDataReader reader(buffer_.data(), buffer_.length());
200 switch (state_) {
201 case STATE_READING_TAG:
202 if (reader.BytesRemaining() < kQuicTagSize) {
203 break;
205 QuicTag message_tag;
206 reader.ReadUInt32(&message_tag);
207 message_.set_tag(message_tag);
208 state_ = STATE_READING_NUM_ENTRIES;
209 case STATE_READING_NUM_ENTRIES:
210 if (reader.BytesRemaining() < kNumEntriesSize + sizeof(uint16)) {
211 break;
213 reader.ReadUInt16(&num_entries_);
214 if (num_entries_ > kMaxEntries) {
215 return QUIC_CRYPTO_TOO_MANY_ENTRIES;
217 uint16 padding;
218 reader.ReadUInt16(&padding);
220 tags_and_lengths_.reserve(num_entries_);
221 state_ = STATE_READING_TAGS_AND_LENGTHS;
222 values_len_ = 0;
223 case STATE_READING_TAGS_AND_LENGTHS: {
224 if (reader.BytesRemaining() <
225 num_entries_ * (kQuicTagSize + kCryptoEndOffsetSize)) {
226 break;
229 uint32 last_end_offset = 0;
230 for (unsigned i = 0; i < num_entries_; ++i) {
231 QuicTag tag;
232 reader.ReadUInt32(&tag);
233 if (i > 0 && tag <= tags_and_lengths_[i-1].first) {
234 if (tag == tags_and_lengths_[i-1].first) {
235 return QUIC_CRYPTO_DUPLICATE_TAG;
237 return QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
240 uint32 end_offset;
241 reader.ReadUInt32(&end_offset);
243 if (end_offset < last_end_offset) {
244 return QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
246 tags_and_lengths_.push_back(
247 make_pair(tag, static_cast<size_t>(end_offset - last_end_offset)));
248 last_end_offset = end_offset;
250 values_len_ = last_end_offset;
251 state_ = STATE_READING_VALUES;
253 case STATE_READING_VALUES:
254 if (reader.BytesRemaining() < values_len_) {
255 break;
257 for (vector<pair<QuicTag, size_t> >::const_iterator
258 it = tags_and_lengths_.begin(); it != tags_and_lengths_.end();
259 it++) {
260 StringPiece value;
261 reader.ReadStringPiece(&value, it->second);
262 message_.SetStringPiece(it->first, value);
264 visitor_->OnHandshakeMessage(message_);
265 Clear();
266 state_ = STATE_READING_TAG;
267 break;
269 // Save any remaining data.
270 buffer_ = reader.PeekRemainingPayload().as_string();
271 return QUIC_NO_ERROR;
274 // static
275 bool CryptoFramer::WritePadTag(QuicDataWriter* writer,
276 size_t pad_length,
277 uint32* end_offset) {
278 if (!writer->WriteUInt32(kPAD)) {
279 DCHECK(false) << "Failed to write tag.";
280 return false;
282 *end_offset += pad_length;
283 if (!writer->WriteUInt32(*end_offset)) {
284 DCHECK(false) << "Failed to write end offset.";
285 return false;
287 return true;
290 } // namespace net