Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(397)

Unified Diff: net/spdy/spdy_header_block.h

Issue 2611173004: Modify SpdyHeaderBlock's internals to consolidate header values only on first access. (Closed)
Patch Set: Nit. Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/spdy/spdy_header_block.h
diff --git a/net/spdy/spdy_header_block.h b/net/spdy/spdy_header_block.h
index fef27e8f51a6577b7d725635f1ae38751c62093e..fe8827f5c8d06aba8c0932439c06aaea956dab3e 100644
--- a/net/spdy/spdy_header_block.h
+++ b/net/spdy/spdy_header_block.h
@@ -11,6 +11,7 @@
#include <map>
#include <memory>
#include <string>
+#include <vector>
#include "base/macros.h"
#include "base/strings/string_piece.h"
@@ -27,6 +28,7 @@ namespace net {
class NetLogCaptureMode;
namespace test {
+class SpdyHeaderBlockPeer;
class ValueProxyPeer;
}
@@ -43,16 +45,93 @@ class ValueProxyPeer;
// It's expected that keys are rarely deleted from a SpdyHeaderBlock.
class NET_EXPORT SpdyHeaderBlock {
private:
- using MapType = linked_hash_map<base::StringPiece,
- base::StringPiece,
- base::StringPieceHash>;
class Storage;
+ // Stores a list of value fragments that can be joined later with a
+ // key-dependent separator.
+ class NET_EXPORT HeaderValue {
+ public:
+ HeaderValue(Storage* storage,
+ base::StringPiece key,
+ base::StringPiece initial_value);
+
+ // Moves are allowed.
+ HeaderValue(HeaderValue&& other);
+ HeaderValue& operator=(HeaderValue&& other);
+
+ // Copies are not.
+ HeaderValue(const HeaderValue& other) = delete;
+ HeaderValue& operator=(const HeaderValue& other) = delete;
+
+ ~HeaderValue();
+
+ // Consumes at most |fragment.size()| bytes of memory.
+ void Append(base::StringPiece fragment);
+
+ base::StringPiece value() const { return as_pair().second; }
+ const std::pair<base::StringPiece, base::StringPiece>& as_pair() const;
+
+ private:
+ // May allocate a large contiguous region of memory to hold the concatenated
+ // fragments and separators.
+ base::StringPiece ConsolidatedValue() const;
+
+ mutable Storage* storage_;
+ mutable std::vector<base::StringPiece> fragments_;
+ // The first element is the key; the second is the consolidated value.
+ mutable std::pair<base::StringPiece, base::StringPiece> pair_;
+ };
+
+ typedef linked_hash_map<base::StringPiece, HeaderValue, base::StringPieceHash>
+ MapType;
+
public:
- using iterator = MapType::iterator;
- using const_iterator = MapType::const_iterator;
- using value_type = MapType::value_type;
- using reverse_iterator = MapType::reverse_iterator;
+ typedef std::pair<base::StringPiece, base::StringPiece> value_type;
+
+ // Provides iteration over a sequence of std::pair<StringPiece, StringPiece>,
+ // even though the underlying MapType::value_type is different. Dereferencing
+ // the iterator will result in memory allocation for multi-value headers.
+ class NET_EXPORT iterator {
+ public:
+ // The following type definitions fulfill the requirements for iterator
+ // implementations.
+ typedef std::pair<base::StringPiece, base::StringPiece> value_type;
+ typedef value_type& reference;
+ typedef value_type* pointer;
+ typedef std::forward_iterator_tag iterator_category;
+ typedef MapType::iterator::difference_type difference_type;
+
+ // In practice, this iterator only offers access to const value_type.
+ typedef const value_type& const_reference;
+ typedef const value_type* const_pointer;
+
+ explicit iterator(MapType::const_iterator it);
+ iterator(const iterator& other);
+ ~iterator();
+
+ // This will result in memory allocation if the value consists of multiple
+ // fragments.
+ const_reference operator*() const { return it_->second.as_pair(); }
+
+ const_pointer operator->() const { return &(this->operator*()); }
+ bool operator==(const iterator& it) const { return it_ == it.it_; }
+ bool operator!=(const iterator& it) const { return !(*this == it); }
+
+ iterator& operator++() {
+ it_++;
+ return *this;
+ }
+
+ iterator operator++(int) {
+ auto ret = *this;
+ this->operator++();
+ return ret;
+ }
+
+ private:
+ MapType::const_iterator it_;
+ };
+ typedef iterator const_iterator;
class ValueProxy;
@@ -72,16 +151,16 @@ class NET_EXPORT SpdyHeaderBlock {
// keys and values.
std::string DebugString() const;
- // These methods delegate to our MapType member.
- iterator begin() { return block_.begin(); }
- iterator end() { return block_.end(); }
- const_iterator begin() const { return block_.begin(); }
- const_iterator end() const { return block_.end(); }
+ iterator begin() { return iterator(block_.begin()); }
+ iterator end() { return iterator(block_.end()); }
+ const_iterator begin() const { return const_iterator(block_.begin()); }
+ const_iterator end() const { return const_iterator(block_.end()); }
bool empty() const { return block_.empty(); }
size_t size() const { return block_.size(); }
- iterator find(base::StringPiece key) { return block_.find(key); }
- const_iterator find(base::StringPiece key) const { return block_.find(key); }
- reverse_iterator rbegin() { return block_.rbegin(); }
+ iterator find(base::StringPiece key) { return iterator(block_.find(key)); }
+ const_iterator find(base::StringPiece key) const {
+ return const_iterator(block_.find(key));
+ }
void erase(base::StringPiece key) { block_.erase(key); }
// Clears both our MapType member and the memory used to hold headers.
@@ -91,7 +170,7 @@ class NET_EXPORT SpdyHeaderBlock {
// If key already exists in the block, replaces the value of that key. Else
// adds a new header to the end of the block.
- void insert(const MapType::value_type& value);
+ void insert(const value_type& value);
// If a header with the key is already present, then append the value to the
// existing header value, NUL ("\0") separated unless the key is cookie, in
@@ -140,8 +219,11 @@ class NET_EXPORT SpdyHeaderBlock {
};
private:
+ friend class test::SpdyHeaderBlockPeer;
+
void AppendHeader(const base::StringPiece key, const base::StringPiece value);
Storage* GetStorage();
+ size_t bytes_allocated() const;
// StringPieces held by |block_| point to memory owned by |*storage_|.
// |storage_| might be nullptr as long as |block_| is empty.
@@ -149,6 +231,12 @@ class NET_EXPORT SpdyHeaderBlock {
std::unique_ptr<Storage> storage_;
};
+// Writes |fragments| to |dst|, joined by |separator|. |dst| must be large
+// enough to hold the result. Returns the number of bytes written.
+NET_EXPORT size_t Join(char* dst,
+ const std::vector<base::StringPiece>& fragments,
+ base::StringPiece separator);
+
// Converts a SpdyHeaderBlock into NetLog event parameters.
NET_EXPORT std::unique_ptr<base::Value> SpdyHeaderBlockNetLogCallback(
const SpdyHeaderBlock* headers,

Powered by Google App Engine
This is Rietveld 408576698