1// Copyright 2013 The Chromium Authors. All rights reserved.
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/quic/quic_headers_stream.h"
6
7#include "net/quic/quic_flags.h"
8#include "net/quic/quic_utils.h"
9#include "net/quic/spdy_utils.h"
10#include "net/quic/test_tools/quic_connection_peer.h"
11#include "net/quic/test_tools/quic_session_peer.h"
12#include "net/quic/test_tools/quic_test_utils.h"
13#include "net/spdy/spdy_protocol.h"
14#include "testing/gtest/include/gtest/gtest.h"
15
16using base::StringPiece;
17using std::string;
18using testing::Invoke;
19using testing::StrictMock;
20using testing::WithArgs;
21using testing::_;
22
23namespace net {
24namespace test {
25namespace {
26
27class MockVisitor : public SpdyFramerVisitorInterface {
28 public:
29  MOCK_METHOD1(OnError, void(SpdyFramer* framer));
30  MOCK_METHOD3(OnDataFrameHeader, void(SpdyStreamId stream_id,
31                                       size_t length,
32                                       bool fin));
33  MOCK_METHOD4(OnStreamFrameData, void(SpdyStreamId stream_id,
34                                       const char* data,
35                                       size_t len,
36                                       bool fin));
37  MOCK_METHOD3(OnControlFrameHeaderData, bool(SpdyStreamId stream_id,
38                                              const char* header_data,
39                                              size_t len));
40  MOCK_METHOD5(OnSynStream, void(SpdyStreamId stream_id,
41                                 SpdyStreamId associated_stream_id,
42                                 SpdyPriority priority,
43                                 bool fin,
44                                 bool unidirectional));
45  MOCK_METHOD2(OnSynReply, void(SpdyStreamId stream_id, bool fin));
46  MOCK_METHOD2(OnRstStream, void(SpdyStreamId stream_id,
47                                 SpdyRstStreamStatus status));
48  MOCK_METHOD1(OnSettings, void(bool clear_persisted));
49  MOCK_METHOD3(OnSetting, void(SpdySettingsIds id, uint8 flags, uint32 value));
50  MOCK_METHOD0(OnSettingsAck, void());
51  MOCK_METHOD0(OnSettingsEnd, void());
52  MOCK_METHOD2(OnPing, void(SpdyPingId unique_id, bool is_ack));
53  MOCK_METHOD2(OnGoAway, void(SpdyStreamId last_accepted_stream_id,
54                              SpdyGoAwayStatus status));
55  MOCK_METHOD3(OnHeaders, void(SpdyStreamId stream_id, bool fin, bool end));
56  MOCK_METHOD2(OnWindowUpdate, void(SpdyStreamId stream_id,
57                                    uint32 delta_window_size));
58  MOCK_METHOD2(OnCredentialFrameData, bool(const char* credential_data,
59                                           size_t len));
60  MOCK_METHOD1(OnBlocked, void(SpdyStreamId stream_id));
61  MOCK_METHOD3(OnPushPromise, void(SpdyStreamId stream_id,
62                                   SpdyStreamId promised_stream_id,
63                                   bool end));
64  MOCK_METHOD2(OnContinuation, void(SpdyStreamId stream_id, bool end));
65  MOCK_METHOD6(OnAltSvc, void(SpdyStreamId stream_id,
66                              uint32 max_age,
67                              uint16 port,
68                              StringPiece protocol_id,
69                              StringPiece host,
70                              StringPiece origin));
71};
72
73class QuicHeadersStreamTest : public ::testing::TestWithParam<bool> {
74 public:
75  static QuicVersionVector GetVersions() {
76    QuicVersionVector versions;
77    versions.push_back(QuicVersionMax());
78    return versions;
79  }
80
81  QuicHeadersStreamTest()
82      : connection_(new StrictMock<MockConnection>(is_server(), GetVersions())),
83        session_(connection_),
84        headers_stream_(QuicSessionPeer::GetHeadersStream(&session_)),
85        body_("hello world"),
86        framer_(SPDY3) {
87    headers_[":version"]  = "HTTP/1.1";
88    headers_[":status"] = "200 Ok";
89    headers_["content-length"] = "11";
90    framer_.set_visitor(&visitor_);
91    EXPECT_EQ(QuicVersionMax(), session_.connection()->version());
92    EXPECT_TRUE(headers_stream_ != NULL);
93  }
94
95  QuicConsumedData SaveIov(const IOVector& data) {
96    const iovec* iov = data.iovec();
97    int count = data.Capacity();
98    for (int i = 0 ; i < count; ++i) {
99      saved_data_.append(static_cast<char*>(iov[i].iov_base), iov[i].iov_len);
100    }
101    return QuicConsumedData(saved_data_.length(), false);
102  }
103
104  bool SaveHeaderData(const char* data, int len) {
105    saved_header_data_.append(data, len);
106    return true;
107  }
108
109  void SaveHeaderDataStringPiece(StringPiece data) {
110    saved_header_data_.append(data.data(), data.length());
111  }
112
113  void WriteHeadersAndExpectSynStream(QuicStreamId stream_id,
114                                      bool fin,
115                                      QuicPriority priority) {
116    WriteHeadersAndCheckData(stream_id, fin, priority, SYN_STREAM);
117  }
118
119  void WriteHeadersAndExpectSynReply(QuicStreamId stream_id,
120                                     bool fin) {
121    WriteHeadersAndCheckData(stream_id, fin, 0, SYN_REPLY);
122  }
123
124  void WriteHeadersAndCheckData(QuicStreamId stream_id,
125                                bool fin,
126                                QuicPriority priority,
127                                SpdyFrameType type) {
128    // Write the headers and capture the outgoing data
129    EXPECT_CALL(session_, WritevData(kHeadersStreamId, _, _, false, _, NULL))
130        .WillOnce(WithArgs<1>(Invoke(this, &QuicHeadersStreamTest::SaveIov)));
131    headers_stream_->WriteHeaders(stream_id, headers_, fin, NULL);
132
133    // Parse the outgoing data and check that it matches was was written.
134    if (type == SYN_STREAM) {
135      EXPECT_CALL(visitor_, OnSynStream(stream_id, kNoAssociatedStream, 0,
136                                        // priority,
137                                        fin, kNotUnidirectional));
138    } else {
139      EXPECT_CALL(visitor_, OnSynReply(stream_id, fin));
140    }
141    EXPECT_CALL(visitor_, OnControlFrameHeaderData(stream_id, _, _))
142        .WillRepeatedly(WithArgs<1, 2>(
143            Invoke(this, &QuicHeadersStreamTest::SaveHeaderData)));
144    if (fin) {
145      EXPECT_CALL(visitor_, OnStreamFrameData(stream_id, NULL, 0, true));
146    }
147    framer_.ProcessInput(saved_data_.data(), saved_data_.length());
148    EXPECT_FALSE(framer_.HasError()) << framer_.error_code();
149
150    CheckHeaders();
151    saved_data_.clear();
152  }
153
154  void CheckHeaders() {
155    SpdyHeaderBlock headers;
156    EXPECT_EQ(saved_header_data_.length(),
157              framer_.ParseHeaderBlockInBuffer(saved_header_data_.data(),
158                                               saved_header_data_.length(),
159                                               &headers));
160    EXPECT_EQ(headers_, headers);
161    saved_header_data_.clear();
162  }
163
164  bool is_server() {
165    return GetParam();
166  }
167
168  void CloseConnection() {
169    QuicConnectionPeer::CloseConnection(connection_);
170  }
171
172  static const bool kNotUnidirectional = false;
173  static const bool kNoAssociatedStream = false;
174
175  StrictMock<MockConnection>* connection_;
176  StrictMock<MockSession> session_;
177  QuicHeadersStream* headers_stream_;
178  SpdyHeaderBlock headers_;
179  string body_;
180  string saved_data_;
181  string saved_header_data_;
182  SpdyFramer framer_;
183  StrictMock<MockVisitor> visitor_;
184};
185
186INSTANTIATE_TEST_CASE_P(Tests, QuicHeadersStreamTest, testing::Bool());
187
188TEST_P(QuicHeadersStreamTest, StreamId) {
189  EXPECT_EQ(3u, headers_stream_->id());
190}
191
192TEST_P(QuicHeadersStreamTest, EffectivePriority) {
193  EXPECT_EQ(0u, headers_stream_->EffectivePriority());
194}
195
196TEST_P(QuicHeadersStreamTest, WriteHeaders) {
197  for (QuicStreamId stream_id = kClientDataStreamId1;
198       stream_id < kClientDataStreamId3; stream_id += 2) {
199    for (int count = 0; count < 2; ++count) {
200      bool fin = (count == 0);
201      if (is_server()) {
202        WriteHeadersAndExpectSynReply(stream_id, fin);
203      } else {
204        for (QuicPriority priority = 0; priority < 7; ++priority) {
205          WriteHeadersAndExpectSynStream(stream_id, fin, priority);
206        }
207      }
208    }
209  }
210}
211
212TEST_P(QuicHeadersStreamTest, ProcessRawData) {
213  for (QuicStreamId stream_id = kClientDataStreamId1;
214       stream_id < kClientDataStreamId3; stream_id += 2) {
215    for (int count = 0; count < 2; ++count) {
216      bool fin = (count == 0);
217      for (QuicPriority priority = 0; priority < 7; ++priority) {
218        // Replace with "WriteHeadersAndSaveData"
219        scoped_ptr<SpdySerializedFrame> frame;
220        if (is_server()) {
221          SpdySynStreamIR syn_stream(stream_id);
222          syn_stream.set_name_value_block(headers_);
223          syn_stream.set_fin(fin);
224          frame.reset(framer_.SerializeSynStream(syn_stream));
225          EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0));
226        } else {
227          SpdySynReplyIR syn_reply(stream_id);
228          syn_reply.set_name_value_block(headers_);
229          syn_reply.set_fin(fin);
230          frame.reset(framer_.SerializeSynReply(syn_reply));
231        }
232        EXPECT_CALL(session_, OnStreamHeaders(stream_id, _))
233            .WillRepeatedly(WithArgs<1>(
234                Invoke(this,
235                       &QuicHeadersStreamTest::SaveHeaderDataStringPiece)));
236        EXPECT_CALL(session_,
237                    OnStreamHeadersComplete(stream_id, fin, frame->size()));
238        headers_stream_->ProcessRawData(frame->data(), frame->size());
239
240        CheckHeaders();
241      }
242    }
243  }
244}
245
246TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrame) {
247  SpdyDataIR data(2, "");
248  scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
249  EXPECT_CALL(*connection_,
250              SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
251                                             "SPDY DATA frame received."))
252      .WillOnce(InvokeWithoutArgs(this,
253                                  &QuicHeadersStreamTest::CloseConnection));
254  headers_stream_->ProcessRawData(frame->data(), frame->size());
255}
256
257TEST_P(QuicHeadersStreamTest, ProcessSpdyRstStreamFrame) {
258  SpdyRstStreamIR data(2, RST_STREAM_PROTOCOL_ERROR, "");
259  scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
260  EXPECT_CALL(*connection_,
261              SendConnectionCloseWithDetails(
262                  QUIC_INVALID_HEADERS_STREAM_DATA,
263                  "SPDY RST_STREAM frame received."))
264      .WillOnce(InvokeWithoutArgs(this,
265                                  &QuicHeadersStreamTest::CloseConnection));
266  headers_stream_->ProcessRawData(frame->data(), frame->size());
267}
268
269TEST_P(QuicHeadersStreamTest, ProcessSpdySettingsFrame) {
270  SpdySettingsIR data;
271  data.AddSetting(SETTINGS_UPLOAD_BANDWIDTH, true, true, 0);
272  scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
273  EXPECT_CALL(*connection_,
274              SendConnectionCloseWithDetails(
275                  QUIC_INVALID_HEADERS_STREAM_DATA,
276                  "SPDY SETTINGS frame received."))
277      .WillOnce(InvokeWithoutArgs(this,
278                                  &QuicHeadersStreamTest::CloseConnection));
279  headers_stream_->ProcessRawData(frame->data(), frame->size());
280}
281
282TEST_P(QuicHeadersStreamTest, ProcessSpdyPingFrame) {
283  SpdyPingIR data(1);
284  scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
285  EXPECT_CALL(*connection_,
286              SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
287                                             "SPDY PING frame received."))
288      .WillOnce(InvokeWithoutArgs(this,
289                                  &QuicHeadersStreamTest::CloseConnection));
290  headers_stream_->ProcessRawData(frame->data(), frame->size());
291}
292
293TEST_P(QuicHeadersStreamTest, ProcessSpdyGoAwayFrame) {
294  SpdyGoAwayIR data(1, GOAWAY_PROTOCOL_ERROR, "go away");
295  scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
296  EXPECT_CALL(*connection_,
297              SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
298                                             "SPDY GOAWAY frame received."))
299      .WillOnce(InvokeWithoutArgs(this,
300                                  &QuicHeadersStreamTest::CloseConnection));
301  headers_stream_->ProcessRawData(frame->data(), frame->size());
302}
303
304TEST_P(QuicHeadersStreamTest, ProcessSpdyHeadersFrame) {
305  SpdyHeadersIR data(1);
306  scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
307  EXPECT_CALL(*connection_,
308              SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
309                                             "SPDY HEADERS frame received."))
310      .WillOnce(InvokeWithoutArgs(this,
311                                  &QuicHeadersStreamTest::CloseConnection));
312  headers_stream_->ProcessRawData(frame->data(), frame->size());
313}
314
315TEST_P(QuicHeadersStreamTest, ProcessSpdyWindowUpdateFrame) {
316  SpdyWindowUpdateIR data(1, 1);
317  scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
318  EXPECT_CALL(*connection_,
319              SendConnectionCloseWithDetails(
320                  QUIC_INVALID_HEADERS_STREAM_DATA,
321                  "SPDY WINDOW_UPDATE frame received."))
322      .WillOnce(InvokeWithoutArgs(this,
323                                  &QuicHeadersStreamTest::CloseConnection));
324  headers_stream_->ProcessRawData(frame->data(), frame->size());
325}
326
327TEST_P(QuicHeadersStreamTest, NoFlowControl) {
328  ValueRestore<bool> old_flag(&FLAGS_enable_quic_stream_flow_control_2, true);
329  EXPECT_FALSE(headers_stream_->flow_controller()->IsEnabled());
330}
331
332}  // namespace
333}  // namespace test
334}  // namespace net
335