xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/http2/adapter/nghttp2_session_test.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 #include "quiche/http2/adapter/nghttp2_session.h"
2 
3 #include "quiche/http2/adapter/mock_http2_visitor.h"
4 #include "quiche/http2/adapter/nghttp2_callbacks.h"
5 #include "quiche/http2/adapter/nghttp2_util.h"
6 #include "quiche/http2/adapter/test_frame_sequence.h"
7 #include "quiche/http2/adapter/test_utils.h"
8 #include "quiche/common/platform/api/quiche_expect_bug.h"
9 #include "quiche/common/platform/api/quiche_test.h"
10 
11 namespace http2 {
12 namespace adapter {
13 namespace test {
14 namespace {
15 
16 using testing::_;
17 
18 enum FrameType {
19   DATA,
20   HEADERS,
21   PRIORITY,
22   RST_STREAM,
23   SETTINGS,
24   PUSH_PROMISE,
25   PING,
26   GOAWAY,
27   WINDOW_UPDATE,
28 };
29 
30 class NgHttp2SessionTest : public quiche::test::QuicheTest {
31  public:
SetUp()32   void SetUp() override {
33     nghttp2_option_new(&options_);
34     nghttp2_option_set_no_auto_window_update(options_, 1);
35   }
36 
TearDown()37   void TearDown() override { nghttp2_option_del(options_); }
38 
CreateCallbacks()39   nghttp2_session_callbacks_unique_ptr CreateCallbacks() {
40     nghttp2_session_callbacks_unique_ptr callbacks = callbacks::Create();
41     return callbacks;
42   }
43 
44   DataSavingVisitor visitor_;
45   nghttp2_option* options_ = nullptr;
46 };
47 
TEST_F(NgHttp2SessionTest,ClientConstruction)48 TEST_F(NgHttp2SessionTest, ClientConstruction) {
49   NgHttp2Session session(Perspective::kClient, CreateCallbacks(), options_,
50                          &visitor_);
51   EXPECT_TRUE(session.want_read());
52   EXPECT_FALSE(session.want_write());
53   EXPECT_EQ(session.GetRemoteWindowSize(), kInitialFlowControlWindowSize);
54   EXPECT_NE(session.raw_ptr(), nullptr);
55 }
56 
TEST_F(NgHttp2SessionTest,ClientHandlesFrames)57 TEST_F(NgHttp2SessionTest, ClientHandlesFrames) {
58   NgHttp2Session session(Perspective::kClient, CreateCallbacks(), options_,
59                          &visitor_);
60 
61   ASSERT_EQ(0, nghttp2_session_send(session.raw_ptr()));
62   ASSERT_GT(visitor_.data().size(), 0);
63 
64   const std::string initial_frames = TestFrameSequence()
65                                          .ServerPreface()
66                                          .Ping(42)
67                                          .WindowUpdate(0, 1000)
68                                          .Serialize();
69   testing::InSequence s;
70 
71   // Server preface (empty SETTINGS)
72   EXPECT_CALL(visitor_, OnFrameHeader(0, 0, SETTINGS, 0));
73   EXPECT_CALL(visitor_, OnSettingsStart());
74   EXPECT_CALL(visitor_, OnSettingsEnd());
75 
76   EXPECT_CALL(visitor_, OnFrameHeader(0, 8, PING, 0));
77   EXPECT_CALL(visitor_, OnPing(42, false));
78   EXPECT_CALL(visitor_, OnFrameHeader(0, 4, WINDOW_UPDATE, 0));
79   EXPECT_CALL(visitor_, OnWindowUpdate(0, 1000));
80 
81   const int64_t initial_result = session.ProcessBytes(initial_frames);
82   EXPECT_EQ(initial_frames.size(), initial_result);
83 
84   EXPECT_EQ(session.GetRemoteWindowSize(),
85             kInitialFlowControlWindowSize + 1000);
86 
87   EXPECT_CALL(visitor_, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
88   EXPECT_CALL(visitor_, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
89   EXPECT_CALL(visitor_, OnBeforeFrameSent(PING, 0, 8, 0x1));
90   EXPECT_CALL(visitor_, OnFrameSent(PING, 0, 8, 0x1, 0));
91 
92   ASSERT_EQ(0, nghttp2_session_send(session.raw_ptr()));
93   // Some bytes should have been serialized.
94   absl::string_view serialized = visitor_.data();
95   ASSERT_THAT(serialized,
96               testing::StartsWith(spdy::kHttp2ConnectionHeaderPrefix));
97   serialized.remove_prefix(strlen(spdy::kHttp2ConnectionHeaderPrefix));
98   EXPECT_THAT(serialized, EqualsFrames({spdy::SpdyFrameType::SETTINGS,
99                                         spdy::SpdyFrameType::PING}));
100   visitor_.Clear();
101 
102   const std::vector<Header> headers1 =
103       ToHeaders({{":method", "GET"},
104                  {":scheme", "http"},
105                  {":authority", "example.com"},
106                  {":path", "/this/is/request/one"}});
107   const auto nvs1 = GetNghttp2Nvs(headers1);
108 
109   const std::vector<Header> headers2 =
110       ToHeaders({{":method", "GET"},
111                  {":scheme", "http"},
112                  {":authority", "example.com"},
113                  {":path", "/this/is/request/two"}});
114   const auto nvs2 = GetNghttp2Nvs(headers2);
115 
116   const std::vector<Header> headers3 =
117       ToHeaders({{":method", "GET"},
118                  {":scheme", "http"},
119                  {":authority", "example.com"},
120                  {":path", "/this/is/request/three"}});
121   const auto nvs3 = GetNghttp2Nvs(headers3);
122 
123   const int32_t stream_id1 = nghttp2_submit_request(
124       session.raw_ptr(), nullptr, nvs1.data(), nvs1.size(), nullptr, nullptr);
125   ASSERT_GT(stream_id1, 0);
126   QUICHE_LOG(INFO) << "Created stream: " << stream_id1;
127 
128   const int32_t stream_id2 = nghttp2_submit_request(
129       session.raw_ptr(), nullptr, nvs2.data(), nvs2.size(), nullptr, nullptr);
130   ASSERT_GT(stream_id2, 0);
131   QUICHE_LOG(INFO) << "Created stream: " << stream_id2;
132 
133   const int32_t stream_id3 = nghttp2_submit_request(
134       session.raw_ptr(), nullptr, nvs3.data(), nvs3.size(), nullptr, nullptr);
135   ASSERT_GT(stream_id3, 0);
136   QUICHE_LOG(INFO) << "Created stream: " << stream_id3;
137 
138   EXPECT_CALL(visitor_, OnBeforeFrameSent(HEADERS, 1, _, 0x5));
139   EXPECT_CALL(visitor_, OnFrameSent(HEADERS, 1, _, 0x5, 0));
140   EXPECT_CALL(visitor_, OnBeforeFrameSent(HEADERS, 3, _, 0x5));
141   EXPECT_CALL(visitor_, OnFrameSent(HEADERS, 3, _, 0x5, 0));
142   EXPECT_CALL(visitor_, OnBeforeFrameSent(HEADERS, 5, _, 0x5));
143   EXPECT_CALL(visitor_, OnFrameSent(HEADERS, 5, _, 0x5, 0));
144 
145   ASSERT_EQ(0, nghttp2_session_send(session.raw_ptr()));
146   serialized = visitor_.data();
147   EXPECT_THAT(serialized, EqualsFrames({spdy::SpdyFrameType::HEADERS,
148                                         spdy::SpdyFrameType::HEADERS,
149                                         spdy::SpdyFrameType::HEADERS}));
150   visitor_.Clear();
151 
152   const std::string stream_frames =
153       TestFrameSequence()
154           .Headers(1,
155                    {{":status", "200"},
156                     {"server", "my-fake-server"},
157                     {"date", "Tue, 6 Apr 2021 12:54:01 GMT"}},
158                    /*fin=*/false)
159           .Data(1, "This is the response body.")
160           .RstStream(3, Http2ErrorCode::INTERNAL_ERROR)
161           .GoAway(5, Http2ErrorCode::ENHANCE_YOUR_CALM, "calm down!!")
162           .Serialize();
163 
164   EXPECT_CALL(visitor_, OnFrameHeader(1, _, HEADERS, 4));
165   EXPECT_CALL(visitor_, OnBeginHeadersForStream(1));
166   EXPECT_CALL(visitor_, OnHeaderForStream(1, ":status", "200"));
167   EXPECT_CALL(visitor_, OnHeaderForStream(1, "server", "my-fake-server"));
168   EXPECT_CALL(visitor_,
169               OnHeaderForStream(1, "date", "Tue, 6 Apr 2021 12:54:01 GMT"));
170   EXPECT_CALL(visitor_, OnEndHeadersForStream(1));
171   EXPECT_CALL(visitor_, OnFrameHeader(1, 26, DATA, 0));
172   EXPECT_CALL(visitor_, OnBeginDataForStream(1, 26));
173   EXPECT_CALL(visitor_, OnDataForStream(1, "This is the response body."));
174   EXPECT_CALL(visitor_, OnFrameHeader(3, 4, RST_STREAM, 0));
175   EXPECT_CALL(visitor_, OnRstStream(3, Http2ErrorCode::INTERNAL_ERROR));
176   EXPECT_CALL(visitor_, OnCloseStream(3, Http2ErrorCode::INTERNAL_ERROR));
177   EXPECT_CALL(visitor_, OnFrameHeader(0, 19, GOAWAY, 0));
178   EXPECT_CALL(visitor_,
179               OnGoAway(5, Http2ErrorCode::ENHANCE_YOUR_CALM, "calm down!!"));
180   const int64_t stream_result = session.ProcessBytes(stream_frames);
181   EXPECT_EQ(stream_frames.size(), stream_result);
182 
183   // Even though the client recieved a GOAWAY, streams 1 and 5 are still active.
184   EXPECT_TRUE(session.want_read());
185 
186   EXPECT_CALL(visitor_, OnFrameHeader(1, 0, DATA, 1));
187   EXPECT_CALL(visitor_, OnBeginDataForStream(1, 0));
188   EXPECT_CALL(visitor_, OnEndStream(1));
189   EXPECT_CALL(visitor_, OnCloseStream(1, Http2ErrorCode::HTTP2_NO_ERROR));
190   EXPECT_CALL(visitor_, OnFrameHeader(5, 4, RST_STREAM, 0));
191   EXPECT_CALL(visitor_, OnRstStream(5, Http2ErrorCode::REFUSED_STREAM));
192   EXPECT_CALL(visitor_, OnCloseStream(5, Http2ErrorCode::REFUSED_STREAM));
193   session.ProcessBytes(TestFrameSequence()
194                            .Data(1, "", true)
195                            .RstStream(5, Http2ErrorCode::REFUSED_STREAM)
196                            .Serialize());
197   // After receiving END_STREAM for 1 and RST_STREAM for 5, the session no
198   // longer expects reads.
199   EXPECT_FALSE(session.want_read());
200 
201   // Client will not have anything else to write.
202   EXPECT_FALSE(session.want_write());
203   ASSERT_EQ(0, nghttp2_session_send(session.raw_ptr()));
204   serialized = visitor_.data();
205   EXPECT_EQ(serialized.size(), 0);
206 }
207 
TEST_F(NgHttp2SessionTest,ServerConstruction)208 TEST_F(NgHttp2SessionTest, ServerConstruction) {
209   NgHttp2Session session(Perspective::kServer, CreateCallbacks(), options_,
210                          &visitor_);
211   EXPECT_TRUE(session.want_read());
212   EXPECT_FALSE(session.want_write());
213   EXPECT_EQ(session.GetRemoteWindowSize(), kInitialFlowControlWindowSize);
214   EXPECT_NE(session.raw_ptr(), nullptr);
215 }
216 
TEST_F(NgHttp2SessionTest,ServerHandlesFrames)217 TEST_F(NgHttp2SessionTest, ServerHandlesFrames) {
218   NgHttp2Session session(Perspective::kServer, CreateCallbacks(), options_,
219                          &visitor_);
220 
221   const std::string frames = TestFrameSequence()
222                                  .ClientPreface()
223                                  .Ping(42)
224                                  .WindowUpdate(0, 1000)
225                                  .Headers(1,
226                                           {{":method", "POST"},
227                                            {":scheme", "https"},
228                                            {":authority", "example.com"},
229                                            {":path", "/this/is/request/one"}},
230                                           /*fin=*/false)
231                                  .WindowUpdate(1, 2000)
232                                  .Data(1, "This is the request body.")
233                                  .Headers(3,
234                                           {{":method", "GET"},
235                                            {":scheme", "http"},
236                                            {":authority", "example.com"},
237                                            {":path", "/this/is/request/two"}},
238                                           /*fin=*/true)
239                                  .RstStream(3, Http2ErrorCode::CANCEL)
240                                  .Ping(47)
241                                  .Serialize();
242   testing::InSequence s;
243 
244   // Client preface (empty SETTINGS)
245   EXPECT_CALL(visitor_, OnFrameHeader(0, 0, SETTINGS, 0));
246   EXPECT_CALL(visitor_, OnSettingsStart());
247   EXPECT_CALL(visitor_, OnSettingsEnd());
248 
249   EXPECT_CALL(visitor_, OnFrameHeader(0, 8, PING, 0));
250   EXPECT_CALL(visitor_, OnPing(42, false));
251   EXPECT_CALL(visitor_, OnFrameHeader(0, 4, WINDOW_UPDATE, 0));
252   EXPECT_CALL(visitor_, OnWindowUpdate(0, 1000));
253   EXPECT_CALL(visitor_, OnFrameHeader(1, _, HEADERS, 4));
254   EXPECT_CALL(visitor_, OnBeginHeadersForStream(1));
255   EXPECT_CALL(visitor_, OnHeaderForStream(1, ":method", "POST"));
256   EXPECT_CALL(visitor_, OnHeaderForStream(1, ":scheme", "https"));
257   EXPECT_CALL(visitor_, OnHeaderForStream(1, ":authority", "example.com"));
258   EXPECT_CALL(visitor_, OnHeaderForStream(1, ":path", "/this/is/request/one"));
259   EXPECT_CALL(visitor_, OnEndHeadersForStream(1));
260   EXPECT_CALL(visitor_, OnFrameHeader(1, 4, WINDOW_UPDATE, 0));
261   EXPECT_CALL(visitor_, OnWindowUpdate(1, 2000));
262   EXPECT_CALL(visitor_, OnFrameHeader(1, 25, DATA, 0));
263   EXPECT_CALL(visitor_, OnBeginDataForStream(1, 25));
264   EXPECT_CALL(visitor_, OnDataForStream(1, "This is the request body."));
265   EXPECT_CALL(visitor_, OnFrameHeader(3, _, HEADERS, 5));
266   EXPECT_CALL(visitor_, OnBeginHeadersForStream(3));
267   EXPECT_CALL(visitor_, OnHeaderForStream(3, ":method", "GET"));
268   EXPECT_CALL(visitor_, OnHeaderForStream(3, ":scheme", "http"));
269   EXPECT_CALL(visitor_, OnHeaderForStream(3, ":authority", "example.com"));
270   EXPECT_CALL(visitor_, OnHeaderForStream(3, ":path", "/this/is/request/two"));
271   EXPECT_CALL(visitor_, OnEndHeadersForStream(3));
272   EXPECT_CALL(visitor_, OnEndStream(3));
273   EXPECT_CALL(visitor_, OnFrameHeader(3, 4, RST_STREAM, 0));
274   EXPECT_CALL(visitor_, OnRstStream(3, Http2ErrorCode::CANCEL));
275   EXPECT_CALL(visitor_, OnCloseStream(3, Http2ErrorCode::CANCEL));
276   EXPECT_CALL(visitor_, OnFrameHeader(0, 8, PING, 0));
277   EXPECT_CALL(visitor_, OnPing(47, false));
278 
279   const int64_t result = session.ProcessBytes(frames);
280   EXPECT_EQ(frames.size(), result);
281 
282   EXPECT_EQ(session.GetRemoteWindowSize(),
283             kInitialFlowControlWindowSize + 1000);
284 
285   EXPECT_CALL(visitor_, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
286   EXPECT_CALL(visitor_, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
287   EXPECT_CALL(visitor_, OnBeforeFrameSent(PING, 0, 8, 0x1));
288   EXPECT_CALL(visitor_, OnFrameSent(PING, 0, 8, 0x1, 0));
289   EXPECT_CALL(visitor_, OnBeforeFrameSent(PING, 0, 8, 0x1));
290   EXPECT_CALL(visitor_, OnFrameSent(PING, 0, 8, 0x1, 0));
291 
292   EXPECT_TRUE(session.want_write());
293   ASSERT_EQ(0, nghttp2_session_send(session.raw_ptr()));
294   // Some bytes should have been serialized.
295   absl::string_view serialized = visitor_.data();
296   // SETTINGS ack, two PING acks.
297   EXPECT_THAT(serialized, EqualsFrames({spdy::SpdyFrameType::SETTINGS,
298                                         spdy::SpdyFrameType::PING,
299                                         spdy::SpdyFrameType::PING}));
300 }
301 
302 // Verifies that a null payload is caught by the OnPackExtensionCallback
303 // implementation.
TEST_F(NgHttp2SessionTest,NullPayload)304 TEST_F(NgHttp2SessionTest, NullPayload) {
305   NgHttp2Session session(Perspective::kClient, CreateCallbacks(), options_,
306                          &visitor_);
307 
308   void* payload = nullptr;
309   const int result = nghttp2_submit_extension(
310       session.raw_ptr(), kMetadataFrameType, 0, 1, payload);
311   ASSERT_EQ(0, result);
312   EXPECT_TRUE(session.want_write());
313   int send_result = -1;
314   EXPECT_QUICHE_BUG(
315       {
316         send_result = nghttp2_session_send(session.raw_ptr());
317         EXPECT_EQ(NGHTTP2_ERR_CALLBACK_FAILURE, send_result);
318       },
319       "Extension frame payload for stream 1 is null!");
320 }
321 
TEST_F(NgHttp2SessionTest,ServerSeesErrorOnEndStream)322 TEST_F(NgHttp2SessionTest, ServerSeesErrorOnEndStream) {
323   NgHttp2Session session(Perspective::kServer, CreateCallbacks(), options_,
324                          &visitor_);
325 
326   const std::string frames = TestFrameSequence()
327                                  .ClientPreface()
328                                  .Headers(1,
329                                           {{":method", "POST"},
330                                            {":scheme", "https"},
331                                            {":authority", "example.com"},
332                                            {":path", "/"}},
333                                           /*fin=*/false)
334                                  .Data(1, "Request body", true)
335                                  .Serialize();
336   testing::InSequence s;
337 
338   // Client preface (empty SETTINGS)
339   EXPECT_CALL(visitor_, OnFrameHeader(0, 0, SETTINGS, 0));
340   EXPECT_CALL(visitor_, OnSettingsStart());
341   EXPECT_CALL(visitor_, OnSettingsEnd());
342   // Stream 1
343   EXPECT_CALL(visitor_, OnFrameHeader(1, _, HEADERS, 0x4));
344   EXPECT_CALL(visitor_, OnBeginHeadersForStream(1));
345   EXPECT_CALL(visitor_, OnHeaderForStream(1, ":method", "POST"));
346   EXPECT_CALL(visitor_, OnHeaderForStream(1, ":scheme", "https"));
347   EXPECT_CALL(visitor_, OnHeaderForStream(1, ":authority", "example.com"));
348   EXPECT_CALL(visitor_, OnHeaderForStream(1, ":path", "/"));
349   EXPECT_CALL(visitor_, OnEndHeadersForStream(1));
350 
351   EXPECT_CALL(visitor_, OnFrameHeader(1, _, DATA, 0x1));
352   EXPECT_CALL(visitor_, OnBeginDataForStream(1, _));
353   EXPECT_CALL(visitor_, OnDataForStream(1, "Request body"));
354   EXPECT_CALL(visitor_, OnEndStream(1)).WillOnce(testing::Return(false));
355 
356   const int64_t result = session.ProcessBytes(frames);
357   EXPECT_EQ(NGHTTP2_ERR_CALLBACK_FAILURE, result);
358 
359   EXPECT_TRUE(session.want_write());
360 
361   EXPECT_CALL(visitor_, OnBeforeFrameSent(SETTINGS, 0, _, 0x1));
362   EXPECT_CALL(visitor_, OnFrameSent(SETTINGS, 0, _, 0x1, 0));
363 
364   ASSERT_EQ(0, nghttp2_session_send(session.raw_ptr()));
365   EXPECT_THAT(visitor_.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS}));
366   visitor_.Clear();
367 
368   EXPECT_FALSE(session.want_write());
369 }
370 
371 }  // namespace
372 }  // namespace test
373 }  // namespace adapter
374 }  // namespace http2
375