Commit aa7859a1 authored by rch's avatar rch Committed by Commit bot

Make some changes to the QuicInMemory server to clarify the interface.

Specifically that the cache is indexed by host and path, not by method
nor scheme, nor full URL, nor request headers, etc. In preparation for
making the chrome version more similar.

Merge internal change: 89092881

Review URL: https://codereview.chromium.org/1028923002

Cr-Commit-Position: refs/heads/master@{#321883}
parent 741de3a5
......@@ -158,14 +158,12 @@ class QuicEndToEndTest : public PlatformTest {
// Adds an entry to the cache used by the QUIC server to serve
// responses.
void AddToCache(const StringPiece& method,
const StringPiece& path,
const StringPiece& version,
const StringPiece& response_code,
const StringPiece& response_detail,
const StringPiece& body) {
void AddToCache(StringPiece path,
int response_code,
StringPiece response_detail,
StringPiece body) {
QuicInMemoryCache::GetInstance()->AddSimpleResponse(
method, path, version, response_code, response_detail, body);
"www.google.com", path, response_code, response_detail, body);
}
// Populates |request_body_| with |length_| ASCII bytes.
......@@ -227,9 +225,7 @@ class QuicEndToEndTest : public PlatformTest {
TEST_F(QuicEndToEndTest, LargeGetWithNoPacketLoss) {
std::string response(10 * 1024, 'x');
AddToCache("GET", request_.url.spec(),
"HTTP/1.1", "200", "OK",
response);
AddToCache(request_.url.PathForRequest(), 200, "OK", response);
TestTransactionConsumer consumer(DEFAULT_PRIORITY,
transaction_factory_.get());
......@@ -245,9 +241,7 @@ TEST_F(QuicEndToEndTest, LargeGetWithNoPacketLoss) {
TEST_F(QuicEndToEndTest, DISABLED_LargePostWithNoPacketLoss) {
InitializePostRequest(10 * 1024 * 1024);
AddToCache("POST", request_.url.spec(),
"HTTP/1.1", "200", "OK",
kResponseBody);
AddToCache(request_.url.PathForRequest(), 200, "OK", kResponseBody);
TestTransactionConsumer consumer(DEFAULT_PRIORITY,
transaction_factory_.get());
......@@ -264,9 +258,7 @@ TEST_F(QuicEndToEndTest, LargePostWithPacketLoss) {
InitializePostRequest(1024 * 1024);
const char kResponseBody[] = "some really big response body";
AddToCache("POST", request_.url.spec(),
"HTTP/1.1", "200", "OK",
kResponseBody);
AddToCache(request_.url.PathForRequest(), 200, "OK", kResponseBody);
TestTransactionConsumer consumer(DEFAULT_PRIORITY,
transaction_factory_.get());
......@@ -282,9 +274,7 @@ TEST_F(QuicEndToEndTest, UberTest) {
// FLAGS_fake_packet_loss_percentage = 30;
const char kResponseBody[] = "some really big response body";
AddToCache("GET", request_.url.spec(),
"HTTP/1.1", "200", "OK",
kResponseBody);
AddToCache(request_.url.PathForRequest(), 200, "OK", kResponseBody);
std::vector<TestTransactionConsumer*> consumers;
size_t num_requests = 100;
......
......@@ -212,10 +212,8 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
3 * kInitialSessionFlowControlWindowForTest);
QuicInMemoryCachePeer::ResetForTests();
AddToCache("GET", "https://www.google.com/foo",
"HTTP/1.1", "200", "OK", kFooResponseBody);
AddToCache("GET", "https://www.google.com/bar",
"HTTP/1.1", "200", "OK", kBarResponseBody);
AddToCache("/foo", 200, "OK", kFooResponseBody);
AddToCache("/bar", 200, "OK", kBarResponseBody);
}
~EndToEndTest() override {
......@@ -343,14 +341,12 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
}
}
void AddToCache(StringPiece method,
StringPiece path,
StringPiece version,
StringPiece response_code,
void AddToCache(StringPiece path,
int response_code,
StringPiece response_detail,
StringPiece body) {
QuicInMemoryCache::GetInstance()->AddSimpleResponse(
method, path, version, response_code, response_detail, body);
"www.google.com", path, response_code, response_detail, body);
}
void SetPacketLossPercentage(int32 loss) {
......@@ -502,9 +498,8 @@ TEST_P(EndToEndTest, MultipleClients) {
TEST_P(EndToEndTest, RequestOverMultiplePackets) {
// Send a large enough request to guarantee fragmentation.
string huge_request =
"https://www.google.com/some/path?query=" + string(kMaxPacketSize, '.');
AddToCache("GET", huge_request, "HTTP/1.1", "200", "OK", kBarResponseBody);
string huge_request = "/some/path?query=" + string(kMaxPacketSize, '.');
AddToCache(huge_request, 200, "OK", kBarResponseBody);
ASSERT_TRUE(Initialize());
......@@ -514,9 +509,8 @@ TEST_P(EndToEndTest, RequestOverMultiplePackets) {
TEST_P(EndToEndTest, MultiplePacketsRandomOrder) {
// Send a large enough request to guarantee fragmentation.
string huge_request =
"https://www.google.com/some/path?query=" + string(kMaxPacketSize, '.');
AddToCache("GET", huge_request, "HTTP/1.1", "200", "OK", kBarResponseBody);
string huge_request = "/some/path?query=" + string(kMaxPacketSize, '.');
AddToCache(huge_request, 200, "OK", kBarResponseBody);
ASSERT_TRUE(Initialize());
SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2));
......@@ -1068,7 +1062,7 @@ TEST_P(EndToEndTest, MaxStreamsUberTest) {
GenerateBody(&large_body, 10240);
int max_streams = 100;
AddToCache("GET", "/large_response", "HTTP/1.1", "200", "OK", large_body);;
AddToCache("/large_response", 200, "OK", large_body);;
client_->client()->WaitForCryptoHandshakeConfirmed();
SetPacketLossPercentage(10);
......@@ -1088,7 +1082,7 @@ TEST_P(EndToEndTest, StreamCancelErrorTest) {
string small_body;
GenerateBody(&small_body, 256);
AddToCache("GET", "/small_response", "HTTP/1.1", "200", "OK", small_body);
AddToCache("/small_response", 200, "OK", small_body);
client_->client()->WaitForCryptoHandshakeConfirmed();
......
......@@ -14,14 +14,13 @@ using base::FilePath;
using base::StringPiece;
using std::string;
// Specifies the directory used during QuicInMemoryCache
// construction to seed the cache. Cache directory can be
// generated using `wget -p --save-headers <url>
namespace net {
namespace tools {
std::string FLAGS_quic_in_memory_cache_dir = "";
// Specifies the directory used during QuicInMemoryCache
// construction to seed the cache. Cache directory can be
// generated using `wget -p --save-headers <url>
string FLAGS_quic_in_memory_cache_dir = "";
namespace {
......@@ -59,57 +58,41 @@ QuicInMemoryCache* QuicInMemoryCache::GetInstance() {
}
const QuicInMemoryCache::Response* QuicInMemoryCache::GetResponse(
const BalsaHeaders& request_headers) const {
ResponseMap::const_iterator it = responses_.find(GetKey(request_headers));
StringPiece host,
StringPiece path) const {
ResponseMap::const_iterator it = responses_.find(GetKey(host, path));
if (it == responses_.end()) {
return nullptr;
}
return it->second;
}
void QuicInMemoryCache::AddSimpleResponse(StringPiece method,
void QuicInMemoryCache::AddSimpleResponse(StringPiece host,
StringPiece path,
StringPiece version,
StringPiece response_code,
int response_code,
StringPiece response_detail,
StringPiece body) {
BalsaHeaders request_headers, response_headers;
request_headers.SetRequestFirstlineFromStringPieces(method,
path,
version);
response_headers.SetRequestFirstlineFromStringPieces(version,
response_code,
response_detail);
BalsaHeaders response_headers;
response_headers.SetRequestFirstlineFromStringPieces(
"HTTP/1.1", base::IntToString(response_code), response_detail);
response_headers.AppendHeader("content-length",
base::IntToString(body.length()));
AddResponse(request_headers, response_headers, body);
AddResponse(host, path, response_headers, body);
}
void QuicInMemoryCache::AddResponse(const BalsaHeaders& request_headers,
void QuicInMemoryCache::AddResponse(StringPiece host,
StringPiece path,
const BalsaHeaders& response_headers,
StringPiece response_body) {
VLOG(1) << "Adding response for: " << GetKey(request_headers);
if (ContainsKey(responses_, GetKey(request_headers))) {
LOG(DFATAL) << "Response for given request already exists!";
return;
}
Response* new_response = new Response();
new_response->set_headers(response_headers);
new_response->set_body(response_body);
responses_[GetKey(request_headers)] = new_response;
AddResponseImpl(host, path, REGULAR_RESPONSE, response_headers,
response_body);
}
void QuicInMemoryCache::AddSpecialResponse(StringPiece method,
void QuicInMemoryCache::AddSpecialResponse(StringPiece host,
StringPiece path,
StringPiece version,
SpecialResponseType response_type) {
BalsaHeaders request_headers, response_headers;
request_headers.SetRequestFirstlineFromStringPieces(method,
path,
version);
AddResponse(request_headers, response_headers, "");
responses_[GetKey(request_headers)]->response_type_ = response_type;
AddResponseImpl(host, path, response_type, BalsaHeaders(), "");
}
QuicInMemoryCache::QuicInMemoryCache() {
......@@ -135,11 +118,10 @@ void QuicInMemoryCache::Initialize() {
true,
base::FileEnumerator::FILES);
FilePath file = file_list.Next();
while (!file.empty()) {
for (FilePath file = file_list.Next(); !file.empty();
file = file_list.Next()) {
// Need to skip files in .svn directories
if (file.value().find("/.svn/") != std::string::npos) {
file = file_list.Next();
if (file.value().find("/.svn/") != string::npos) {
continue;
}
......@@ -193,18 +175,7 @@ void QuicInMemoryCache::Initialize() {
if (path[path.length() - 1] == ',') {
path.remove_suffix(1);
}
// Set up request headers. Assume method is GET and protocol is HTTP/1.1.
request_headers.SetRequestFirstlineFromStringPieces("GET",
path,
"HTTP/1.1");
request_headers.ReplaceOrAppendHeader("host", host);
VLOG(1) << "Inserting 'http://" << GetKey(request_headers)
<< "' into QuicInMemoryCache.";
AddResponse(request_headers, response_headers, caching_visitor.body());
file = file_list.Next();
AddResponse(host, path, response_headers, caching_visitor.body());
}
}
......@@ -212,20 +183,27 @@ QuicInMemoryCache::~QuicInMemoryCache() {
STLDeleteValues(&responses_);
}
string QuicInMemoryCache::GetKey(const BalsaHeaders& request_headers) const {
StringPiece uri = request_headers.request_uri();
if (uri.size() == 0) {
return "";
}
StringPiece host;
if (uri[0] == '/') {
host = request_headers.GetHeader("host");
} else if (StringPieceUtils::StartsWithIgnoreCase(uri, "https://")) {
uri.remove_prefix(8);
} else if (StringPieceUtils::StartsWithIgnoreCase(uri, "http://")) {
uri.remove_prefix(7);
void QuicInMemoryCache::AddResponseImpl(
StringPiece host,
StringPiece path,
SpecialResponseType response_type,
const BalsaHeaders& response_headers,
StringPiece response_body) {
string key = GetKey(host, path);
VLOG(1) << "Adding response for: " << key;
if (ContainsKey(responses_, key)) {
LOG(DFATAL) << "Response for '" << key << "' already exists!";
return;
}
return host.as_string() + uri.as_string();
Response* new_response = new Response();
new_response->set_response_type(response_type);
new_response->set_headers(response_headers);
new_response->set_body(response_body);
responses_[key] = new_response;
}
string QuicInMemoryCache::GetKey(StringPiece host, StringPiece path) const {
return host.as_string() + path.as_string();
}
} // namespace tools
......
......@@ -51,6 +51,9 @@ class QuicInMemoryCache {
private:
friend class QuicInMemoryCache;
void set_response_type(SpecialResponseType response_type) {
response_type_ = response_type;
}
void set_headers(const BalsaHeaders& headers) {
headers_.CopyFrom(headers);
}
......@@ -68,29 +71,28 @@ class QuicInMemoryCache {
// Returns the singleton instance of the cache.
static QuicInMemoryCache* GetInstance();
// Retrieve a response from this cache for a given request.
// Retrieve a response from this cache for a given host and path..
// If no appropriate response exists, nullptr is returned.
// Currently, responses are selected based on request URI only.
const Response* GetResponse(const BalsaHeaders& request_headers) const;
const Response* GetResponse(base::StringPiece host,
base::StringPiece path) const;
// Adds a simple response to the cache. The response headers will
// only contain the "content-length" header with the lenght of |body|.
void AddSimpleResponse(base::StringPiece method,
// only contain the "content-length" header with the length of |body|.
void AddSimpleResponse(base::StringPiece host,
base::StringPiece path,
base::StringPiece version,
base::StringPiece response_code,
int response_code,
base::StringPiece response_detail,
base::StringPiece body);
// Add a response to the cache.
void AddResponse(const BalsaHeaders& request_headers,
void AddResponse(base::StringPiece host,
base::StringPiece path,
const BalsaHeaders& response_headers,
base::StringPiece response_body);
// Simulate a special behavior at a particular path.
void AddSpecialResponse(base::StringPiece method,
void AddSpecialResponse(base::StringPiece host,
base::StringPiece path,
base::StringPiece version,
SpecialResponseType response_type);
private:
......@@ -105,7 +107,13 @@ class QuicInMemoryCache {
void Initialize();
std::string GetKey(const BalsaHeaders& response_headers) const;
void AddResponseImpl(base::StringPiece host,
base::StringPiece path,
SpecialResponseType response_type,
const BalsaHeaders& response_headers,
base::StringPiece response_body);
std::string GetKey(base::StringPiece host, base::StringPiece path) const;
// Cached responses.
ResponseMap responses_;
......
......@@ -16,6 +16,7 @@
using base::IntToString;
using base::StringPiece;
using std::string;
namespace net {
namespace tools {
......@@ -32,102 +33,60 @@ class QuicInMemoryCacheTest : public ::testing::Test {
FLAGS_quic_in_memory_cache_dir = path.MaybeAsASCII();
}
void CreateRequest(std::string host,
std::string path,
net::BalsaHeaders* headers) {
~QuicInMemoryCacheTest() override { QuicInMemoryCachePeer::ResetForTests(); }
void CreateRequest(StringPiece host,
StringPiece path,
BalsaHeaders* headers) {
headers->SetRequestFirstlineFromStringPieces("GET", path, "HTTP/1.1");
headers->ReplaceOrAppendHeader("host", host);
}
void SetUp() override { QuicInMemoryCachePeer::ResetForTests(); }
// This method was copied from end_to_end_test.cc in this directory.
void AddToCache(const StringPiece& method,
const StringPiece& path,
const StringPiece& version,
const StringPiece& response_code,
const StringPiece& response_detail,
const StringPiece& body) {
BalsaHeaders request_headers, response_headers;
request_headers.SetRequestFirstlineFromStringPieces(method,
path,
version);
response_headers.SetRequestFirstlineFromStringPieces(version,
response_code,
response_detail);
response_headers.AppendHeader("content-length",
base::IntToString(body.length()));
// Check if response already exists and matches.
QuicInMemoryCache* cache = QuicInMemoryCache::GetInstance();
const QuicInMemoryCache::Response* cached_response =
cache->GetResponse(request_headers);
if (cached_response != nullptr) {
std::string cached_response_headers_str, response_headers_str;
cached_response->headers().DumpToString(&cached_response_headers_str);
response_headers.DumpToString(&response_headers_str);
CHECK_EQ(cached_response_headers_str, response_headers_str);
CHECK_EQ(cached_response->body(), body);
return;
}
cache->AddResponse(request_headers, response_headers, body);
}
};
TEST_F(QuicInMemoryCacheTest, AddResponseGetResponse) {
std::string response_body("hello response");
AddToCache("GET", "https://www.google.com/bar",
"HTTP/1.1", "200", "OK", response_body);
net::BalsaHeaders request_headers;
CreateRequest("www.google.com", "/bar", &request_headers);
TEST_F(QuicInMemoryCacheTest, AddSimpleResponseGetResponse) {
string response_body("hello response");
QuicInMemoryCache* cache = QuicInMemoryCache::GetInstance();
const QuicInMemoryCache::Response* response =
cache->GetResponse(request_headers);
ASSERT_TRUE(response);
EXPECT_EQ("200", response->headers().response_code());
EXPECT_EQ(response_body.size(), response->body().length());
cache->AddSimpleResponse("www.google.com", "/", 200, "OK", response_body);
CreateRequest("", "https://www.google.com/bar", &request_headers);
response = cache->GetResponse(request_headers);
BalsaHeaders request_headers;
CreateRequest("www.google.com", "/", &request_headers);
const QuicInMemoryCache::Response* response =
cache->GetResponse("www.google.com", "/");
ASSERT_TRUE(response);
EXPECT_EQ("200", response->headers().response_code());
EXPECT_EQ(response_body.size(), response->body().length());
}
TEST_F(QuicInMemoryCacheTest, ReadsCacheDir) {
net::BalsaHeaders request_headers;
CreateRequest("quic.test.url", "/index.html", &request_headers);
const QuicInMemoryCache::Response* response =
QuicInMemoryCache::GetInstance()->GetResponse(request_headers);
QuicInMemoryCache::GetInstance()->GetResponse("quic.test.url",
"/index.html");
ASSERT_TRUE(response);
std::string value;
string value;
response->headers().GetAllOfHeaderAsString("Connection", &value);
EXPECT_EQ("200", response->headers().response_code());
EXPECT_EQ("Keep-Alive", value);
EXPECT_LT(0U, response->body().length());
}
TEST_F(QuicInMemoryCacheTest, ReadsCacheDirHttp) {
net::BalsaHeaders request_headers;
CreateRequest("", "http://quic.test.url/index.html", &request_headers);
TEST_F(QuicInMemoryCacheTest, UsesOriginalUrl) {
const QuicInMemoryCache::Response* response =
QuicInMemoryCache::GetInstance()->GetResponse(request_headers);
QuicInMemoryCache::GetInstance()->GetResponse("quic.test.url",
"/index.html");
ASSERT_TRUE(response);
std::string value;
response->headers().GetAllOfHeaderAsString("Connection", &value);
EXPECT_EQ("200", response->headers().response_code());
EXPECT_EQ("Keep-Alive", value);
string value;
response->headers().GetAllOfHeaderAsString("Connection", &value);
EXPECT_LT(0U, response->body().length());
}
TEST_F(QuicInMemoryCacheTest, GetResponseNoMatch) {
net::BalsaHeaders request_headers;
CreateRequest("www.google.com", "/index.html", &request_headers);
const QuicInMemoryCache::Response* response =
QuicInMemoryCache::GetInstance()->GetResponse(request_headers);
QuicInMemoryCache::GetInstance()->GetResponse("mail.google.com",
"/index.html");
ASSERT_FALSE(response);
}
......
......@@ -9,6 +9,7 @@
#include "net/spdy/spdy_framer.h"
#include "net/tools/quic/quic_in_memory_cache.h"
#include "net/tools/quic/spdy_utils.h"
#include "url/gurl.h"
using base::StringPiece;
using std::string;
......@@ -90,8 +91,15 @@ void QuicSpdyServerStream::ParseRequestHeaders() {
void QuicSpdyServerStream::SendResponse() {
// Find response in cache. If not found, send error response.
GURL url(headers_.request_uri().as_string());
if (!url.is_valid()) {
SendErrorResponse();
return;
}
const QuicInMemoryCache::Response* response =
QuicInMemoryCache::GetInstance()->GetResponse(headers_);
QuicInMemoryCache::GetInstance()->GetResponse(
url.host(),
url.PathForRequest());
if (response == nullptr) {
SendErrorResponse();
return;
......
......@@ -100,21 +100,19 @@ class QuicSpdyServerStreamTest : public ::testing::TestWithParam<QuicVersion> {
void SetUp() override {
QuicInMemoryCache* cache = QuicInMemoryCache::GetInstance();
BalsaHeaders request_headers, response_headers;
BalsaHeaders response_headers;
StringPiece body("Yum");
request_headers.SetRequestFirstlineFromStringPieces(
"GET",
"https://www.google.com/foo",
"HTTP/1.1");
response_headers.SetRequestFirstlineFromStringPieces("HTTP/1.1",
"200",
"OK");
response_headers.AppendHeader("content-length",
base::IntToString(body.length()));
string host = "";
string path = "/foo";
// Check if response already exists and matches.
const QuicInMemoryCache::Response* cached_response =
cache->GetResponse(request_headers);
cache->GetResponse(host, path);
if (cached_response != nullptr) {
string cached_response_headers_str, response_headers_str;
cached_response->headers().DumpToString(&cached_response_headers_str);
......@@ -124,7 +122,7 @@ class QuicSpdyServerStreamTest : public ::testing::TestWithParam<QuicVersion> {
return;
}
cache->AddResponse(request_headers, response_headers, body);
cache->AddResponse(host, path, response_headers, body);
}
const string& StreamBody() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment