Index: net/spdy/spdy_header_block.cc |
diff --git a/net/spdy/spdy_header_block.cc b/net/spdy/spdy_header_block.cc |
deleted file mode 100644 |
index 1cb7b13b6e8ccd2aa374ef888954d11e248aa8af..0000000000000000000000000000000000000000 |
--- a/net/spdy/spdy_header_block.cc |
+++ /dev/null |
@@ -1,399 +0,0 @@ |
-// 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/spdy/spdy_header_block.h" |
- |
-#include <string.h> |
- |
-#include <algorithm> |
-#include <utility> |
- |
-#include "base/logging.h" |
-#include "base/macros.h" |
-#include "base/values.h" |
-#include "net/base/arena.h" |
-#include "net/http/http_log_util.h" |
-#include "net/log/net_log_capture_mode.h" |
-#include "net/spdy/platform/api/spdy_estimate_memory_usage.h" |
-#include "net/spdy/platform/api/spdy_string_utils.h" |
- |
-namespace net { |
-namespace { |
- |
-// By default, linked_hash_map's internal map allocates space for 100 map |
-// buckets on construction, which is larger than necessary. Standard library |
-// unordered map implementations use a list of prime numbers to set the bucket |
-// count for a particular capacity. |kInitialMapBuckets| is chosen to reduce |
-// memory usage for small header blocks, at the cost of having to rehash for |
-// large header blocks. |
-const size_t kInitialMapBuckets = 11; |
- |
-// SpdyHeaderBlock::Storage allocates blocks of this size by default. |
-const size_t kDefaultStorageBlockSize = 2048; |
- |
-const char kCookieKey[] = "cookie"; |
-const char kNullSeparator = 0; |
- |
-SpdyStringPiece SeparatorForKey(SpdyStringPiece key) { |
- if (key == kCookieKey) { |
- static SpdyStringPiece cookie_separator = "; "; |
- return cookie_separator; |
- } else { |
- return SpdyStringPiece(&kNullSeparator, 1); |
- } |
-} |
- |
-} // namespace |
- |
-// This class provides a backing store for SpdyStringPieces. It previously used |
-// custom allocation logic, but now uses an UnsafeArena instead. It has the |
-// property that SpdyStringPieces that refer to data in Storage are never |
-// invalidated until the Storage is deleted or Clear() is called. |
-// |
-// Write operations always append to the last block. If there is not enough |
-// space to perform the write, a new block is allocated, and any unused space |
-// is wasted. |
-class SpdyHeaderBlock::Storage { |
- public: |
- Storage() : arena_(kDefaultStorageBlockSize) {} |
- ~Storage() { Clear(); } |
- |
- SpdyStringPiece Write(const SpdyStringPiece s) { |
- return SpdyStringPiece(arena_.Memdup(s.data(), s.size()), s.size()); |
- } |
- |
- // 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 SpdyStringPiece s) { |
- arena_.Free(const_cast<char*>(s.data()), s.size()); |
- } |
- |
- 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 SpdyStringPiece |
- // pointing to the region of memory. |
- SpdyStringPiece WriteFragments(const std::vector<SpdyStringPiece>& fragments, |
- SpdyStringPiece separator) { |
- if (fragments.empty()) { |
- return SpdyStringPiece(); |
- } |
- 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 SpdyStringPiece(dst, total_size); |
- } |
- |
- size_t bytes_allocated() const { return arena_.status().bytes_allocated(); } |
- |
- // TODO(xunjieli): https://crbug.com/669108. Merge this with bytes_allocated() |
- size_t EstimateMemoryUsage() const { |
- return arena_.status().bytes_allocated(); |
- } |
- |
- private: |
- UnsafeArena arena_; |
- |
- DISALLOW_COPY_AND_ASSIGN(Storage); |
-}; |
- |
-SpdyHeaderBlock::HeaderValue::HeaderValue(Storage* storage, |
- SpdyStringPiece key, |
- SpdyStringPiece 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() {} |
- |
-SpdyStringPiece SpdyHeaderBlock::HeaderValue::ConsolidatedValue() const { |
- if (fragments_.empty()) { |
- return SpdyStringPiece(); |
- } |
- if (fragments_.size() > 1) { |
- fragments_ = { |
- storage_->WriteFragments(fragments_, SeparatorForKey(pair_.first))}; |
- } |
- return fragments_[0]; |
-} |
- |
-void SpdyHeaderBlock::HeaderValue::Append(SpdyStringPiece fragment) { |
- fragments_.push_back(fragment); |
-} |
- |
-const std::pair<SpdyStringPiece, SpdyStringPiece>& |
-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, |
- SpdyHeaderBlock::MapType::iterator lookup_result, |
- const SpdyStringPiece key) |
- : block_(block), |
- storage_(storage), |
- lookup_result_(lookup_result), |
- key_(key), |
- valid_(true) {} |
- |
-SpdyHeaderBlock::ValueProxy::ValueProxy(ValueProxy&& other) |
- : block_(other.block_), |
- storage_(other.storage_), |
- lookup_result_(other.lookup_result_), |
- key_(other.key_), |
- valid_(true) { |
- other.valid_ = false; |
-} |
- |
-SpdyHeaderBlock::ValueProxy& SpdyHeaderBlock::ValueProxy::operator=( |
- SpdyHeaderBlock::ValueProxy&& other) { |
- block_ = other.block_; |
- storage_ = other.storage_; |
- lookup_result_ = other.lookup_result_; |
- key_ = other.key_; |
- valid_ = true; |
- other.valid_ = false; |
- return *this; |
-} |
- |
-SpdyHeaderBlock::ValueProxy::~ValueProxy() { |
- // If the ValueProxy is destroyed while lookup_result_ == block_->end(), |
- // the assignment operator was never used, and the block's Storage can |
- // reclaim the memory used by the key. This makes lookup-only access to |
- // SpdyHeaderBlock through operator[] memory-neutral. |
- if (valid_ && lookup_result_ == block_->end()) { |
- storage_->Rewind(key_); |
- } |
-} |
- |
-SpdyHeaderBlock::ValueProxy& SpdyHeaderBlock::ValueProxy::operator=( |
- const SpdyStringPiece value) { |
- if (lookup_result_ == block_->end()) { |
- DVLOG(1) << "Inserting: (" << key_ << ", " << value << ")"; |
- lookup_result_ = |
- block_ |
- ->emplace(std::make_pair( |
- key_, HeaderValue(storage_, key_, storage_->Write(value)))) |
- .first; |
- } else { |
- DVLOG(1) << "Updating key: " << key_ << " with value: " << value; |
- lookup_result_->second = |
- HeaderValue(storage_, key_, storage_->Write(value)); |
- } |
- return *this; |
-} |
- |
-SpdyString SpdyHeaderBlock::ValueProxy::as_string() const { |
- if (lookup_result_ == block_->end()) { |
- return ""; |
- } else { |
- return SpdyString(lookup_result_->second.value()); |
- } |
-} |
- |
-SpdyHeaderBlock::SpdyHeaderBlock() : block_(kInitialMapBuckets) {} |
- |
-SpdyHeaderBlock::SpdyHeaderBlock(SpdyHeaderBlock&& other) = default; |
- |
-SpdyHeaderBlock::~SpdyHeaderBlock() {} |
- |
-SpdyHeaderBlock& SpdyHeaderBlock::operator=(SpdyHeaderBlock&& other) { |
- block_.swap(other.block_); |
- storage_.swap(other.storage_); |
- return *this; |
-} |
- |
-SpdyHeaderBlock SpdyHeaderBlock::Clone() const { |
- SpdyHeaderBlock copy; |
- for (const auto& p : *this) { |
- copy.AppendHeader(p.first, p.second); |
- } |
- return copy; |
-} |
- |
-bool SpdyHeaderBlock::operator==(const SpdyHeaderBlock& other) const { |
- return size() == other.size() && std::equal(begin(), end(), other.begin()); |
-} |
- |
-bool SpdyHeaderBlock::operator!=(const SpdyHeaderBlock& other) const { |
- return !(operator==(other)); |
-} |
- |
-SpdyString SpdyHeaderBlock::DebugString() const { |
- if (empty()) { |
- return "{}"; |
- } |
- |
- SpdyString output = "\n{\n"; |
- for (auto it = begin(); it != end(); ++it) { |
- SpdyStrAppend(&output, " ", it->first, " ", it->second, "\n"); |
- } |
- SpdyStrAppend(&output, "}\n"); |
- return output; |
-} |
- |
-void SpdyHeaderBlock::clear() { |
- block_.clear(); |
- storage_.reset(); |
-} |
- |
-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()) { |
- DVLOG(1) << "Inserting: (" << value.first << ", " << value.second << ")"; |
- AppendHeader(value.first, value.second); |
- } else { |
- DVLOG(1) << "Updating key: " << iter->first |
- << " with value: " << value.second; |
- auto* storage = GetStorage(); |
- iter->second = |
- HeaderValue(storage, iter->first, storage->Write(value.second)); |
- } |
-} |
- |
-SpdyHeaderBlock::ValueProxy SpdyHeaderBlock::operator[]( |
- const SpdyStringPiece key) { |
- DVLOG(2) << "Operator[] saw key: " << key; |
- SpdyStringPiece out_key; |
- auto iter = block_.find(key); |
- if (iter == block_.end()) { |
- // We write the key first, to assure that the ValueProxy has a |
- // reference to a valid SpdyStringPiece in its operator=. |
- out_key = GetStorage()->Write(key); |
- DVLOG(2) << "Key written as: " << std::hex |
- << static_cast<const void*>(key.data()) << ", " << std::dec |
- << key.size(); |
- } else { |
- out_key = iter->first; |
- } |
- return ValueProxy(&block_, GetStorage(), iter, out_key); |
-} |
- |
-void SpdyHeaderBlock::AppendValueOrAddHeader(const SpdyStringPiece key, |
- const SpdyStringPiece value) { |
- auto iter = block_.find(key); |
- if (iter == block_.end()) { |
- DVLOG(1) << "Inserting: (" << key << ", " << value << ")"; |
- AppendHeader(key, value); |
- return; |
- } |
- DVLOG(1) << "Updating key: " << iter->first << "; appending value: " << value; |
- iter->second.Append(GetStorage()->Write(value)); |
-} |
- |
-size_t SpdyHeaderBlock::EstimateMemoryUsage() const { |
- // TODO(xunjieli): https://crbug.com/669108. Also include |block_| when EMU() |
- // supports linked_hash_map. |
- return SpdyEstimateMemoryUsage(storage_); |
-} |
- |
-void SpdyHeaderBlock::AppendHeader(const SpdyStringPiece key, |
- const SpdyStringPiece value) { |
- auto* storage = GetStorage(); |
- auto backed_key = storage->Write(key); |
- block_.emplace(std::make_pair( |
- backed_key, HeaderValue(storage, backed_key, storage->Write(value)))); |
-} |
- |
-SpdyHeaderBlock::Storage* SpdyHeaderBlock::GetStorage() { |
- if (!storage_) { |
- storage_.reset(new Storage); |
- } |
- return storage_.get(); |
-} |
- |
-std::unique_ptr<base::Value> SpdyHeaderBlockNetLogCallback( |
- const SpdyHeaderBlock* headers, |
- NetLogCaptureMode capture_mode) { |
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
- base::DictionaryValue* headers_dict = new base::DictionaryValue(); |
- for (SpdyHeaderBlock::const_iterator it = headers->begin(); |
- it != headers->end(); ++it) { |
- headers_dict->SetWithoutPathExpansion( |
- it->first.as_string(), |
- new base::Value(ElideHeaderValueForNetLog( |
- capture_mode, it->first.as_string(), it->second.as_string()))); |
- } |
- dict->Set("headers", headers_dict); |
- return std::move(dict); |
-} |
- |
-bool SpdyHeaderBlockFromNetLogParam( |
- const base::Value* event_param, |
- SpdyHeaderBlock* headers) { |
- headers->clear(); |
- |
- const base::DictionaryValue* dict = NULL; |
- const base::DictionaryValue* header_dict = NULL; |
- |
- if (!event_param || |
- !event_param->GetAsDictionary(&dict) || |
- !dict->GetDictionary("headers", &header_dict)) { |
- return false; |
- } |
- |
- for (base::DictionaryValue::Iterator it(*header_dict); !it.IsAtEnd(); |
- it.Advance()) { |
- SpdyString value; |
- if (!it.value().GetAsString(&value)) { |
- headers->clear(); |
- return false; |
- } |
- (*headers)[it.key()] = value; |
- } |
- 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<SpdyStringPiece>& fragments, |
- SpdyStringPiece 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 |