gfe-relnote: Use indexed name if possible when sending Literal Header Field without Indexing instruction.  Protected by gfe2_reloadable_flag_spdy_hpack_use_indexed_name.

This CL touches HPACK encoding, which is used over HTTP/2 and Google QUIC.

If compression is enabled and a pseudo-header other than :authority has a
matching name but not matching value in the static table, then before this
change, its name was sent as a string literal; after this change, it is sent
indexed.

Bug: https://crbug.com/983254
PiperOrigin-RevId: 305517407
Change-Id: If6172beacb02efe2465d8753749e6c586688e3c0
diff --git a/spdy/core/hpack/hpack_encoder.cc b/spdy/core/hpack/hpack_encoder.cc
index 3835047..e3bf8f6 100644
--- a/spdy/core/hpack/hpack_encoder.cc
+++ b/spdy/core/hpack/hpack_encoder.cc
@@ -13,6 +13,7 @@
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_estimate_memory_usage.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_flags.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_logging.h"
 
 namespace spdy {
@@ -146,10 +147,10 @@
       } else if (should_index_(header.first, header.second)) {
         EmitIndexedLiteral(header);
       } else {
-        EmitNonIndexedLiteral(header);
+        EmitNonIndexedLiteral(header, enable_compression_);
       }
     } else {
-      EmitNonIndexedLiteral(header);
+      EmitNonIndexedLiteral(header, enable_compression_);
     }
   }
 
@@ -170,12 +171,25 @@
   header_table_.TryAddEntry(representation.first, representation.second);
 }
 
-void HpackEncoder::EmitNonIndexedLiteral(const Representation& representation) {
+void HpackEncoder::EmitNonIndexedLiteral(const Representation& representation,
+                                         bool enable_compression) {
   SPDY_DVLOG(2) << "Emitting nonindexed literal: (" << representation.first
                 << ", " << representation.second << ")";
   output_stream_.AppendPrefix(kLiteralNoIndexOpcode);
-  output_stream_.AppendUint32(0);
-  EmitString(representation.first);
+  if (GetSpdyReloadableFlag(spdy_hpack_use_indexed_name)) {
+    SPDY_CODE_COUNT(spdy_hpack_use_indexed_name);
+    const HpackEntry* name_entry =
+        header_table_.GetByName(representation.first);
+    if (enable_compression && name_entry != nullptr) {
+      output_stream_.AppendUint32(header_table_.IndexOf(name_entry));
+    } else {
+      output_stream_.AppendUint32(0);
+      EmitString(representation.first);
+    }
+  } else {
+    output_stream_.AppendUint32(0);
+    EmitString(representation.first);
+  }
   EmitString(representation.second);
 }
 
@@ -347,14 +361,14 @@
                                      std::string* output) {
   SPDY_BUG_IF(!has_next_)
       << "Encoderator::Next called with nothing left to encode.";
-  const bool use_compression = encoder_->enable_compression_;
+  const bool enable_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) {
+    if (enable_compression) {
       const HpackEntry* entry = encoder_->header_table_.GetByNameAndValue(
           header.first, header.second);
       if (entry != nullptr) {
@@ -362,10 +376,10 @@
       } else if (encoder_->should_index_(header.first, header.second)) {
         encoder_->EmitIndexedLiteral(header);
       } else {
-        encoder_->EmitNonIndexedLiteral(header);
+        encoder_->EmitNonIndexedLiteral(header, enable_compression);
       }
     } else {
-      encoder_->EmitNonIndexedLiteral(header);
+      encoder_->EmitNonIndexedLiteral(header, enable_compression);
     }
   }
 
diff --git a/spdy/core/hpack/hpack_encoder.h b/spdy/core/hpack/hpack_encoder.h
index c3d3a19..534b9e6 100644
--- a/spdy/core/hpack/hpack_encoder.h
+++ b/spdy/core/hpack/hpack_encoder.h
@@ -122,7 +122,8 @@
 
   // Emits a literal representation (Section 7.2).
   void EmitIndexedLiteral(const Representation& representation);
-  void EmitNonIndexedLiteral(const Representation& representation);
+  void EmitNonIndexedLiteral(const Representation& representation,
+                             bool enable_compression);
   void EmitLiteral(const Representation& representation);
 
   // Emits a Huffman or identity string (whichever is smaller).
diff --git a/spdy/core/hpack/hpack_encoder_test.cc b/spdy/core/hpack/hpack_encoder_test.cc
index 2ac0a5f..2b1efe9 100644
--- a/spdy/core/hpack/hpack_encoder_test.cc
+++ b/spdy/core/hpack/hpack_encoder_test.cc
@@ -11,6 +11,7 @@
 #include "net/third_party/quiche/src/common/platform/api/quiche_test.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_simple_arena.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_flags.h"
 
 namespace spdy {
 
@@ -182,6 +183,12 @@
     ExpectString(&expected_, name);
     ExpectString(&expected_, value);
   }
+  void ExpectNonIndexedLiteralWithNameIndex(const HpackEntry* key_entry,
+                                            quiche::QuicheStringPiece value) {
+    expected_.AppendPrefix(kLiteralNoIndexOpcode);
+    expected_.AppendUint32(IndexOf(key_entry));
+    ExpectString(&expected_, value);
+  }
   void ExpectString(HpackOutputStream* stream, quiche::QuicheStringPiece str) {
     const HpackHuffmanTable& huffman_table = peer_.huffman_table();
     size_t encoded_size = peer_.compression_enabled()
@@ -267,7 +274,12 @@
                      {"accept", "text/html, text/plain,application/xml"},
                      {"cookie", "val4"},
                      {"withnul", quiche::QuicheStringPiece("one\0two", 7)}};
-  ExpectNonIndexedLiteral(":path", "/home");
+  if (GetSpdyReloadableFlag(spdy_hpack_use_indexed_name)) {
+    ExpectNonIndexedLiteralWithNameIndex(peer_.table()->GetByName(":path"),
+                                         "/home");
+  } else {
+    ExpectNonIndexedLiteral(":path", "/home");
+  }
   ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "val1");
   ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "val2");
   ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "val3");
@@ -554,7 +566,12 @@
 
   // Headers are indexed in the order in which they were added.
   // This entry pushes "cookie: a=bb" back to 63.
-  ExpectNonIndexedLiteral(":path", "/spam/eggs.html");
+  if (GetSpdyReloadableFlag(spdy_hpack_use_indexed_name)) {
+    ExpectNonIndexedLiteralWithNameIndex(peer_.table()->GetByName(":path"),
+                                         "/spam/eggs.html");
+  } else {
+    ExpectNonIndexedLiteral(":path", "/spam/eggs.html");
+  }
   ExpectIndexedLiteral(peer_.table()->GetByName(":authority"),
                        "www.example.com");
   ExpectIndexedLiteral("-foo", "bar");