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