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