Index: net/spdy/hpack_encoder.cc |
diff --git a/net/spdy/hpack_encoder.cc b/net/spdy/hpack_encoder.cc |
index 735e8c0b48019799255f94a880427d6bd51087a7..6cb8fad954161470b543eb8ddfc4e2ea194d27a7 100644 |
--- a/net/spdy/hpack_encoder.cc |
+++ b/net/spdy/hpack_encoder.cc |
@@ -27,33 +27,65 @@ HpackEncoder::~HpackEncoder() {} |
bool HpackEncoder::EncodeHeaderSet(const std::map<string, string>& header_set, |
string* output) { |
- // Flatten & crumble headers into an ordered list of representations. |
- Representations full_set; |
+ // Separate header set into pseudo-headers and regular headers. |
+ Representations pseudo_headers; |
+ Representations regular_headers; |
for (std::map<string, string>::const_iterator it = header_set.begin(); |
it != header_set.end(); ++it) { |
if (it->first == "cookie") { |
- // |CookieToCrumbs()| produces ordered crumbs. |
- CookieToCrumbs(*it, &full_set); |
+ // Note that there can only be one "cookie" header, because header_set is |
+ // a map. |
+ CookieToCrumbs(*it, ®ular_headers); |
+ } else if (it->first[0] == kPseudoHeaderPrefix) { |
+ pseudo_headers.push_back(make_pair( |
+ StringPiece(it->first), StringPiece(it->second))); |
} else { |
- // Note std::map guarantees representations are ordered. |
- full_set.push_back(make_pair( |
+ regular_headers.push_back(make_pair( |
StringPiece(it->first), StringPiece(it->second))); |
} |
} |
- // Walk this ordered list and encode entries. |
- for (Representations::const_iterator it = full_set.begin(); |
- it != full_set.end(); ++it) { |
+ // Encode pseudo-headers. |
+ for (Representations::const_iterator it = pseudo_headers.begin(); |
+ it != pseudo_headers.end(); ++it) { |
+ HpackEntry* entry = header_table_.GetByNameAndValue(it->first, it->second); |
+ if (entry != NULL) { |
+ EmitIndex(entry); |
+ } else { |
+ if (it->first == ":authority") { |
+ // :authority is always present and rarely changes, and has moderate |
+ // length, therefore it makes a lot of sense to index (insert in the |
+ // header table). |
+ EmitIndexedLiteral(*it); |
+ } else { |
+ // Most common pseudo-header fields are represented in the static table, |
+ // while uncommon ones are small, so do not index them. |
+ EmitNonIndexedLiteral(*it); |
+ } |
+ } |
+ } |
+ |
+ // Encode regular headers that are already in the header table first, |
+ // save the rest into another vector. This way we avoid evicting an entry |
+ // from the header table before it can be used. |
+ Representations literal_headers; |
+ for (Representations::const_iterator it = regular_headers.begin(); |
+ it != regular_headers.end(); ++it) { |
HpackEntry* entry = header_table_.GetByNameAndValue(it->first, it->second); |
if (entry != NULL) { |
EmitIndex(entry); |
} else { |
- // TODO(bnc): if another entry in the header table is about to be evicted |
- // but it appears in the header list, emit that by index first. |
- EmitIndexedLiteral(*it); |
+ literal_headers.push_back(*it); |
} |
} |
+ // Encode the remaining header fields, while inserting them in the header |
+ // table. |
+ for (Representations::const_iterator it = literal_headers.begin(); |
+ it != literal_headers.end(); ++it) { |
+ EmitIndexedLiteral(*it); |
+ } |
+ |
output_stream_.TakeString(output); |
return true; |
} |
@@ -140,8 +172,8 @@ void HpackEncoder::CookieToCrumbs(const Representation& cookie, |
Representations* out) { |
size_t prior_size = out->size(); |
- // See Section 8.1.3.4 "Compressing the Cookie Header Field" in the HTTP/2 |
- // specification at http://tools.ietf.org/html/draft-ietf-httpbis-http2-11 |
+ // 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. |
for (size_t pos = 0;;) { |
size_t end = cookie.second.find(";", pos); |