| Index: net/spdy/spdy_header_block.cc
|
| diff --git a/net/spdy/spdy_header_block.cc b/net/spdy/spdy_header_block.cc
|
| index 4e36b8927b57529a3c72405c2a95bdb51e01748f..6cbd6ba645c4585a3126099322effb3f9525c968 100644
|
| --- a/net/spdy/spdy_header_block.cc
|
| +++ b/net/spdy/spdy_header_block.cc
|
| @@ -19,6 +19,7 @@
|
| using base::StringPiece;
|
| using std::dec;
|
| using std::hex;
|
| +using std::make_pair;
|
| using std::max;
|
| using std::min;
|
| using std::string;
|
| @@ -30,6 +31,16 @@ namespace {
|
| const size_t kDefaultStorageBlockSize = 2048;
|
|
|
| const char kCookieKey[] = "cookie";
|
| +const char kNullSeparator = 0;
|
| +
|
| +StringPiece SeparatorForKey(StringPiece key) {
|
| + if (key == kCookieKey) {
|
| + static StringPiece cookie_separator = "; ";
|
| + return cookie_separator;
|
| + } else {
|
| + return StringPiece(&kNullSeparator, 1);
|
| + }
|
| +}
|
|
|
| } // namespace
|
|
|
| @@ -50,24 +61,6 @@ class SpdyHeaderBlock::Storage {
|
| return StringPiece(arena_.Memdup(s.data(), s.size()), s.size());
|
| }
|
|
|
| - // Given value, a string already in the arena, perform a realloc and append
|
| - // separator and more to the end of the value's new location. If value is the
|
| - // most recently added string (via Write), then UnsafeArena will not copy the
|
| - // existing value but instead will increase the space reserved for value.
|
| - StringPiece Realloc(StringPiece value,
|
| - StringPiece separator,
|
| - StringPiece more) {
|
| - size_t total_length = value.size() + separator.size() + more.size();
|
| - char* ptr = const_cast<char*>(value.data());
|
| - ptr = arena_.Realloc(ptr, value.size(), total_length);
|
| - StringPiece result(ptr, total_length);
|
| - ptr += value.size();
|
| - memcpy(ptr, separator.data(), separator.size());
|
| - ptr += separator.size();
|
| - memcpy(ptr, more.data(), more.size());
|
| - return result;
|
| - }
|
| -
|
| // If |s| points to the most recent allocation from arena_, the arena will
|
| // reclaim the memory. Otherwise, this method is a no-op.
|
| void Rewind(const StringPiece s) {
|
| @@ -76,10 +69,77 @@ class SpdyHeaderBlock::Storage {
|
|
|
| void Clear() { arena_.Reset(); }
|
|
|
| + // Given a list of fragments and a separator, writes the fragments joined by
|
| + // the separator to a contiguous region of memory. Returns a StringPiece
|
| + // pointing to the region of memory.
|
| + StringPiece WriteFragments(const std::vector<StringPiece>& fragments,
|
| + StringPiece separator) {
|
| + if (fragments.empty()) {
|
| + return StringPiece();
|
| + }
|
| + size_t total_size = separator.size() * (fragments.size() - 1);
|
| + for (const auto fragment : fragments) {
|
| + total_size += fragment.size();
|
| + }
|
| + char* dst = arena_.Alloc(total_size);
|
| + size_t written = Join(dst, fragments, separator);
|
| + DCHECK_EQ(written, total_size);
|
| + return StringPiece(dst, total_size);
|
| + }
|
| +
|
| + size_t bytes_allocated() const { return arena_.status().bytes_allocated(); }
|
| +
|
| private:
|
| UnsafeArena arena_;
|
| };
|
|
|
| +SpdyHeaderBlock::HeaderValue::HeaderValue(Storage* storage,
|
| + StringPiece key,
|
| + StringPiece initial_value)
|
| + : storage_(storage), fragments_({initial_value}), pair_({key, {}}) {}
|
| +
|
| +SpdyHeaderBlock::HeaderValue::HeaderValue(HeaderValue&& other)
|
| + : storage_(other.storage_),
|
| + fragments_(std::move(other.fragments_)),
|
| + pair_(std::move(other.pair_)) {}
|
| +
|
| +SpdyHeaderBlock::HeaderValue& SpdyHeaderBlock::HeaderValue::operator=(
|
| + HeaderValue&& other) {
|
| + storage_ = other.storage_;
|
| + fragments_ = std::move(other.fragments_);
|
| + pair_ = std::move(other.pair_);
|
| + return *this;
|
| +}
|
| +
|
| +SpdyHeaderBlock::HeaderValue::~HeaderValue() {}
|
| +
|
| +StringPiece SpdyHeaderBlock::HeaderValue::ConsolidatedValue() const {
|
| + if (fragments_.empty()) {
|
| + return StringPiece();
|
| + }
|
| + if (fragments_.size() > 1) {
|
| + fragments_ = {
|
| + storage_->WriteFragments(fragments_, SeparatorForKey(pair_.first))};
|
| + }
|
| + return fragments_[0];
|
| +}
|
| +
|
| +void SpdyHeaderBlock::HeaderValue::Append(StringPiece fragment) {
|
| + fragments_.push_back(fragment);
|
| +}
|
| +
|
| +const std::pair<StringPiece, StringPiece>&
|
| +SpdyHeaderBlock::HeaderValue::as_pair() const {
|
| + pair_.second = ConsolidatedValue();
|
| + return pair_;
|
| +}
|
| +
|
| +SpdyHeaderBlock::iterator::iterator(MapType::const_iterator it) : it_(it) {}
|
| +
|
| +SpdyHeaderBlock::iterator::iterator(const iterator& other) : it_(other.it_) {}
|
| +
|
| +SpdyHeaderBlock::iterator::~iterator() {}
|
| +
|
| SpdyHeaderBlock::ValueProxy::ValueProxy(
|
| SpdyHeaderBlock::MapType* block,
|
| SpdyHeaderBlock::Storage* storage,
|
| @@ -89,8 +149,7 @@ SpdyHeaderBlock::ValueProxy::ValueProxy(
|
| storage_(storage),
|
| lookup_result_(lookup_result),
|
| key_(key),
|
| - valid_(true) {
|
| -}
|
| + valid_(true) {}
|
|
|
| SpdyHeaderBlock::ValueProxy::ValueProxy(ValueProxy&& other)
|
| : block_(other.block_),
|
| @@ -127,10 +186,14 @@ SpdyHeaderBlock::ValueProxy& SpdyHeaderBlock::ValueProxy::operator=(
|
| if (lookup_result_ == block_->end()) {
|
| DVLOG(1) << "Inserting: (" << key_ << ", " << value << ")";
|
| lookup_result_ =
|
| - block_->insert(std::make_pair(key_, storage_->Write(value))).first;
|
| + block_
|
| + ->emplace(make_pair(
|
| + key_, HeaderValue(storage_, key_, storage_->Write(value))))
|
| + .first;
|
| } else {
|
| DVLOG(1) << "Updating key: " << key_ << " with value: " << value;
|
| - lookup_result_->second = storage_->Write(value);
|
| + lookup_result_->second =
|
| + HeaderValue(storage_, key_, storage_->Write(value));
|
| }
|
| return *this;
|
| }
|
| @@ -139,7 +202,7 @@ string SpdyHeaderBlock::ValueProxy::as_string() const {
|
| if (lookup_result_ == block_->end()) {
|
| return "";
|
| } else {
|
| - return lookup_result_->second.as_string();
|
| + return lookup_result_->second.value().as_string();
|
| }
|
| }
|
|
|
| @@ -160,8 +223,8 @@ SpdyHeaderBlock& SpdyHeaderBlock::operator=(SpdyHeaderBlock&& other) {
|
|
|
| SpdyHeaderBlock SpdyHeaderBlock::Clone() const {
|
| SpdyHeaderBlock copy;
|
| - for (auto iter : *this) {
|
| - copy.AppendHeader(iter.first, iter.second);
|
| + for (const auto& p : *this) {
|
| + copy.AppendHeader(p.first, p.second);
|
| }
|
| return copy;
|
| }
|
| @@ -181,7 +244,7 @@ string SpdyHeaderBlock::DebugString() const {
|
| string output = "\n{\n";
|
| for (auto it = begin(); it != end(); ++it) {
|
| output +=
|
| - " " + it->first.as_string() + ":" + it->second.as_string() + "\n";
|
| + " " + it->first.as_string() + " " + it->second.as_string() + "\n";
|
| }
|
| output.append("}\n");
|
| return output;
|
| @@ -192,8 +255,7 @@ void SpdyHeaderBlock::clear() {
|
| storage_.reset();
|
| }
|
|
|
| -void SpdyHeaderBlock::insert(
|
| - const SpdyHeaderBlock::MapType::value_type& value) {
|
| +void SpdyHeaderBlock::insert(const SpdyHeaderBlock::value_type& value) {
|
| // TODO(birenroy): Write new value in place of old value, if it fits.
|
| auto iter = block_.find(value.first);
|
| if (iter == block_.end()) {
|
| @@ -202,7 +264,9 @@ void SpdyHeaderBlock::insert(
|
| } else {
|
| DVLOG(1) << "Updating key: " << iter->first
|
| << " with value: " << value.second;
|
| - iter->second = GetStorage()->Write(value.second);
|
| + auto storage = GetStorage();
|
| + iter->second =
|
| + HeaderValue(storage, iter->first, storage->Write(value.second));
|
| }
|
| }
|
|
|
| @@ -232,16 +296,15 @@ void SpdyHeaderBlock::AppendValueOrAddHeader(const StringPiece key,
|
| return;
|
| }
|
| DVLOG(1) << "Updating key: " << iter->first << "; appending value: " << value;
|
| - StringPiece separator("", 1);
|
| - if (key == kCookieKey) {
|
| - separator = "; ";
|
| - }
|
| - iter->second = GetStorage()->Realloc(iter->second, separator, value);
|
| + iter->second.Append(GetStorage()->Write(value));
|
| }
|
|
|
| void SpdyHeaderBlock::AppendHeader(const StringPiece key,
|
| const StringPiece value) {
|
| - block_.emplace(GetStorage()->Write(key), GetStorage()->Write(value));
|
| + auto storage = GetStorage();
|
| + auto backed_key = storage->Write(key);
|
| + block_.emplace(make_pair(
|
| + backed_key, HeaderValue(storage, backed_key, storage->Write(value))));
|
| }
|
|
|
| SpdyHeaderBlock::Storage* SpdyHeaderBlock::GetStorage() {
|
| @@ -293,4 +356,31 @@ bool SpdyHeaderBlockFromNetLogParam(
|
| return true;
|
| }
|
|
|
| +size_t SpdyHeaderBlock::bytes_allocated() const {
|
| + if (storage_ == nullptr) {
|
| + return 0;
|
| + } else {
|
| + return storage_->bytes_allocated();
|
| + }
|
| +}
|
| +
|
| +size_t Join(char* dst,
|
| + const std::vector<StringPiece>& fragments,
|
| + StringPiece separator) {
|
| + if (fragments.empty()) {
|
| + return 0;
|
| + }
|
| + auto original_dst = dst;
|
| + auto it = fragments.begin();
|
| + memcpy(dst, it->data(), it->size());
|
| + dst += it->size();
|
| + for (++it; it != fragments.end(); ++it) {
|
| + memcpy(dst, separator.data(), separator.size());
|
| + dst += separator.size();
|
| + memcpy(dst, it->data(), it->size());
|
| + dst += it->size();
|
| + }
|
| + return dst - original_dst;
|
| +}
|
| +
|
| } // namespace net
|
|
|