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