xref: /aosp_15_r20/external/cronet/net/spdy/buffered_spdy_framer_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/spdy/buffered_spdy_framer.h"
6 
7 #include <algorithm>
8 #include <string_view>
9 #include <utility>
10 
11 #include "base/logging.h"
12 #include "net/log/net_log_with_source.h"
13 #include "net/spdy/spdy_test_util_common.h"
14 #include "testing/platform_test.h"
15 
16 namespace net {
17 
18 namespace {
19 
20 class TestBufferedSpdyVisitor : public BufferedSpdyFramerVisitorInterface {
21  public:
TestBufferedSpdyVisitor()22   TestBufferedSpdyVisitor()
23       : buffered_spdy_framer_(kMaxHeaderListSizeForTest, NetLogWithSource()),
24         header_stream_id_(static_cast<spdy::SpdyStreamId>(-1)),
25         promised_stream_id_(static_cast<spdy::SpdyStreamId>(-1)) {}
26 
OnError(http2::Http2DecoderAdapter::SpdyFramerError spdy_framer_error)27   void OnError(
28       http2::Http2DecoderAdapter::SpdyFramerError spdy_framer_error) override {
29     VLOG(1) << "spdy::SpdyFramer Error: " << spdy_framer_error;
30     error_count_++;
31   }
32 
OnStreamError(spdy::SpdyStreamId stream_id,const std::string & description)33   void OnStreamError(spdy::SpdyStreamId stream_id,
34                      const std::string& description) override {
35     VLOG(1) << "spdy::SpdyFramer Error on stream: " << stream_id << " "
36             << description;
37     error_count_++;
38   }
39 
OnHeaders(spdy::SpdyStreamId stream_id,bool has_priority,int weight,spdy::SpdyStreamId parent_stream_id,bool exclusive,bool fin,spdy::Http2HeaderBlock headers,base::TimeTicks recv_first_byte_time)40   void OnHeaders(spdy::SpdyStreamId stream_id,
41                  bool has_priority,
42                  int weight,
43                  spdy::SpdyStreamId parent_stream_id,
44                  bool exclusive,
45                  bool fin,
46                  spdy::Http2HeaderBlock headers,
47                  base::TimeTicks recv_first_byte_time) override {
48     header_stream_id_ = stream_id;
49     headers_frame_count_++;
50     headers_ = std::move(headers);
51   }
52 
OnDataFrameHeader(spdy::SpdyStreamId stream_id,size_t length,bool fin)53   void OnDataFrameHeader(spdy::SpdyStreamId stream_id,
54                          size_t length,
55                          bool fin) override {
56     ADD_FAILURE() << "Unexpected OnDataFrameHeader call.";
57   }
58 
OnStreamFrameData(spdy::SpdyStreamId stream_id,const char * data,size_t len)59   void OnStreamFrameData(spdy::SpdyStreamId stream_id,
60                          const char* data,
61                          size_t len) override {
62     LOG(FATAL) << "Unexpected OnStreamFrameData call.";
63   }
64 
OnStreamEnd(spdy::SpdyStreamId stream_id)65   void OnStreamEnd(spdy::SpdyStreamId stream_id) override {
66     LOG(FATAL) << "Unexpected OnStreamEnd call.";
67   }
68 
OnStreamPadding(spdy::SpdyStreamId stream_id,size_t len)69   void OnStreamPadding(spdy::SpdyStreamId stream_id, size_t len) override {
70     LOG(FATAL) << "Unexpected OnStreamPadding call.";
71   }
72 
OnSettings()73   void OnSettings() override {}
74 
OnSettingsAck()75   void OnSettingsAck() override {}
76 
OnSettingsEnd()77   void OnSettingsEnd() override {}
78 
OnSetting(spdy::SpdySettingsId id,uint32_t value)79   void OnSetting(spdy::SpdySettingsId id, uint32_t value) override {
80     setting_count_++;
81   }
82 
OnPing(spdy::SpdyPingId unique_id,bool is_ack)83   void OnPing(spdy::SpdyPingId unique_id, bool is_ack) override {}
84 
OnRstStream(spdy::SpdyStreamId stream_id,spdy::SpdyErrorCode error_code)85   void OnRstStream(spdy::SpdyStreamId stream_id,
86                    spdy::SpdyErrorCode error_code) override {}
87 
OnGoAway(spdy::SpdyStreamId last_accepted_stream_id,spdy::SpdyErrorCode error_code,std::string_view debug_data)88   void OnGoAway(spdy::SpdyStreamId last_accepted_stream_id,
89                 spdy::SpdyErrorCode error_code,
90                 std::string_view debug_data) override {
91     goaway_count_++;
92     goaway_last_accepted_stream_id_ = last_accepted_stream_id;
93     goaway_error_code_ = error_code;
94     goaway_debug_data_.assign(debug_data.data(), debug_data.size());
95   }
96 
OnDataFrameHeader(const spdy::SpdySerializedFrame * frame)97   void OnDataFrameHeader(const spdy::SpdySerializedFrame* frame) {
98     LOG(FATAL) << "Unexpected OnDataFrameHeader call.";
99   }
100 
OnRstStream(const spdy::SpdySerializedFrame & frame)101   void OnRstStream(const spdy::SpdySerializedFrame& frame) {}
OnGoAway(const spdy::SpdySerializedFrame & frame)102   void OnGoAway(const spdy::SpdySerializedFrame& frame) {}
OnPing(const spdy::SpdySerializedFrame & frame)103   void OnPing(const spdy::SpdySerializedFrame& frame) {}
OnWindowUpdate(spdy::SpdyStreamId stream_id,int delta_window_size)104   void OnWindowUpdate(spdy::SpdyStreamId stream_id,
105                       int delta_window_size) override {}
106 
OnPushPromise(spdy::SpdyStreamId stream_id,spdy::SpdyStreamId promised_stream_id,spdy::Http2HeaderBlock headers)107   void OnPushPromise(spdy::SpdyStreamId stream_id,
108                      spdy::SpdyStreamId promised_stream_id,
109                      spdy::Http2HeaderBlock headers) override {
110     header_stream_id_ = stream_id;
111     push_promise_frame_count_++;
112     promised_stream_id_ = promised_stream_id;
113     headers_ = std::move(headers);
114   }
115 
OnAltSvc(spdy::SpdyStreamId stream_id,std::string_view origin,const spdy::SpdyAltSvcWireFormat::AlternativeServiceVector & altsvc_vector)116   void OnAltSvc(spdy::SpdyStreamId stream_id,
117                 std::string_view origin,
118                 const spdy::SpdyAltSvcWireFormat::AlternativeServiceVector&
119                     altsvc_vector) override {
120     altsvc_count_++;
121     altsvc_stream_id_ = stream_id;
122     altsvc_origin_.assign(origin.data(), origin.size());
123     altsvc_vector_ = altsvc_vector;
124   }
125 
OnUnknownFrame(spdy::SpdyStreamId stream_id,uint8_t frame_type)126   bool OnUnknownFrame(spdy::SpdyStreamId stream_id,
127                       uint8_t frame_type) override {
128     return true;
129   }
130 
131   // Convenience function which runs a framer simulation with particular input.
SimulateInFramer(const spdy::SpdySerializedFrame & frame)132   void SimulateInFramer(const spdy::SpdySerializedFrame& frame) {
133     const char* input_ptr = frame.data();
134     size_t input_remaining = frame.size();
135     buffered_spdy_framer_.set_visitor(this);
136     while (input_remaining > 0 &&
137            buffered_spdy_framer_.spdy_framer_error() ==
138                http2::Http2DecoderAdapter::SPDY_NO_ERROR) {
139       // To make the tests more interesting, we feed random (amd small) chunks
140       // into the framer.  This simulates getting strange-sized reads from
141       // the socket.
142       const size_t kMaxReadSize = 32;
143       size_t bytes_read =
144           (rand() % std::min(input_remaining, kMaxReadSize)) + 1;
145       size_t bytes_processed =
146           buffered_spdy_framer_.ProcessInput(input_ptr, bytes_read);
147       input_remaining -= bytes_processed;
148       input_ptr += bytes_processed;
149     }
150   }
151 
152   BufferedSpdyFramer buffered_spdy_framer_;
153 
154   // Counters from the visitor callbacks.
155   int error_count_ = 0;
156   int setting_count_ = 0;
157   int headers_frame_count_ = 0;
158   int push_promise_frame_count_ = 0;
159   int goaway_count_ = 0;
160   int altsvc_count_ = 0;
161 
162   // Header block streaming state:
163   spdy::SpdyStreamId header_stream_id_;
164   spdy::SpdyStreamId promised_stream_id_;
165 
166   // Headers from OnHeaders and OnPushPromise for verification.
167   spdy::Http2HeaderBlock headers_;
168 
169   // OnGoAway parameters.
170   spdy::SpdyStreamId goaway_last_accepted_stream_id_;
171   spdy::SpdyErrorCode goaway_error_code_;
172   std::string goaway_debug_data_;
173 
174   // OnAltSvc parameters.
175   spdy::SpdyStreamId altsvc_stream_id_;
176   std::string altsvc_origin_;
177   spdy::SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector_;
178 };
179 
180 }  // namespace
181 
182 class BufferedSpdyFramerTest : public PlatformTest {};
183 
TEST_F(BufferedSpdyFramerTest,OnSetting)184 TEST_F(BufferedSpdyFramerTest, OnSetting) {
185   spdy::SpdyFramer framer(spdy::SpdyFramer::ENABLE_COMPRESSION);
186   spdy::SpdySettingsIR settings_ir;
187   settings_ir.AddSetting(spdy::SETTINGS_INITIAL_WINDOW_SIZE, 2);
188   settings_ir.AddSetting(spdy::SETTINGS_MAX_CONCURRENT_STREAMS, 3);
189   spdy::SpdySerializedFrame control_frame(
190       framer.SerializeSettings(settings_ir));
191   TestBufferedSpdyVisitor visitor;
192 
193   visitor.SimulateInFramer(control_frame);
194   EXPECT_EQ(0, visitor.error_count_);
195   EXPECT_EQ(2, visitor.setting_count_);
196 }
197 
TEST_F(BufferedSpdyFramerTest,HeaderListTooLarge)198 TEST_F(BufferedSpdyFramerTest, HeaderListTooLarge) {
199   spdy::Http2HeaderBlock headers;
200   std::string long_header_value(256 * 1024, 'x');
201   headers["foo"] = long_header_value;
202   spdy::SpdyHeadersIR headers_ir(/*stream_id=*/1, std::move(headers));
203 
204   NetLogWithSource net_log;
205   BufferedSpdyFramer framer(kMaxHeaderListSizeForTest, net_log);
206   spdy::SpdySerializedFrame control_frame = framer.SerializeFrame(headers_ir);
207 
208   TestBufferedSpdyVisitor visitor;
209   visitor.SimulateInFramer(control_frame);
210 
211   EXPECT_EQ(1, visitor.error_count_);
212   EXPECT_EQ(0, visitor.headers_frame_count_);
213   EXPECT_EQ(0, visitor.push_promise_frame_count_);
214   EXPECT_EQ(spdy::Http2HeaderBlock(), visitor.headers_);
215 }
216 
TEST_F(BufferedSpdyFramerTest,ValidHeadersAfterInvalidHeaders)217 TEST_F(BufferedSpdyFramerTest, ValidHeadersAfterInvalidHeaders) {
218   spdy::Http2HeaderBlock headers;
219   headers["invalid"] = "\r\n\r\n";
220 
221   spdy::Http2HeaderBlock headers2;
222   headers["alpha"] = "beta";
223 
224   SpdyTestUtil spdy_test_util;
225   spdy::SpdySerializedFrame headers_frame(
226       spdy_test_util.ConstructSpdyReply(1, std::move(headers)));
227   spdy::SpdySerializedFrame headers_frame2(
228       spdy_test_util.ConstructSpdyReply(2, std::move(headers2)));
229 
230   TestBufferedSpdyVisitor visitor;
231   visitor.SimulateInFramer(headers_frame);
232   EXPECT_EQ(1, visitor.error_count_);
233   EXPECT_EQ(0, visitor.headers_frame_count_);
234 
235   visitor.SimulateInFramer(headers_frame2);
236   EXPECT_EQ(1, visitor.error_count_);
237   EXPECT_EQ(1, visitor.headers_frame_count_);
238 }
239 
TEST_F(BufferedSpdyFramerTest,ReadHeadersHeaderBlock)240 TEST_F(BufferedSpdyFramerTest, ReadHeadersHeaderBlock) {
241   spdy::Http2HeaderBlock headers;
242   headers["alpha"] = "beta";
243   headers["gamma"] = "delta";
244   spdy::SpdyHeadersIR headers_ir(/*stream_id=*/1, headers.Clone());
245 
246   NetLogWithSource net_log;
247   BufferedSpdyFramer framer(kMaxHeaderListSizeForTest, net_log);
248   spdy::SpdySerializedFrame control_frame = framer.SerializeFrame(headers_ir);
249 
250   TestBufferedSpdyVisitor visitor;
251   visitor.SimulateInFramer(control_frame);
252   EXPECT_EQ(0, visitor.error_count_);
253   EXPECT_EQ(1, visitor.headers_frame_count_);
254   EXPECT_EQ(0, visitor.push_promise_frame_count_);
255   EXPECT_EQ(headers, visitor.headers_);
256 }
257 
TEST_F(BufferedSpdyFramerTest,ReadPushPromiseHeaderBlock)258 TEST_F(BufferedSpdyFramerTest, ReadPushPromiseHeaderBlock) {
259   spdy::Http2HeaderBlock headers;
260   headers["alpha"] = "beta";
261   headers["gamma"] = "delta";
262   NetLogWithSource net_log;
263   BufferedSpdyFramer framer(kMaxHeaderListSizeForTest, net_log);
264   spdy::SpdyPushPromiseIR push_promise_ir(
265       /*stream_id=*/1, /*promised_stream_id=*/2, headers.Clone());
266   spdy::SpdySerializedFrame control_frame =
267       framer.SerializeFrame(push_promise_ir);
268 
269   TestBufferedSpdyVisitor visitor;
270   visitor.SimulateInFramer(control_frame);
271   EXPECT_EQ(0, visitor.error_count_);
272   EXPECT_EQ(0, visitor.headers_frame_count_);
273   EXPECT_EQ(1, visitor.push_promise_frame_count_);
274   EXPECT_EQ(headers, visitor.headers_);
275   EXPECT_EQ(1u, visitor.header_stream_id_);
276   EXPECT_EQ(2u, visitor.promised_stream_id_);
277 }
278 
TEST_F(BufferedSpdyFramerTest,GoAwayDebugData)279 TEST_F(BufferedSpdyFramerTest, GoAwayDebugData) {
280   spdy::SpdyGoAwayIR go_ir(/*last_good_stream_id=*/2,
281                            spdy::ERROR_CODE_FRAME_SIZE_ERROR, "foo");
282   NetLogWithSource net_log;
283   BufferedSpdyFramer framer(kMaxHeaderListSizeForTest, net_log);
284   spdy::SpdySerializedFrame goaway_frame = framer.SerializeFrame(go_ir);
285 
286   TestBufferedSpdyVisitor visitor;
287   visitor.SimulateInFramer(goaway_frame);
288   EXPECT_EQ(0, visitor.error_count_);
289   EXPECT_EQ(1, visitor.goaway_count_);
290   EXPECT_EQ(2u, visitor.goaway_last_accepted_stream_id_);
291   EXPECT_EQ(spdy::ERROR_CODE_FRAME_SIZE_ERROR, visitor.goaway_error_code_);
292   EXPECT_EQ("foo", visitor.goaway_debug_data_);
293 }
294 
295 // ALTSVC frame on stream 0 must have an origin.
TEST_F(BufferedSpdyFramerTest,OnAltSvcOnStreamZero)296 TEST_F(BufferedSpdyFramerTest, OnAltSvcOnStreamZero) {
297   const spdy::SpdyStreamId altsvc_stream_id(0);
298   spdy::SpdyAltSvcIR altsvc_ir(altsvc_stream_id);
299   spdy::SpdyAltSvcWireFormat::AlternativeService alternative_service(
300       "quic", "alternative.example.org", 443, 86400,
301       spdy::SpdyAltSvcWireFormat::VersionVector());
302   altsvc_ir.add_altsvc(alternative_service);
303   const char altsvc_origin[] = "https://www.example.org";
304   altsvc_ir.set_origin(altsvc_origin);
305   NetLogWithSource net_log;
306   BufferedSpdyFramer framer(kMaxHeaderListSizeForTest, net_log);
307   spdy::SpdySerializedFrame altsvc_frame(framer.SerializeFrame(altsvc_ir));
308 
309   TestBufferedSpdyVisitor visitor;
310   visitor.SimulateInFramer(altsvc_frame);
311   EXPECT_EQ(0, visitor.error_count_);
312   EXPECT_EQ(1, visitor.altsvc_count_);
313   EXPECT_EQ(altsvc_stream_id, visitor.altsvc_stream_id_);
314   EXPECT_EQ(altsvc_origin, visitor.altsvc_origin_);
315   ASSERT_EQ(1u, visitor.altsvc_vector_.size());
316   EXPECT_EQ(alternative_service, visitor.altsvc_vector_[0]);
317 }
318 
319 // ALTSVC frame on a non-zero stream must not have an origin.
TEST_F(BufferedSpdyFramerTest,OnAltSvcOnNonzeroStream)320 TEST_F(BufferedSpdyFramerTest, OnAltSvcOnNonzeroStream) {
321   const spdy::SpdyStreamId altsvc_stream_id(1);
322   spdy::SpdyAltSvcIR altsvc_ir(altsvc_stream_id);
323   spdy::SpdyAltSvcWireFormat::AlternativeService alternative_service(
324       "quic", "alternative.example.org", 443, 86400,
325       spdy::SpdyAltSvcWireFormat::VersionVector());
326   altsvc_ir.add_altsvc(alternative_service);
327   NetLogWithSource net_log;
328   BufferedSpdyFramer framer(kMaxHeaderListSizeForTest, net_log);
329   spdy::SpdySerializedFrame altsvc_frame(framer.SerializeFrame(altsvc_ir));
330 
331   TestBufferedSpdyVisitor visitor;
332   visitor.SimulateInFramer(altsvc_frame);
333   EXPECT_EQ(0, visitor.error_count_);
334   EXPECT_EQ(1, visitor.altsvc_count_);
335   EXPECT_EQ(altsvc_stream_id, visitor.altsvc_stream_id_);
336   EXPECT_TRUE(visitor.altsvc_origin_.empty());
337   ASSERT_EQ(1u, visitor.altsvc_vector_.size());
338   EXPECT_EQ(alternative_service, visitor.altsvc_vector_[0]);
339 }
340 
341 }  // namespace net
342