1 #include "quiche/http2/adapter/http2_protocol.h"
2 #include "quiche/http2/adapter/nghttp2_adapter.h"
3 #include "quiche/http2/adapter/oghttp2_adapter.h"
4 #include "quiche/http2/adapter/recording_http2_visitor.h"
5 #include "quiche/http2/adapter/test_frame_sequence.h"
6 #include "quiche/common/platform/api/quiche_test.h"
7 #include "quiche/spdy/core/spdy_protocol.h"
8
9 namespace http2 {
10 namespace adapter {
11 namespace test {
12 namespace {
13
TEST(AdapterImplComparisonTest,ClientHandlesFrames)14 TEST(AdapterImplComparisonTest, ClientHandlesFrames) {
15 RecordingHttp2Visitor nghttp2_visitor;
16 std::unique_ptr<NgHttp2Adapter> nghttp2_adapter =
17 NgHttp2Adapter::CreateClientAdapter(nghttp2_visitor);
18
19 RecordingHttp2Visitor oghttp2_visitor;
20 OgHttp2Adapter::Options options;
21 options.perspective = Perspective::kClient;
22 std::unique_ptr<OgHttp2Adapter> oghttp2_adapter =
23 OgHttp2Adapter::Create(oghttp2_visitor, options);
24
25 const std::string initial_frames = TestFrameSequence()
26 .ServerPreface()
27 .Ping(42)
28 .WindowUpdate(0, 1000)
29 .Serialize();
30
31 nghttp2_adapter->ProcessBytes(initial_frames);
32 oghttp2_adapter->ProcessBytes(initial_frames);
33
34 EXPECT_EQ(nghttp2_visitor.GetEventSequence(),
35 oghttp2_visitor.GetEventSequence());
36
37 // TODO(b/181586191): Consider consistent behavior for delivering events on
38 // non-existent streams between nghttp2_adapter and oghttp2_adapter.
39 }
40
TEST(AdapterImplComparisonTest,SubmitWindowUpdateBumpsWindow)41 TEST(AdapterImplComparisonTest, SubmitWindowUpdateBumpsWindow) {
42 RecordingHttp2Visitor nghttp2_visitor;
43 std::unique_ptr<NgHttp2Adapter> nghttp2_adapter =
44 NgHttp2Adapter::CreateClientAdapter(nghttp2_visitor);
45
46 RecordingHttp2Visitor oghttp2_visitor;
47 OgHttp2Adapter::Options options;
48 options.perspective = Perspective::kClient;
49 std::unique_ptr<OgHttp2Adapter> oghttp2_adapter =
50 OgHttp2Adapter::Create(oghttp2_visitor, options);
51
52 int result;
53
54 const std::vector<Header> request_headers =
55 ToHeaders({{":method", "POST"},
56 {":scheme", "https"},
57 {":authority", "example.com"},
58 {":path", "/"}});
59 const int kInitialFlowControlWindow = 65535;
60 const int kConnectionWindowIncrease = 192 * 1024;
61
62 const int32_t nghttp2_stream_id =
63 nghttp2_adapter->SubmitRequest(request_headers, nullptr, nullptr);
64
65 // Both the connection and stream flow control windows are increased.
66 nghttp2_adapter->SubmitWindowUpdate(0, kConnectionWindowIncrease);
67 nghttp2_adapter->SubmitWindowUpdate(nghttp2_stream_id,
68 kConnectionWindowIncrease);
69 result = nghttp2_adapter->Send();
70 EXPECT_EQ(0, result);
71 int nghttp2_window = nghttp2_adapter->GetReceiveWindowSize();
72 EXPECT_EQ(kInitialFlowControlWindow + kConnectionWindowIncrease,
73 nghttp2_window);
74
75 const int32_t oghttp2_stream_id =
76 oghttp2_adapter->SubmitRequest(request_headers, nullptr, nullptr);
77 // Both the connection and stream flow control windows are increased.
78 oghttp2_adapter->SubmitWindowUpdate(0, kConnectionWindowIncrease);
79 oghttp2_adapter->SubmitWindowUpdate(oghttp2_stream_id,
80 kConnectionWindowIncrease);
81 result = oghttp2_adapter->Send();
82 EXPECT_EQ(0, result);
83 int oghttp2_window = oghttp2_adapter->GetReceiveWindowSize();
84 EXPECT_EQ(kInitialFlowControlWindow + kConnectionWindowIncrease,
85 oghttp2_window);
86
87 // nghttp2 and oghttp2 agree on the advertised window.
88 EXPECT_EQ(nghttp2_window, oghttp2_window);
89
90 ASSERT_EQ(nghttp2_stream_id, oghttp2_stream_id);
91
92 const int kMaxFrameSize = 16 * 1024;
93 const std::string body_chunk(kMaxFrameSize, 'a');
94 auto sequence = TestFrameSequence();
95 sequence.ServerPreface().Headers(nghttp2_stream_id, {{":status", "200"}},
96 /*fin=*/false);
97 // This loop generates enough DATA frames to consume the window increase.
98 const int kNumFrames = kConnectionWindowIncrease / kMaxFrameSize;
99 for (int i = 0; i < kNumFrames; ++i) {
100 sequence.Data(nghttp2_stream_id, body_chunk);
101 }
102 const std::string frames = sequence.Serialize();
103
104 nghttp2_adapter->ProcessBytes(frames);
105 // Marking the data consumed causes a window update, which is reflected in the
106 // advertised window size.
107 nghttp2_adapter->MarkDataConsumedForStream(nghttp2_stream_id,
108 kNumFrames * kMaxFrameSize);
109 result = nghttp2_adapter->Send();
110 EXPECT_EQ(0, result);
111 nghttp2_window = nghttp2_adapter->GetReceiveWindowSize();
112
113 oghttp2_adapter->ProcessBytes(frames);
114 // Marking the data consumed causes a window update, which is reflected in the
115 // advertised window size.
116 oghttp2_adapter->MarkDataConsumedForStream(oghttp2_stream_id,
117 kNumFrames * kMaxFrameSize);
118 result = oghttp2_adapter->Send();
119 EXPECT_EQ(0, result);
120 oghttp2_window = oghttp2_adapter->GetReceiveWindowSize();
121
122 const int kMinExpectation =
123 (kInitialFlowControlWindow + kConnectionWindowIncrease) / 2;
124 EXPECT_GT(nghttp2_window, kMinExpectation);
125 EXPECT_GT(oghttp2_window, kMinExpectation);
126 }
127
TEST(AdapterImplComparisonTest,ServerHandlesFrames)128 TEST(AdapterImplComparisonTest, ServerHandlesFrames) {
129 RecordingHttp2Visitor nghttp2_visitor;
130 std::unique_ptr<NgHttp2Adapter> nghttp2_adapter =
131 NgHttp2Adapter::CreateServerAdapter(nghttp2_visitor);
132
133 RecordingHttp2Visitor oghttp2_visitor;
134 OgHttp2Adapter::Options options;
135 options.perspective = Perspective::kServer;
136 std::unique_ptr<OgHttp2Adapter> oghttp2_adapter =
137 OgHttp2Adapter::Create(oghttp2_visitor, options);
138
139 const std::string frames = TestFrameSequence()
140 .ClientPreface()
141 .Ping(42)
142 .WindowUpdate(0, 1000)
143 .Headers(1,
144 {{":method", "POST"},
145 {":scheme", "https"},
146 {":authority", "example.com"},
147 {":path", "/this/is/request/one"}},
148 /*fin=*/false)
149 .WindowUpdate(1, 2000)
150 .Data(1, "This is the request body.")
151 .Headers(3,
152 {{":method", "GET"},
153 {":scheme", "http"},
154 {":authority", "example.com"},
155 {":path", "/this/is/request/two"}},
156 /*fin=*/true)
157 .RstStream(3, Http2ErrorCode::CANCEL)
158 .Ping(47)
159 .Serialize();
160
161 nghttp2_adapter->ProcessBytes(frames);
162 oghttp2_adapter->ProcessBytes(frames);
163
164 EXPECT_EQ(nghttp2_visitor.GetEventSequence(),
165 oghttp2_visitor.GetEventSequence());
166 }
167
168 } // namespace
169 } // namespace test
170 } // namespace adapter
171 } // namespace http2
172