Introduce a debugging utility for printing HTTP/2 logical frames from wire bytes.
This utility class, Http2TracePrinter, may be useful for a variety of
scenarios, including easier reproduction of test failures.
The printer appears to be working based on a local test run:
http://screen/5DDNEMaPFzpnJwQ. (Also with connection preface error:
http://screen/9XFCtvqMUUoYRMa.)
PiperOrigin-RevId: 566429201
diff --git a/build/source_list.bzl b/build/source_list.bzl
index b008e48..05fd184 100644
--- a/build/source_list.bzl
+++ b/build/source_list.bzl
@@ -763,6 +763,7 @@
"http2/test_tools/http2_random.h",
"http2/test_tools/http2_structure_decoder_test_util.h",
"http2/test_tools/http2_structures_test_util.h",
+ "http2/test_tools/http2_trace_printer.h",
"http2/test_tools/payload_decoder_base_test_util.h",
"http2/test_tools/random_decoder_test_base.h",
"http2/test_tools/random_util.h",
@@ -869,6 +870,7 @@
"http2/test_tools/http2_random.cc",
"http2/test_tools/http2_structure_decoder_test_util.cc",
"http2/test_tools/http2_structures_test_util.cc",
+ "http2/test_tools/http2_trace_printer.cc",
"http2/test_tools/payload_decoder_base_test_util.cc",
"http2/test_tools/random_decoder_test_base.cc",
"http2/test_tools/random_util.cc",
diff --git a/build/source_list.gni b/build/source_list.gni
index 23b3066..a788a47 100644
--- a/build/source_list.gni
+++ b/build/source_list.gni
@@ -763,6 +763,7 @@
"src/quiche/http2/test_tools/http2_random.h",
"src/quiche/http2/test_tools/http2_structure_decoder_test_util.h",
"src/quiche/http2/test_tools/http2_structures_test_util.h",
+ "src/quiche/http2/test_tools/http2_trace_printer.h",
"src/quiche/http2/test_tools/payload_decoder_base_test_util.h",
"src/quiche/http2/test_tools/random_decoder_test_base.h",
"src/quiche/http2/test_tools/random_util.h",
@@ -869,6 +870,7 @@
"src/quiche/http2/test_tools/http2_random.cc",
"src/quiche/http2/test_tools/http2_structure_decoder_test_util.cc",
"src/quiche/http2/test_tools/http2_structures_test_util.cc",
+ "src/quiche/http2/test_tools/http2_trace_printer.cc",
"src/quiche/http2/test_tools/payload_decoder_base_test_util.cc",
"src/quiche/http2/test_tools/random_decoder_test_base.cc",
"src/quiche/http2/test_tools/random_util.cc",
diff --git a/build/source_list.json b/build/source_list.json
index ef16ce6..e3c9efd 100644
--- a/build/source_list.json
+++ b/build/source_list.json
@@ -762,6 +762,7 @@
"quiche/http2/test_tools/http2_random.h",
"quiche/http2/test_tools/http2_structure_decoder_test_util.h",
"quiche/http2/test_tools/http2_structures_test_util.h",
+ "quiche/http2/test_tools/http2_trace_printer.h",
"quiche/http2/test_tools/payload_decoder_base_test_util.h",
"quiche/http2/test_tools/random_decoder_test_base.h",
"quiche/http2/test_tools/random_util.h",
@@ -868,6 +869,7 @@
"quiche/http2/test_tools/http2_random.cc",
"quiche/http2/test_tools/http2_structure_decoder_test_util.cc",
"quiche/http2/test_tools/http2_structures_test_util.cc",
+ "quiche/http2/test_tools/http2_trace_printer.cc",
"quiche/http2/test_tools/payload_decoder_base_test_util.cc",
"quiche/http2/test_tools/random_decoder_test_base.cc",
"quiche/http2/test_tools/random_util.cc",
diff --git a/quiche/http2/test_tools/http2_trace_printer.cc b/quiche/http2/test_tools/http2_trace_printer.cc
new file mode 100644
index 0000000..682f91b
--- /dev/null
+++ b/quiche/http2/test_tools/http2_trace_printer.cc
@@ -0,0 +1,61 @@
+#include "quiche/http2/test_tools/http2_trace_printer.h"
+
+#include <algorithm>
+#include <cstddef>
+
+#include "absl/strings/escaping.h"
+#include "absl/strings/match.h"
+#include "absl/strings/string_view.h"
+#include "quiche/http2/core/http2_trace_logging.h"
+#include "quiche/spdy/core/spdy_protocol.h"
+
+namespace http2 {
+namespace test {
+namespace {
+
+bool IsLoggingEnabled() { return true; }
+
+} // namespace
+
+Http2TracePrinter::Http2TracePrinter(absl::string_view perspective,
+ const void* connection_id,
+ bool consume_connection_preface)
+ : logger_(&visitor_, perspective, IsLoggingEnabled, connection_id),
+ perspective_(perspective) {
+ decoder_.set_visitor(&logger_);
+ if (consume_connection_preface) {
+ remaining_preface_ =
+ absl::string_view(spdy::kHttp2ConnectionHeaderPrefix,
+ spdy::kHttp2ConnectionHeaderPrefixSize);
+ }
+}
+
+void Http2TracePrinter::ProcessInput(absl::string_view bytes) {
+ if (preface_error_) {
+ HTTP2_TRACE_LOG(perspective_, IsLoggingEnabled)
+ << "Earlier connection preface error, ignoring " << bytes.size()
+ << " bytes";
+ return;
+ }
+ if (!remaining_preface_.empty()) {
+ const size_t consumed = std::min(remaining_preface_.size(), bytes.size());
+
+ const absl::string_view preface = bytes.substr(0, consumed);
+ HTTP2_TRACE_LOG(perspective_, IsLoggingEnabled)
+ << "Received connection preface: " << absl::CEscape(preface);
+
+ if (!absl::StartsWith(remaining_preface_, preface)) {
+ HTTP2_TRACE_LOG(perspective_, IsLoggingEnabled)
+ << "Received preface does not match expected remaining preface: "
+ << absl::CEscape(remaining_preface_);
+ preface_error_ = true;
+ return;
+ }
+ bytes.remove_prefix(consumed);
+ remaining_preface_.remove_prefix(consumed);
+ }
+ decoder_.ProcessInput(bytes.data(), bytes.size());
+}
+
+} // namespace test
+} // namespace http2
diff --git a/quiche/http2/test_tools/http2_trace_printer.h b/quiche/http2/test_tools/http2_trace_printer.h
new file mode 100644
index 0000000..b965ad8
--- /dev/null
+++ b/quiche/http2/test_tools/http2_trace_printer.h
@@ -0,0 +1,48 @@
+#ifndef QUICHE_HTTP2_TEST_TOOLS_HTTP2_TRACE_PRINTER_H_
+#define QUICHE_HTTP2_TEST_TOOLS_HTTP2_TRACE_PRINTER_H_
+
+#include <cstddef>
+
+#include "absl/strings/string_view.h"
+#include "quiche/http2/core/http2_trace_logging.h"
+#include "quiche/common/platform/api/quiche_export.h"
+#include "quiche/spdy/core/http2_frame_decoder_adapter.h"
+#include "quiche/spdy/core/spdy_no_op_visitor.h"
+
+namespace http2 {
+namespace test {
+
+// A debugging utility that prints HTTP/2 wire bytes into logical HTTP/2 frame
+// sequences using `Http2TraceLogger`.
+class QUICHE_NO_EXPORT Http2TracePrinter {
+ public:
+ // Creates a printer with the given `perspective` prefixed with each log line
+ // (e.g., "CLIENT" or "SERVER"). The given `connection_id` is also included
+ // with each log line and distinguishes among multiple printed connections
+ // with the same `perspective`. If `consume_connection_preface` is true, the
+ // printer will attempt to consume and log the HTTP/2 client connection
+ // preface from the wire bytes.
+ explicit Http2TracePrinter(absl::string_view perspective,
+ const void* connection_id = nullptr,
+ bool consume_connection_preface = false);
+
+ // Processes the `bytes` as HTTP/2 wire format and INFO logs the received
+ // frames. See `Http2TraceLogger` for more details on the logging format. If
+ // `consume_connection_preface` was passed as true to the constructor, then
+ // errors in processing the connection preface will be logged and subsequent
+ // calls to `ProcessInput()` will be a no-op.
+ void ProcessInput(absl::string_view bytes);
+
+ private:
+ spdy::SpdyNoOpVisitor visitor_;
+ Http2TraceLogger logger_;
+ Http2DecoderAdapter decoder_;
+ const absl::string_view perspective_;
+ absl::string_view remaining_preface_;
+ bool preface_error_ = false;
+};
+
+} // namespace test
+} // namespace http2
+
+#endif // QUICHE_HTTP2_TEST_TOOLS_HTTP2_TRACE_PRINTER_H_