Initial import of Cobalt 2.8885 2016-07-27
diff --git a/src/net/quic/crypto/crypto_framer.cc b/src/net/quic/crypto/crypto_framer.cc
new file mode 100644
index 0000000..31c26cf
--- /dev/null
+++ b/src/net/quic/crypto/crypto_framer.cc
@@ -0,0 +1,183 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/crypto/crypto_framer.h"
+
+#include "net/quic/quic_data_reader.h"
+#include "net/quic/quic_data_writer.h"
+#include "net/quic/quic_protocol.h"
+
+using base::StringPiece;
+
+namespace net {
+
+namespace {
+
+const size_t kCryptoTagSize = sizeof(uint32);
+const size_t kNumEntriesSize = sizeof(uint16);
+const size_t kValueLenSize = sizeof(uint16);
+
+}  // namespace
+
+CryptoFramer::CryptoFramer()
+    : visitor_(NULL),
+      message_tag_(0),
+      num_entries_(0),
+      values_len_(0) {
+  Clear();
+}
+
+CryptoFramer::~CryptoFramer() {}
+
+bool CryptoFramer::ProcessInput(StringPiece input) {
+  DCHECK_EQ(QUIC_NO_ERROR, error_);
+  if (error_ != QUIC_NO_ERROR) {
+    return false;
+  }
+  // Add this data to the buffer.
+  buffer_.append(input.data(), input.length());
+  QuicDataReader reader(buffer_.data(), buffer_.length());
+
+  switch (state_) {
+    case STATE_READING_TAG:
+      if (reader.BytesRemaining() < kCryptoTagSize) {
+        break;
+      }
+      reader.ReadUInt32(&message_tag_);
+      state_ = STATE_READING_NUM_ENTRIES;
+    case STATE_READING_NUM_ENTRIES:
+      if (reader.BytesRemaining() < kNumEntriesSize) {
+        break;
+      }
+      reader.ReadUInt16(&num_entries_);
+      if (num_entries_ > kMaxEntries) {
+        error_ = QUIC_CRYPTO_TOO_MANY_ENTRIES;
+        return false;
+      }
+      state_ = STATE_READING_KEY_TAGS;
+    case STATE_READING_KEY_TAGS:
+      if (reader.BytesRemaining() < num_entries_ * kCryptoTagSize) {
+        break;
+      }
+      for (int i = 0; i < num_entries_; ++i) {
+        CryptoTag tag;
+        reader.ReadUInt32(&tag);
+        if (i > 0 && tag <= tags_.back()) {
+          error_ = QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
+          return false;
+        }
+        tags_.push_back(tag);
+      }
+      state_ = STATE_READING_LENGTHS;
+    case STATE_READING_LENGTHS:
+      if (reader.BytesRemaining() < num_entries_ * kValueLenSize) {
+        break;
+      }
+      values_len_ = 0;
+      for (int i = 0; i < num_entries_; ++i) {
+        uint16 len;
+        reader.ReadUInt16(&len);
+        tag_length_map_[tags_[i]] = len;
+        values_len_ += len;
+        if (len == 0 && i != num_entries_ - 1) {
+          error_ = QUIC_CRYPTO_INVALID_VALUE_LENGTH;
+          return false;
+        }
+      }
+      state_ = STATE_READING_VALUES;
+    case STATE_READING_VALUES:
+      if (reader.BytesRemaining() < values_len_) {
+        break;
+      }
+      for (int i = 0; i < num_entries_; ++i) {
+        StringPiece value;
+        reader.ReadStringPiece(&value, tag_length_map_[tags_[i]]);
+        tag_value_map_[tags_[i]] = value;
+      }
+      CryptoHandshakeMessage message;
+      message.tag = message_tag_;
+      message.tag_value_map.swap(tag_value_map_);
+      visitor_->OnHandshakeMessage(message);
+      Clear();
+      state_ = STATE_READING_TAG;
+      break;
+  }
+  // Save any remaining data.
+  buffer_ = reader.PeekRemainingPayload().as_string();
+  return true;
+}
+
+QuicData* CryptoFramer::ConstructHandshakeMessage(
+    const CryptoHandshakeMessage& message) {
+  if (message.tag_value_map.size() > kMaxEntries) {
+    return NULL;
+  }
+  size_t len = sizeof(uint32);  // message tag
+  len += sizeof(uint16);  // number of map entries
+  CryptoTagValueMap::const_iterator it = message.tag_value_map.begin();
+  while (it != message.tag_value_map.end()) {
+    len += sizeof(uint32);  // tag
+    len += sizeof(uint16);  // value len
+    len += it->second.length(); // value
+    if (it->second.length() == 0) {
+      return NULL;
+    }
+    ++it;
+  }
+  if (message.tag_value_map.size() % 2 == 1) {
+    len += sizeof(uint16);  // padding
+  }
+
+  QuicDataWriter writer(len);
+  if (!writer.WriteUInt32(message.tag)) {
+    DCHECK(false) << "Failed to write message tag.";
+    return NULL;
+  }
+  if (!writer.WriteUInt16(message.tag_value_map.size())) {
+    DCHECK(false) << "Failed to write size.";
+    return NULL;
+  }
+  // Tags
+  for (it = message.tag_value_map.begin();
+       it != message.tag_value_map.end(); ++it) {
+    if (!writer.WriteUInt32(it->first)) {
+      DCHECK(false) << "Failed to write tag.";
+      return NULL;
+    }
+  }
+  // Lengths
+  for (it = message.tag_value_map.begin();
+       it != message.tag_value_map.end(); ++it) {
+    if (!writer.WriteUInt16(it->second.length())) {
+      DCHECK(false) << "Failed to write length.";
+      return NULL;
+    }
+  }
+  // Possible padding
+  if (message.tag_value_map.size() % 2 == 1) {
+    if (!writer.WriteUInt16(0xABAB)) {
+      DCHECK(false) << "Failed to write padding.";
+      return NULL;
+    }
+  }
+  // Values
+  for (it = message.tag_value_map.begin();
+       it != message.tag_value_map.end(); ++it) {
+    if (!writer.WriteBytes(it->second.data(), it->second.length())) {
+      DCHECK(false) << "Failed to write value.";
+      return NULL;
+    }
+  }
+  return new QuicData(writer.take(), len, true);
+}
+
+void CryptoFramer::Clear() {
+  tag_value_map_.clear();
+  tag_length_map_.clear();
+  tags_.clear();
+  error_ = QUIC_NO_ERROR;
+  state_ = STATE_READING_TAG;
+}
+
+}  // namespace net