Call visitor_.OnConnectionError() when failing to send the connection preface. This CL brings the connection preface write failure handling in line with queued frame write failure handling (http://google3/third_party/http2/adapter/oghttp2_session.cc?l=332-334&rcl=399578585). This CL also changes a static const member to a static constexpr member. For some reason, this change was needed to be able to refer to the member outside of the class (e.g., in a test). PiperOrigin-RevId: 400037133
diff --git a/http2/adapter/http2_visitor_interface.h b/http2/adapter/http2_visitor_interface.h index 308f0d8..8297334 100644 --- a/http2/adapter/http2_visitor_interface.h +++ b/http2/adapter/http2_visitor_interface.h
@@ -52,8 +52,8 @@ Http2VisitorInterface& operator=(const Http2VisitorInterface&) = delete; virtual ~Http2VisitorInterface() = default; - static const int64_t kSendBlocked = 0; - static const int64_t kSendError = -1; + static constexpr int64_t kSendBlocked = 0; + static constexpr int64_t kSendError = -1; // Called when there are serialized frames to send. Should return how many // bytes were actually sent. May return kSendBlocked or kSendError. virtual int64_t OnReadyToSend(absl::string_view serialized) = 0;
diff --git a/http2/adapter/nghttp2_adapter_test.cc b/http2/adapter/nghttp2_adapter_test.cc index a61c55c..ccfb1ac 100644 --- a/http2/adapter/nghttp2_adapter_test.cc +++ b/http2/adapter/nghttp2_adapter_test.cc
@@ -1386,6 +1386,17 @@ EXPECT_FALSE(adapter->want_write()); } +TEST(NgHttp2AdapterTest, FailureSendingConnectionPreface) { + DataSavingVisitor visitor; + auto adapter = NgHttp2Adapter::CreateClientAdapter(visitor); + + visitor.set_has_write_error(); + EXPECT_CALL(visitor, OnConnectionError); + + int result = adapter->Send(); + EXPECT_EQ(result, NGHTTP2_ERR_CALLBACK_FAILURE); +} + TEST(NgHttp2AdapterTest, ServerConstruction) { testing::StrictMock<MockHttp2Visitor> visitor; auto adapter = NgHttp2Adapter::CreateServerAdapter(visitor);
diff --git a/http2/adapter/oghttp2_adapter_test.cc b/http2/adapter/oghttp2_adapter_test.cc index 0efb679..f663fb7 100644 --- a/http2/adapter/oghttp2_adapter_test.cc +++ b/http2/adapter/oghttp2_adapter_test.cc
@@ -4,6 +4,7 @@ #include "absl/strings/str_join.h" #include "http2/adapter/http2_protocol.h" +#include "http2/adapter/http2_visitor_interface.h" #include "http2/adapter/mock_http2_visitor.h" #include "http2/adapter/oghttp2_util.h" #include "http2/adapter/test_frame_sequence.h" @@ -822,6 +823,18 @@ EXPECT_FALSE(adapter->want_write()); } +TEST(OgHttp2AdapterClientTest, FailureSendingConnectionPreface) { + DataSavingVisitor visitor; + OgHttp2Adapter::Options options{.perspective = Perspective::kClient}; + auto adapter = OgHttp2Adapter::Create(visitor, options); + + visitor.set_has_write_error(); + EXPECT_CALL(visitor, OnConnectionError); + + int result = adapter->Send(); + EXPECT_EQ(result, Http2VisitorInterface::kSendError); +} + TEST_F(OgHttp2AdapterTest, SubmitMetadata) { auto source = absl::make_unique<TestMetadataSource>(ToHeaderBlock(ToHeaders( {{"query-cost", "is too darn high"}, {"secret-sauce", "hollandaise"}})));
diff --git a/http2/adapter/oghttp2_session.cc b/http2/adapter/oghttp2_session.cc index 4359bbf..149a026 100644 --- a/http2/adapter/oghttp2_session.cc +++ b/http2/adapter/oghttp2_session.cc
@@ -299,9 +299,13 @@ serialized_prefix_.erase(0, result); } } - if (!serialized_prefix_.empty()) { - return result < 0 ? result : 0; + if (result < 0) { + visitor_.OnConnectionError(); + return result; + } else if (!serialized_prefix_.empty()) { + return 0; } + bool continue_writing = SendQueuedFrames(); while (continue_writing && !connection_metadata_.empty()) { continue_writing = SendMetadata(0, connection_metadata_);
diff --git a/http2/adapter/test_utils.h b/http2/adapter/test_utils.h index 0493788..ec7e95c 100644 --- a/http2/adapter/test_utils.h +++ b/http2/adapter/test_utils.h
@@ -23,6 +23,9 @@ : public testing::StrictMock<MockHttp2Visitor> { public: int64_t OnReadyToSend(absl::string_view data) override { + if (has_write_error_) { + return kSendError; + } if (is_write_blocked_) { return kSendBlocked; } @@ -63,11 +66,14 @@ bool is_write_blocked() const { return is_write_blocked_; } void set_is_write_blocked(bool value) { is_write_blocked_ = value; } + void set_has_write_error() { has_write_error_ = true; } + private: std::string data_; absl::flat_hash_map<Http2StreamId, std::vector<std::string>> metadata_map_; size_t send_limit_ = std::numeric_limits<size_t>::max(); bool is_write_blocked_ = false; + bool has_write_error_ = false; }; // A test DataFrameSource. Starts out in the empty, blocked state.