Index: net/spdy/hpack/hpack_encoder.cc |
diff --git a/net/spdy/hpack/hpack_encoder.cc b/net/spdy/hpack/hpack_encoder.cc |
deleted file mode 100644 |
index 48129d11819e9d5c031f67463c9afab9c176f7d1..0000000000000000000000000000000000000000 |
--- a/net/spdy/hpack/hpack_encoder.cc |
+++ /dev/null |
@@ -1,371 +0,0 @@ |
-// Copyright 2014 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/hpack/hpack_encoder.h" |
- |
-#include <algorithm> |
-#include <limits> |
- |
-#include "base/logging.h" |
-#include "base/memory/ptr_util.h" |
-#include "net/spdy/hpack/hpack_constants.h" |
-#include "net/spdy/hpack/hpack_header_table.h" |
-#include "net/spdy/hpack/hpack_huffman_table.h" |
-#include "net/spdy/hpack/hpack_output_stream.h" |
-#include "net/spdy/platform/api/spdy_estimate_memory_usage.h" |
- |
-namespace net { |
- |
-class HpackEncoder::RepresentationIterator { |
- public: |
- // |pseudo_headers| and |regular_headers| must outlive the iterator. |
- RepresentationIterator(const Representations& pseudo_headers, |
- const Representations& regular_headers) |
- : pseudo_begin_(pseudo_headers.begin()), |
- pseudo_end_(pseudo_headers.end()), |
- regular_begin_(regular_headers.begin()), |
- regular_end_(regular_headers.end()) {} |
- |
- // |headers| must outlive the iterator. |
- explicit RepresentationIterator(const Representations& headers) |
- : pseudo_begin_(headers.begin()), |
- pseudo_end_(headers.end()), |
- regular_begin_(headers.end()), |
- regular_end_(headers.end()) {} |
- |
- bool HasNext() { |
- return pseudo_begin_ != pseudo_end_ || regular_begin_ != regular_end_; |
- } |
- |
- const Representation Next() { |
- if (pseudo_begin_ != pseudo_end_) { |
- return *pseudo_begin_++; |
- } else { |
- return *regular_begin_++; |
- } |
- } |
- |
- private: |
- Representations::const_iterator pseudo_begin_; |
- Representations::const_iterator pseudo_end_; |
- Representations::const_iterator regular_begin_; |
- Representations::const_iterator regular_end_; |
-}; |
- |
-namespace { |
- |
-// The default header listener. |
-void NoOpListener(SpdyStringPiece /*name*/, SpdyStringPiece /*value*/) {} |
- |
-// The default HPACK indexing policy. |
-bool DefaultPolicy(SpdyStringPiece name, SpdyStringPiece /* value */) { |
- if (name.empty()) { |
- return false; |
- } |
- // :authority is always present and rarely changes, and has moderate |
- // length, therefore it makes a lot of sense to index (insert in the |
- // dynamic table). |
- if (name[0] == kPseudoHeaderPrefix) { |
- return name == ":authority"; |
- } |
- return true; |
-} |
- |
-} // namespace |
- |
-HpackEncoder::HpackEncoder(const HpackHuffmanTable& table) |
- : output_stream_(), |
- huffman_table_(table), |
- min_table_size_setting_received_(std::numeric_limits<size_t>::max()), |
- listener_(NoOpListener), |
- should_index_(DefaultPolicy), |
- enable_compression_(true), |
- should_emit_table_size_(false) {} |
- |
-HpackEncoder::~HpackEncoder() {} |
- |
-void HpackEncoder::EncodeHeaderSet(const Representations& representations, |
- SpdyString* output) { |
- RepresentationIterator iter(representations); |
- EncodeRepresentations(&iter, output); |
-} |
- |
-bool HpackEncoder::EncodeHeaderSet(const SpdyHeaderBlock& header_set, |
- SpdyString* output) { |
- // Separate header set into pseudo-headers and regular headers. |
- Representations pseudo_headers; |
- Representations regular_headers; |
- bool found_cookie = false; |
- for (const auto& header : header_set) { |
- if (!found_cookie && header.first == "cookie") { |
- // Note that there can only be one "cookie" header, because header_set is |
- // a map. |
- found_cookie = true; |
- CookieToCrumbs(header, ®ular_headers); |
- } else if (!header.first.empty() && |
- header.first[0] == kPseudoHeaderPrefix) { |
- DecomposeRepresentation(header, &pseudo_headers); |
- } else { |
- DecomposeRepresentation(header, ®ular_headers); |
- } |
- } |
- |
- { |
- RepresentationIterator iter(pseudo_headers, regular_headers); |
- EncodeRepresentations(&iter, output); |
- } |
- return true; |
-} |
- |
-void HpackEncoder::ApplyHeaderTableSizeSetting(size_t size_setting) { |
- if (size_setting == header_table_.settings_size_bound()) { |
- return; |
- } |
- if (size_setting < header_table_.settings_size_bound()) { |
- min_table_size_setting_received_ = |
- std::min(size_setting, min_table_size_setting_received_); |
- } |
- header_table_.SetSettingsHeaderTableSize(size_setting); |
- should_emit_table_size_ = true; |
-} |
- |
-size_t HpackEncoder::EstimateMemoryUsage() const { |
- // |huffman_table_| is a singleton. It's accounted for in spdy_session_pool.cc |
- return SpdyEstimateMemoryUsage(header_table_) + |
- SpdyEstimateMemoryUsage(output_stream_); |
-} |
- |
-void HpackEncoder::EncodeRepresentations(RepresentationIterator* iter, |
- SpdyString* output) { |
- MaybeEmitTableSize(); |
- while (iter->HasNext()) { |
- const auto header = iter->Next(); |
- listener_(header.first, header.second); |
- if (enable_compression_) { |
- const HpackEntry* entry = |
- header_table_.GetByNameAndValue(header.first, header.second); |
- if (entry != nullptr) { |
- EmitIndex(entry); |
- } else if (should_index_(header.first, header.second)) { |
- EmitIndexedLiteral(header); |
- } else { |
- EmitNonIndexedLiteral(header); |
- } |
- } else { |
- EmitNonIndexedLiteral(header); |
- } |
- } |
- |
- output_stream_.TakeString(output); |
-} |
- |
-void HpackEncoder::EmitIndex(const HpackEntry* entry) { |
- DVLOG(2) << "Emitting index " << header_table_.IndexOf(entry); |
- output_stream_.AppendPrefix(kIndexedOpcode); |
- output_stream_.AppendUint32(header_table_.IndexOf(entry)); |
-} |
- |
-void HpackEncoder::EmitIndexedLiteral(const Representation& representation) { |
- DVLOG(2) << "Emitting indexed literal: (" << representation.first << ", " |
- << representation.second << ")"; |
- output_stream_.AppendPrefix(kLiteralIncrementalIndexOpcode); |
- EmitLiteral(representation); |
- header_table_.TryAddEntry(representation.first, representation.second); |
-} |
- |
-void HpackEncoder::EmitNonIndexedLiteral(const Representation& representation) { |
- DVLOG(2) << "Emitting nonindexed literal: (" << representation.first << ", " |
- << representation.second << ")"; |
- output_stream_.AppendPrefix(kLiteralNoIndexOpcode); |
- output_stream_.AppendUint32(0); |
- EmitString(representation.first); |
- EmitString(representation.second); |
-} |
- |
-void HpackEncoder::EmitLiteral(const Representation& representation) { |
- const HpackEntry* name_entry = header_table_.GetByName(representation.first); |
- if (name_entry != nullptr) { |
- output_stream_.AppendUint32(header_table_.IndexOf(name_entry)); |
- } else { |
- output_stream_.AppendUint32(0); |
- EmitString(representation.first); |
- } |
- EmitString(representation.second); |
-} |
- |
-void HpackEncoder::EmitString(SpdyStringPiece str) { |
- size_t encoded_size = |
- enable_compression_ ? huffman_table_.EncodedSize(str) : str.size(); |
- if (encoded_size < str.size()) { |
- DVLOG(2) << "Emitted Huffman-encoded string of length " << encoded_size; |
- output_stream_.AppendPrefix(kStringLiteralHuffmanEncoded); |
- output_stream_.AppendUint32(encoded_size); |
- huffman_table_.EncodeString(str, &output_stream_); |
- } else { |
- DVLOG(2) << "Emitted literal string of length " << str.size(); |
- output_stream_.AppendPrefix(kStringLiteralIdentityEncoded); |
- output_stream_.AppendUint32(str.size()); |
- output_stream_.AppendBytes(str); |
- } |
-} |
- |
-void HpackEncoder::MaybeEmitTableSize() { |
- if (!should_emit_table_size_) { |
- return; |
- } |
- const size_t current_size = CurrentHeaderTableSizeSetting(); |
- DVLOG(1) << "MaybeEmitTableSize current_size=" << current_size; |
- DVLOG(1) << "MaybeEmitTableSize min_table_size_setting_received_=" |
- << min_table_size_setting_received_; |
- if (min_table_size_setting_received_ < current_size) { |
- output_stream_.AppendPrefix(kHeaderTableSizeUpdateOpcode); |
- output_stream_.AppendUint32(min_table_size_setting_received_); |
- } |
- output_stream_.AppendPrefix(kHeaderTableSizeUpdateOpcode); |
- output_stream_.AppendUint32(current_size); |
- min_table_size_setting_received_ = std::numeric_limits<size_t>::max(); |
- should_emit_table_size_ = false; |
-} |
- |
-// static |
-void HpackEncoder::CookieToCrumbs(const Representation& cookie, |
- Representations* out) { |
- // See Section 8.1.2.5. "Compressing the Cookie Header Field" in the HTTP/2 |
- // specification at https://tools.ietf.org/html/draft-ietf-httpbis-http2-14. |
- // Cookie values are split into individually-encoded HPACK representations. |
- SpdyStringPiece cookie_value = cookie.second; |
- // Consume leading and trailing whitespace if present. |
- SpdyStringPiece::size_type first = cookie_value.find_first_not_of(" \t"); |
- SpdyStringPiece::size_type last = cookie_value.find_last_not_of(" \t"); |
- if (first == SpdyStringPiece::npos) { |
- cookie_value = SpdyStringPiece(); |
- } else { |
- cookie_value = cookie_value.substr(first, (last - first) + 1); |
- } |
- for (size_t pos = 0;;) { |
- size_t end = cookie_value.find(";", pos); |
- |
- if (end == SpdyStringPiece::npos) { |
- out->push_back(std::make_pair(cookie.first, cookie_value.substr(pos))); |
- break; |
- } |
- out->push_back( |
- std::make_pair(cookie.first, cookie_value.substr(pos, end - pos))); |
- |
- // Consume next space if present. |
- pos = end + 1; |
- if (pos != cookie_value.size() && cookie_value[pos] == ' ') { |
- pos++; |
- } |
- } |
-} |
- |
-// static |
-void HpackEncoder::DecomposeRepresentation(const Representation& header_field, |
- Representations* out) { |
- size_t pos = 0; |
- size_t end = 0; |
- while (end != SpdyStringPiece::npos) { |
- end = header_field.second.find('\0', pos); |
- out->push_back(std::make_pair( |
- header_field.first, |
- header_field.second.substr( |
- pos, end == SpdyStringPiece::npos ? end : end - pos))); |
- pos = end + 1; |
- } |
-} |
- |
-// static |
-void HpackEncoder::GatherRepresentation(const Representation& header_field, |
- Representations* out) { |
- out->push_back(std::make_pair(header_field.first, header_field.second)); |
-} |
- |
-// Iteratively encodes a SpdyHeaderBlock. |
-class HpackEncoder::Encoderator : public ProgressiveEncoder { |
- public: |
- Encoderator(const SpdyHeaderBlock& header_set, HpackEncoder* encoder); |
- |
- // Encoderator is neither copyable nor movable. |
- Encoderator(const Encoderator&) = delete; |
- Encoderator& operator=(const Encoderator&) = delete; |
- |
- // Returns true iff more remains to encode. |
- bool HasNext() const override { return has_next_; } |
- |
- // Encodes up to max_encoded_bytes of the current header block into the |
- // given output string. |
- void Next(size_t max_encoded_bytes, SpdyString* output) override; |
- |
- private: |
- HpackEncoder* encoder_; |
- std::unique_ptr<RepresentationIterator> header_it_; |
- Representations pseudo_headers_; |
- Representations regular_headers_; |
- bool has_next_; |
-}; |
- |
-HpackEncoder::Encoderator::Encoderator(const SpdyHeaderBlock& header_set, |
- HpackEncoder* encoder) |
- : encoder_(encoder), has_next_(true) { |
- // Separate header set into pseudo-headers and regular headers. |
- const bool use_compression = encoder_->enable_compression_; |
- bool found_cookie = false; |
- for (const auto& header : header_set) { |
- if (!found_cookie && header.first == "cookie") { |
- // Note that there can only be one "cookie" header, because header_set |
- // is a map. |
- found_cookie = true; |
- CookieToCrumbs(header, ®ular_headers_); |
- } else if (!header.first.empty() && |
- header.first[0] == kPseudoHeaderPrefix) { |
- use_compression ? DecomposeRepresentation(header, &pseudo_headers_) |
- : GatherRepresentation(header, &pseudo_headers_); |
- } else { |
- use_compression ? DecomposeRepresentation(header, ®ular_headers_) |
- : GatherRepresentation(header, ®ular_headers_); |
- } |
- } |
- header_it_ = base::MakeUnique<RepresentationIterator>(pseudo_headers_, |
- regular_headers_); |
- |
- encoder_->MaybeEmitTableSize(); |
-} |
- |
-void HpackEncoder::Encoderator::Next(size_t max_encoded_bytes, |
- SpdyString* output) { |
- SPDY_BUG_IF(!has_next_) |
- << "Encoderator::Next called with nothing left to encode."; |
- const bool use_compression = encoder_->enable_compression_; |
- |
- // Encode up to max_encoded_bytes of headers. |
- while (header_it_->HasNext() && |
- encoder_->output_stream_.size() <= max_encoded_bytes) { |
- const Representation header = header_it_->Next(); |
- encoder_->listener_(header.first, header.second); |
- if (use_compression) { |
- const HpackEntry* entry = encoder_->header_table_.GetByNameAndValue( |
- header.first, header.second); |
- if (entry != nullptr) { |
- encoder_->EmitIndex(entry); |
- } else if (encoder_->should_index_(header.first, header.second)) { |
- encoder_->EmitIndexedLiteral(header); |
- } else { |
- encoder_->EmitNonIndexedLiteral(header); |
- } |
- } else { |
- encoder_->EmitNonIndexedLiteral(header); |
- } |
- } |
- |
- has_next_ = encoder_->output_stream_.size() > max_encoded_bytes; |
- encoder_->output_stream_.BoundedTakeString(max_encoded_bytes, output); |
-} |
- |
-std::unique_ptr<HpackEncoder::ProgressiveEncoder> HpackEncoder::EncodeHeaderSet( |
- const SpdyHeaderBlock& header_set) { |
- return base::MakeUnique<Encoderator>(header_set, this); |
-} |
- |
-} // namespace net |