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.