1// Copyright (c) 2012 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_reliable_server_stream.h"
6
7#include "base/strings/string_number_conversions.h"
8#include "net/quic/quic_spdy_compressor.h"
9#include "net/quic/quic_utils.h"
10#include "net/quic/test_tools/quic_test_utils.h"
11#include "net/tools/flip_server/epoll_server.h"
12#include "net/tools/quic/quic_in_memory_cache.h"
13#include "net/tools/quic/quic_spdy_server_stream.h"
14#include "net/tools/quic/spdy_utils.h"
15#include "net/tools/quic/test_tools/quic_test_utils.h"
16#include "testing/gmock/include/gmock/gmock.h"
17#include "testing/gtest/include/gtest/gtest.h"
18
19using base::StringPiece;
20using net::tools::test::MockConnection;
21using net::test::MockSession;
22using std::string;
23using testing::_;
24using testing::AnyNumber;
25using testing::Invoke;
26using testing::InvokeArgument;
27using testing::InSequence;
28using testing::Return;
29using testing::StrEq;
30using testing::StrictMock;
31using testing::WithArgs;
32
33namespace net {
34namespace tools {
35namespace test {
36
37class QuicReliableServerStreamPeer {
38 public:
39  static BalsaHeaders* GetMutableHeaders(
40      QuicReliableServerStream* stream) {
41    return &(stream->headers_);
42  }
43};
44
45namespace {
46
47class QuicReliableServerStreamTest : public ::testing::Test {
48 public:
49  QuicReliableServerStreamTest()
50      : session_(new MockConnection(1, IPEndPoint(), 0, &eps_, true), true),
51        body_("hello world") {
52    BalsaHeaders request_headers;
53    request_headers.SetRequestFirstlineFromStringPieces(
54        "POST", "https://www.google.com/", "HTTP/1.1");
55    request_headers.ReplaceOrAppendHeader("content-length", "11");
56
57    headers_string_ = SpdyUtils::SerializeRequestHeaders(request_headers);
58    stream_.reset(new QuicSpdyServerStream(3, &session_));
59  }
60
61  QuicConsumedData ValidateHeaders(StringPiece headers) {
62    headers_string_ = SpdyUtils::SerializeResponseHeaders(
63        response_headers_);
64    QuicSpdyDecompressor decompressor;
65    TestDecompressorVisitor visitor;
66
67    // First the header id, then the compressed data.
68    EXPECT_EQ(1, headers[0]);
69    EXPECT_EQ(0, headers[1]);
70    EXPECT_EQ(0, headers[2]);
71    EXPECT_EQ(0, headers[3]);
72    EXPECT_EQ(static_cast<size_t>(headers.length() - 4),
73              decompressor.DecompressData(headers.substr(4), &visitor));
74
75    EXPECT_EQ(headers_string_, visitor.data());
76
77    return QuicConsumedData(headers.size(), false);
78  }
79
80  static void SetUpTestCase() {
81    QuicInMemoryCache::GetInstance()->ResetForTests();
82  }
83
84  virtual void SetUp() {
85    QuicInMemoryCache* cache = QuicInMemoryCache::GetInstance();
86
87    BalsaHeaders request_headers, response_headers;
88    StringPiece body("Yum");
89    request_headers.SetRequestFirstlineFromStringPieces(
90        "GET",
91        "https://www.google.com/foo",
92        "HTTP/1.1");
93    response_headers.SetRequestFirstlineFromStringPieces("HTTP/1.1",
94                                                         "200",
95                                                         "OK");
96    response_headers.AppendHeader("content-length",
97                                  base::IntToString(body.length()));
98
99    // Check if response already exists and matches.
100    const QuicInMemoryCache::Response* cached_response =
101        cache->GetResponse(request_headers);
102    if (cached_response != NULL) {
103      string cached_response_headers_str, response_headers_str;
104      cached_response->headers().DumpToString(&cached_response_headers_str);
105      response_headers.DumpToString(&response_headers_str);
106      CHECK_EQ(cached_response_headers_str, response_headers_str);
107      CHECK_EQ(cached_response->body(), body);
108      return;
109    }
110
111    cache->AddResponse(request_headers, response_headers, body);
112  }
113
114  BalsaHeaders response_headers_;
115  EpollServer eps_;
116  StrictMock<MockSession> session_;
117  scoped_ptr<QuicReliableServerStream> stream_;
118  string headers_string_;
119  string body_;
120};
121
122QuicConsumedData ConsumeAllData(QuicStreamId id, StringPiece data,
123                                QuicStreamOffset offset, bool fin) {
124  return QuicConsumedData(data.size(), fin);
125}
126
127TEST_F(QuicReliableServerStreamTest, TestFraming) {
128  EXPECT_CALL(session_, WriteData(_, _, _, _)).Times(AnyNumber()).
129      WillRepeatedly(Invoke(ConsumeAllData));
130
131  EXPECT_EQ(headers_string_.size(), stream_->ProcessData(
132      headers_string_.c_str(), headers_string_.size()));
133  EXPECT_EQ(body_.size(), stream_->ProcessData(body_.c_str(), body_.size()));
134  EXPECT_EQ(11u, stream_->headers().content_length());
135  EXPECT_EQ("https://www.google.com/", stream_->headers().request_uri());
136  EXPECT_EQ("POST", stream_->headers().request_method());
137  EXPECT_EQ(body_, stream_->body());
138}
139
140TEST_F(QuicReliableServerStreamTest, TestFramingOnePacket) {
141  EXPECT_CALL(session_, WriteData(_, _, _, _)).Times(AnyNumber()).
142      WillRepeatedly(Invoke(ConsumeAllData));
143
144  string message = headers_string_ + body_;
145
146  EXPECT_EQ(message.size(), stream_->ProcessData(
147      message.c_str(), message.size()));
148  EXPECT_EQ(11u, stream_->headers().content_length());
149  EXPECT_EQ("https://www.google.com/",
150            stream_->headers().request_uri());
151  EXPECT_EQ("POST", stream_->headers().request_method());
152  EXPECT_EQ(body_, stream_->body());
153}
154
155TEST_F(QuicReliableServerStreamTest, TestFramingExtraData) {
156  string large_body = "hello world!!!!!!";
157
158  // We'll automatically write out an error (headers + body)
159  EXPECT_CALL(session_, WriteData(_, _, _, _)).Times(2).
160      WillRepeatedly(Invoke(ConsumeAllData));
161
162  EXPECT_EQ(headers_string_.size(), stream_->ProcessData(
163      headers_string_.c_str(), headers_string_.size()));
164  // Content length is still 11.  This will register as an error and we won't
165  // accept the bytes.
166  stream_->ProcessData(large_body.c_str(), large_body.size());
167  stream_->TerminateFromPeer(true);
168  EXPECT_EQ(11u, stream_->headers().content_length());
169  EXPECT_EQ("https://www.google.com/", stream_->headers().request_uri());
170  EXPECT_EQ("POST", stream_->headers().request_method());
171}
172
173TEST_F(QuicReliableServerStreamTest, TestSendResponse) {
174  BalsaHeaders* request_headers =
175      QuicReliableServerStreamPeer::GetMutableHeaders(stream_.get());
176  request_headers->SetRequestFirstlineFromStringPieces(
177      "GET",
178      "https://www.google.com/foo",
179      "HTTP/1.1");
180
181  response_headers_.SetResponseFirstlineFromStringPieces(
182      "HTTP/1.1", "200", "OK");
183  response_headers_.ReplaceOrAppendHeader("content-length", "3");
184
185  InSequence s;
186  EXPECT_CALL(session_, WriteData(_, _, _, _)).Times(1)
187      .WillOnce(WithArgs<1>(Invoke(
188          this, &QuicReliableServerStreamTest::ValidateHeaders)));
189  StringPiece kBody = "Yum";
190  EXPECT_CALL(session_, WriteData(_, kBody, _, _)).Times(1).
191      WillOnce(Return(QuicConsumedData(3, true)));
192
193  stream_->SendResponse();
194  EXPECT_TRUE(stream_->read_side_closed());
195  EXPECT_TRUE(stream_->write_side_closed());
196}
197
198TEST_F(QuicReliableServerStreamTest, TestSendErrorResponse) {
199  response_headers_.SetResponseFirstlineFromStringPieces(
200      "HTTP/1.1", "500", "Server Error");
201  response_headers_.ReplaceOrAppendHeader("content-length", "3");
202
203  InSequence s;
204  EXPECT_CALL(session_, WriteData(_, _, _, _)).Times(1)
205      .WillOnce(WithArgs<1>(Invoke(
206          this, &QuicReliableServerStreamTest::ValidateHeaders)));
207  StringPiece kBody = "bad";
208  EXPECT_CALL(session_, WriteData(_, kBody, _, _)).Times(1).
209      WillOnce(Return(QuicConsumedData(3, true)));
210
211  stream_->SendErrorResponse();
212  EXPECT_TRUE(stream_->read_side_closed());
213  EXPECT_TRUE(stream_->write_side_closed());
214}
215
216}  // namespace
217}  // namespace test
218}  // namespace tools
219}  // namespace net
220