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_