1// Copyright (c) 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/tools/quic/quic_spdy_server_stream.h"
6
7#include "base/strings/string_number_conversions.h"
8#include "base/strings/string_piece.h"
9#include "net/quic/quic_connection.h"
10#include "net/quic/quic_protocol.h"
11#include "net/quic/quic_utils.h"
12#include "net/quic/test_tools/quic_test_utils.h"
13#include "net/tools/epoll_server/epoll_server.h"
14#include "net/tools/quic/quic_in_memory_cache.h"
15#include "net/tools/quic/spdy_utils.h"
16#include "net/tools/quic/test_tools/quic_in_memory_cache_peer.h"
17#include "net/tools/quic/test_tools/quic_test_utils.h"
18#include "testing/gmock/include/gmock/gmock.h"
19#include "testing/gtest/include/gtest/gtest.h"
20
21using base::StringPiece;
22using net::test::MockSession;
23using net::test::SupportedVersions;
24using net::tools::test::MockConnection;
25using std::string;
26using testing::_;
27using testing::AnyNumber;
28using testing::Invoke;
29using testing::InvokeArgument;
30using testing::InSequence;
31using testing::Return;
32using testing::StrictMock;
33using testing::WithArgs;
34
35namespace net {
36namespace tools {
37namespace test {
38
39class QuicSpdyServerStreamPeer : public QuicSpdyServerStream {
40 public:
41  QuicSpdyServerStreamPeer(QuicStreamId stream_id, QuicSession* session)
42      : QuicSpdyServerStream(stream_id, session) {
43  }
44
45  using QuicSpdyServerStream::SendResponse;
46  using QuicSpdyServerStream::SendErrorResponse;
47
48  BalsaHeaders* mutable_headers() {
49    return &headers_;
50  }
51
52  static void SendResponse(QuicSpdyServerStream* stream) {
53    stream->SendResponse();
54  }
55
56  static void SendErrorResponse(QuicSpdyServerStream* stream) {
57    stream->SendResponse();
58  }
59
60  static const string& body(QuicSpdyServerStream* stream) {
61    return stream->body_;
62  }
63
64  static const BalsaHeaders& headers(QuicSpdyServerStream* stream) {
65    return stream->headers_;
66  }
67};
68
69namespace {
70
71class QuicSpdyServerStreamTest : public ::testing::TestWithParam<QuicVersion> {
72 public:
73  QuicSpdyServerStreamTest()
74      : connection_(new StrictMock<MockConnection>(
75            true, SupportedVersions(GetParam()))),
76        session_(connection_),
77        body_("hello world") {
78    BalsaHeaders request_headers;
79    request_headers.SetRequestFirstlineFromStringPieces(
80        "POST", "https://www.google.com/", "HTTP/1.1");
81    request_headers.ReplaceOrAppendHeader("content-length", "11");
82
83    headers_string_ = SpdyUtils::SerializeRequestHeaders(request_headers);
84
85    // New streams rely on having the peer's flow control receive window
86    // negotiated in the config.
87    session_.config()->SetInitialFlowControlWindowToSend(
88        kInitialSessionFlowControlWindowForTest);
89    session_.config()->SetInitialStreamFlowControlWindowToSend(
90        kInitialStreamFlowControlWindowForTest);
91    session_.config()->SetInitialSessionFlowControlWindowToSend(
92        kInitialSessionFlowControlWindowForTest);
93    stream_.reset(new QuicSpdyServerStreamPeer(3, &session_));
94  }
95
96  static void SetUpTestCase() {
97    QuicInMemoryCachePeer::ResetForTests();
98  }
99
100  virtual void SetUp() OVERRIDE {
101    QuicInMemoryCache* cache = QuicInMemoryCache::GetInstance();
102
103    BalsaHeaders request_headers, response_headers;
104    StringPiece body("Yum");
105    request_headers.SetRequestFirstlineFromStringPieces(
106        "GET",
107        "https://www.google.com/foo",
108        "HTTP/1.1");
109    response_headers.SetRequestFirstlineFromStringPieces("HTTP/1.1",
110                                                         "200",
111                                                         "OK");
112    response_headers.AppendHeader("content-length",
113                                  base::IntToString(body.length()));
114
115    // Check if response already exists and matches.
116    const QuicInMemoryCache::Response* cached_response =
117        cache->GetResponse(request_headers);
118    if (cached_response != NULL) {
119      string cached_response_headers_str, response_headers_str;
120      cached_response->headers().DumpToString(&cached_response_headers_str);
121      response_headers.DumpToString(&response_headers_str);
122      CHECK_EQ(cached_response_headers_str, response_headers_str);
123      CHECK_EQ(cached_response->body(), body);
124      return;
125    }
126
127    cache->AddResponse(request_headers, response_headers, body);
128  }
129
130  const string& StreamBody() {
131    return QuicSpdyServerStreamPeer::body(stream_.get());
132  }
133
134  const BalsaHeaders& StreamHeaders() {
135    return QuicSpdyServerStreamPeer::headers(stream_.get());
136  }
137
138  BalsaHeaders response_headers_;
139  EpollServer eps_;
140  StrictMock<MockConnection>* connection_;
141  StrictMock<MockSession> session_;
142  scoped_ptr<QuicSpdyServerStreamPeer> stream_;
143  string headers_string_;
144  string body_;
145};
146
147QuicConsumedData ConsumeAllData(
148    QuicStreamId id,
149    const IOVector& data,
150    QuicStreamOffset offset,
151    bool fin,
152    FecProtection /*fec_protection_*/,
153    QuicAckNotifier::DelegateInterface* /*ack_notifier_delegate*/) {
154  return QuicConsumedData(data.TotalBufferSize(), fin);
155}
156
157INSTANTIATE_TEST_CASE_P(Tests, QuicSpdyServerStreamTest,
158                        ::testing::ValuesIn(QuicSupportedVersions()));
159
160TEST_P(QuicSpdyServerStreamTest, TestFraming) {
161  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(AnyNumber()).
162      WillRepeatedly(Invoke(ConsumeAllData));
163
164  EXPECT_EQ(headers_string_.size(), stream_->ProcessData(
165      headers_string_.c_str(), headers_string_.size()));
166  EXPECT_EQ(body_.size(), stream_->ProcessData(body_.c_str(), body_.size()));
167  EXPECT_EQ(11u, StreamHeaders().content_length());
168  EXPECT_EQ("https://www.google.com/", StreamHeaders().request_uri());
169  EXPECT_EQ("POST", StreamHeaders().request_method());
170  EXPECT_EQ(body_, StreamBody());
171}
172
173TEST_P(QuicSpdyServerStreamTest, TestFramingOnePacket) {
174  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(AnyNumber()).
175      WillRepeatedly(Invoke(ConsumeAllData));
176
177  string message = headers_string_ + body_;
178
179  EXPECT_EQ(message.size(), stream_->ProcessData(
180      message.c_str(), message.size()));
181  EXPECT_EQ(11u, StreamHeaders().content_length());
182  EXPECT_EQ("https://www.google.com/", StreamHeaders().request_uri());
183  EXPECT_EQ("POST", StreamHeaders().request_method());
184  EXPECT_EQ(body_, StreamBody());
185}
186
187TEST_P(QuicSpdyServerStreamTest, TestFramingExtraData) {
188  string large_body = "hello world!!!!!!";
189
190  // We'll automatically write out an error (headers + body)
191  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(AnyNumber()).
192      WillRepeatedly(Invoke(ConsumeAllData));
193
194  EXPECT_EQ(headers_string_.size(), stream_->ProcessData(
195      headers_string_.c_str(), headers_string_.size()));
196  // Content length is still 11.  This will register as an error and we won't
197  // accept the bytes.
198  stream_->ProcessData(large_body.c_str(), large_body.size());
199  EXPECT_EQ(11u, StreamHeaders().content_length());
200  EXPECT_EQ("https://www.google.com/", StreamHeaders().request_uri());
201  EXPECT_EQ("POST", StreamHeaders().request_method());
202}
203
204TEST_P(QuicSpdyServerStreamTest, TestSendResponse) {
205  BalsaHeaders* request_headers = stream_->mutable_headers();
206  request_headers->SetRequestFirstlineFromStringPieces(
207      "GET",
208      "https://www.google.com/foo",
209      "HTTP/1.1");
210
211  response_headers_.SetResponseFirstlineFromStringPieces(
212      "HTTP/1.1", "200", "OK");
213  response_headers_.ReplaceOrAppendHeader("content-length", "3");
214
215  InSequence s;
216  EXPECT_CALL(session_,
217              WritevData(kHeadersStreamId, _, 0, false, _, NULL));
218  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(1).
219      WillOnce(Return(QuicConsumedData(3, true)));
220
221  QuicSpdyServerStreamPeer::SendResponse(stream_.get());
222  EXPECT_TRUE(stream_->read_side_closed());
223  EXPECT_TRUE(stream_->write_side_closed());
224}
225
226TEST_P(QuicSpdyServerStreamTest, TestSendErrorResponse) {
227  response_headers_.SetResponseFirstlineFromStringPieces(
228      "HTTP/1.1", "500", "Server Error");
229  response_headers_.ReplaceOrAppendHeader("content-length", "3");
230
231  InSequence s;
232  EXPECT_CALL(session_,
233              WritevData(kHeadersStreamId, _, 0, false, _, NULL));
234  EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(1).
235      WillOnce(Return(QuicConsumedData(3, true)));
236
237  QuicSpdyServerStreamPeer::SendErrorResponse(stream_.get());
238  EXPECT_TRUE(stream_->read_side_closed());
239  EXPECT_TRUE(stream_->write_side_closed());
240}
241
242TEST_P(QuicSpdyServerStreamTest, InvalidHeadersWithFin) {
243  char arr[] = {
244    0x3a, 0x68, 0x6f, 0x73,  // :hos
245    0x74, 0x00, 0x00, 0x00,  // t...
246    0x00, 0x00, 0x00, 0x00,  // ....
247    0x07, 0x3a, 0x6d, 0x65,  // .:me
248    0x74, 0x68, 0x6f, 0x64,  // thod
249    0x00, 0x00, 0x00, 0x03,  // ....
250    0x47, 0x45, 0x54, 0x00,  // GET.
251    0x00, 0x00, 0x05, 0x3a,  // ...:
252    0x70, 0x61, 0x74, 0x68,  // path
253    0x00, 0x00, 0x00, 0x04,  // ....
254    0x2f, 0x66, 0x6f, 0x6f,  // /foo
255    0x00, 0x00, 0x00, 0x07,  // ....
256    0x3a, 0x73, 0x63, 0x68,  // :sch
257    0x65, 0x6d, 0x65, 0x00,  // eme.
258    0x00, 0x00, 0x00, 0x00,  // ....
259    0x00, 0x00, 0x08, 0x3a,  // ...:
260    0x76, 0x65, 0x72, 0x73,  // vers
261    '\x96', 0x6f, 0x6e, 0x00,  // <i(69)>on.
262    0x00, 0x00, 0x08, 0x48,  // ...H
263    0x54, 0x54, 0x50, 0x2f,  // TTP/
264    0x31, 0x2e, 0x31,        // 1.1
265  };
266  StringPiece data(arr, arraysize(arr));
267  QuicStreamFrame frame(stream_->id(), true, 0, MakeIOVector(data));
268  // Verify that we don't crash when we get a invalid headers in stream frame.
269  stream_->OnStreamFrame(frame);
270}
271
272}  // namespace
273}  // namespace test
274}  // namespace tools
275}  // namespace net
276