Signal QPACK dynamic table usage from quic_client_interop_test.

Mark down when a dynamic table entry is referenced from a header block in
QpackEncoder and QpackProgressiveDecoder (because they have the best knowledged
of when an entry is referenced from a header block as opposed to the encoder
stream, and also whether the entry is actually used or it cannot because it is
not acked yet or is draining).  Conveniently slap Boolean to QpackHeaderTable
even though it is not set from within QpackHeaderTable, because QpackHeaderTable
lives for the entire connection, whereas QpackProgressiveDecoder is short-lived
and does not have a direct handle of QpackDecoder to send the signal.

Tested with the following command:
  blaze run :quic_client_interop_test https://quic.aiortc.org

Output before this change:
Results for quic.aiortc.org:443
VHDR
B
3

Output after this change:
Results for quic.aiortc.org:443
VHDR
B
3d

gfe-relnote: n/a, change to non-production test tool.
PiperOrigin-RevId: 280004516
Change-Id: I24dd9ed3222dcbb570e6711cb30a41365e7cd6c5
diff --git a/quic/core/http/quic_spdy_session.h b/quic/core/http/quic_spdy_session.h
index 52bab28..0b86627 100644
--- a/quic/core/http/quic_spdy_session.h
+++ b/quic/core/http/quic_spdy_session.h
@@ -266,6 +266,14 @@
                                                  QuicByteCount compressed,
                                                  QuicByteCount uncompressed);
 
+  // True if any dynamic table entries have been referenced from either a sent
+  // or received header block.  Used for stats.
+  bool dynamic_table_entry_referenced() const {
+    return (qpack_encoder_ &&
+            qpack_encoder_->dynamic_table_entry_referenced()) ||
+           (qpack_decoder_ && qpack_decoder_->dynamic_table_entry_referenced());
+  }
+
  protected:
   // Override CreateIncomingStream(), CreateOutgoingBidirectionalStream() and
   // CreateOutgoingUnidirectionalStream() with QuicSpdyStream return type to
diff --git a/quic/core/qpack/qpack_decoder.h b/quic/core/qpack/qpack_decoder.h
index 113c6ea..4ac1e44 100644
--- a/quic/core/qpack/qpack_decoder.h
+++ b/quic/core/qpack/qpack_decoder.h
@@ -95,6 +95,11 @@
     return &encoder_stream_receiver_;
   }
 
+  // True if any dynamic table entries have been referenced from a header block.
+  bool dynamic_table_entry_referenced() const {
+    return header_table_.dynamic_table_entry_referenced();
+  }
+
  private:
   EncoderStreamErrorDelegate* const encoder_stream_error_delegate_;
   QpackEncoderStreamReceiver encoder_stream_receiver_;
diff --git a/quic/core/qpack/qpack_encoder.cc b/quic/core/qpack/qpack_encoder.cc
index c47dccd..59e172e 100644
--- a/quic/core/qpack/qpack_encoder.cc
+++ b/quic/core/qpack/qpack_encoder.cc
@@ -131,6 +131,7 @@
             instructions.push_back(
                 EncodeIndexedHeaderField(is_static, index, referred_indices));
             smallest_blocking_index = std::min(smallest_blocking_index, index);
+            header_table_.set_dynamic_table_entry_referenced();
 
             break;
           }
@@ -151,6 +152,7 @@
             instructions.push_back(EncodeIndexedHeaderField(
                 is_static, entry->InsertionIndex(), referred_indices));
             smallest_blocking_index = std::min(smallest_blocking_index, index);
+            header_table_.set_dynamic_table_entry_referenced();
 
             break;
           }
@@ -208,6 +210,7 @@
           instructions.push_back(EncodeIndexedHeaderField(
               is_static, entry->InsertionIndex(), referred_indices));
           smallest_blocking_index = std::min(smallest_blocking_index, index);
+          header_table_.set_dynamic_table_entry_referenced();
 
           break;
         }
@@ -218,6 +221,7 @@
           instructions.push_back(EncodeLiteralHeaderFieldWithNameReference(
               is_static, index, value, referred_indices));
           smallest_blocking_index = std::min(smallest_blocking_index, index);
+          header_table_.set_dynamic_table_entry_referenced();
 
           break;
         }
diff --git a/quic/core/qpack/qpack_encoder.h b/quic/core/qpack/qpack_encoder.h
index 0e40ddf..c379d68 100644
--- a/quic/core/qpack/qpack_encoder.h
+++ b/quic/core/qpack/qpack_encoder.h
@@ -88,6 +88,11 @@
     return &decoder_stream_receiver_;
   }
 
+  // True if any dynamic table entries have been referenced from a header block.
+  bool dynamic_table_entry_referenced() const {
+    return header_table_.dynamic_table_entry_referenced();
+  }
+
  private:
   friend class test::QpackEncoderPeer;
 
diff --git a/quic/core/qpack/qpack_header_table.cc b/quic/core/qpack/qpack_header_table.cc
index ff9be9a..4cafa19 100644
--- a/quic/core/qpack/qpack_header_table.cc
+++ b/quic/core/qpack/qpack_header_table.cc
@@ -17,7 +17,8 @@
       dynamic_table_capacity_(0),
       maximum_dynamic_table_capacity_(0),
       max_entries_(0),
-      dropped_entry_count_(0) {}
+      dropped_entry_count_(0),
+      dynamic_table_entry_referenced_(false) {}
 
 QpackHeaderTable::~QpackHeaderTable() {
   for (auto& entry : observers_) {
diff --git a/quic/core/qpack/qpack_header_table.h b/quic/core/qpack/qpack_header_table.h
index d2650e5..1b8020f 100644
--- a/quic/core/qpack/qpack_header_table.h
+++ b/quic/core/qpack/qpack_header_table.h
@@ -130,6 +130,13 @@
   // The returned index might not be the index of a valid entry.
   uint64_t draining_index(float draining_fraction) const;
 
+  void set_dynamic_table_entry_referenced() {
+    dynamic_table_entry_referenced_ = true;
+  }
+  bool dynamic_table_entry_referenced() const {
+    return dynamic_table_entry_referenced_;
+  }
+
  private:
   friend class test::QpackHeaderTablePeer;
 
@@ -192,6 +199,10 @@
 
   // Observers waiting to be notified, sorted by required insert count.
   std::multimap<uint64_t, Observer*> observers_;
+
+  // True if any dynamic table entries have been referenced from a header block.
+  // Set directly by the encoder or decoder.  Used for stats.
+  bool dynamic_table_entry_referenced_;
 };
 
 }  // namespace quic
diff --git a/quic/core/qpack/qpack_progressive_decoder.cc b/quic/core/qpack/qpack_progressive_decoder.cc
index 3c0b0f5..63b2669 100644
--- a/quic/core/qpack/qpack_progressive_decoder.cc
+++ b/quic/core/qpack/qpack_progressive_decoder.cc
@@ -163,6 +163,7 @@
       return false;
     }
 
+    header_table_->set_dynamic_table_entry_referenced();
     handler_->OnHeaderDecoded(entry->name(), entry->value());
     return true;
   }
@@ -202,6 +203,7 @@
     return false;
   }
 
+  header_table_->set_dynamic_table_entry_referenced();
   handler_->OnHeaderDecoded(entry->name(), entry->value());
   return true;
 }
@@ -231,6 +233,7 @@
       return false;
     }
 
+    header_table_->set_dynamic_table_entry_referenced();
     handler_->OnHeaderDecoded(entry->name(), instruction_decoder_.value());
     return true;
   }
@@ -270,6 +273,7 @@
     return false;
   }
 
+  header_table_->set_dynamic_table_entry_referenced();
   handler_->OnHeaderDecoded(entry->name(), instruction_decoder_.value());
   return true;
 }
diff --git a/quic/tools/quic_client_interop_test_bin.cc b/quic/tools/quic_client_interop_test_bin.cc
index 47d87a5..8c9f6d1 100644
--- a/quic/tools/quic_client_interop_test_bin.cc
+++ b/quic/tools/quic_client_interop_test_bin.cc
@@ -50,6 +50,9 @@
   // Third row of features (H3 tests)
   // An H3 transaction succeeded.
   kHttp3,
+  // One or both endpoints insert entries into dynamic table and subsequenly
+  // reference them from header blocks.
+  kDynamicEntryReferenced,
 };
 
 char MatrixLetter(Feature f) {
@@ -70,6 +73,8 @@
       return 'B';
     case Feature::kHttp3:
       return '3';
+    case Feature::kDynamicEntryReferenced:
+      return 'd';
   }
 }
 
@@ -181,6 +186,10 @@
   if (client->latest_response_code() != -1) {
     features.insert(Feature::kHttp3);
 
+    if (client->client_session()->dynamic_table_entry_referenced()) {
+      features.insert(Feature::kDynamicEntryReferenced);
+    }
+
     if (attempt_rebind) {
       // Now make a second request after switching to a different client port.
       if (client->ChangeEphemeralPort()) {
@@ -200,6 +209,10 @@
           }
         }
         features.insert(Feature::kRebinding);
+
+        if (client->client_session()->dynamic_table_entry_referenced()) {
+          features.insert(Feature::kDynamicEntryReferenced);
+        }
       } else {
         QUIC_LOG(ERROR) << "Failed to change ephemeral port";
       }