summaryrefslogtreecommitdiffstats
path: root/net/tools
diff options
context:
space:
mode:
Diffstat (limited to 'net/tools')
-rw-r--r--net/tools/quic/quic_in_memory_cache.cc173
-rw-r--r--net/tools/quic/quic_in_memory_cache.h60
-rw-r--r--net/tools/quic/quic_in_memory_cache_test.cc18
-rw-r--r--net/tools/quic/quic_simple_server_stream.cc11
4 files changed, 202 insertions, 60 deletions
diff --git a/net/tools/quic/quic_in_memory_cache.cc b/net/tools/quic/quic_in_memory_cache.cc
index 1f31b9c..aa45d2f 100644
--- a/net/tools/quic/quic_in_memory_cache.cc
+++ b/net/tools/quic/quic_in_memory_cache.cc
@@ -22,6 +22,62 @@ using std::string;
namespace net {
+namespace {
+
+class ResourceFileImpl : public net::QuicInMemoryCache::ResourceFile {
+ public:
+ ResourceFileImpl(const base::FilePath& file_name) : ResourceFile(file_name) {}
+
+ void Read() override {
+ base::ReadFileToString(FilePath(file_name_), &file_contents_);
+
+ int file_len = static_cast<int>(file_contents_.length());
+ int headers_end =
+ HttpUtil::LocateEndOfHeaders(file_contents_.data(), file_len);
+ if (headers_end < 1) {
+ LOG(DFATAL) << "Headers invalid or empty, ignoring: "
+ << file_name_.value();
+ return;
+ }
+ http_headers_ = new HttpResponseHeaders(
+ HttpUtil::AssembleRawHeaders(file_contents_.data(), headers_end));
+
+ if (http_headers_->GetNormalizedHeader("X-Original-Url", &url_)) {
+ x_original_url_ = StringPiece(url_);
+ HandleXOriginalUrl();
+ }
+
+ // X-Push-URL header is a relatively quick way to support sever push
+ // in the toy server. A production server should use link=preload
+ // stuff as described in https://w3c.github.io/preload/.
+ StringPiece x_push_url("X-Push-Url");
+ if (http_headers_->HasHeader(x_push_url)) {
+ size_t iter = 0;
+ std::unique_ptr<std::string> push_url(new string());
+ while (
+ http_headers_->EnumerateHeader(&iter, x_push_url, push_url.get())) {
+ push_urls_.push_back(StringPiece(*push_url));
+ push_url_values_.push_back(std::move(push_url));
+ push_url.reset(new string());
+ }
+ }
+
+ body_ = StringPiece(file_contents_.data() + headers_end,
+ file_contents_.size() - headers_end);
+
+ CreateSpdyHeadersFromHttpResponse(*http_headers_, HTTP2, &spdy_headers_);
+ }
+
+ private:
+ scoped_refptr<HttpResponseHeaders> http_headers_;
+ std::string url_;
+ std::list<std::unique_ptr<string>> push_url_values_;
+
+ DISALLOW_COPY_AND_ASSIGN(ResourceFileImpl);
+};
+
+} // namespace
+
QuicInMemoryCache::ServerPushInfo::ServerPushInfo(
GURL request_url,
const SpdyHeaderBlock& headers,
@@ -39,6 +95,39 @@ QuicInMemoryCache::Response::Response() : response_type_(REGULAR_RESPONSE) {}
QuicInMemoryCache::Response::~Response() {}
+QuicInMemoryCache::ResourceFile::ResourceFile(const base::FilePath& file_name)
+ : file_name_(file_name), file_name_string_(file_name.AsUTF8Unsafe()) {}
+
+QuicInMemoryCache::ResourceFile::~ResourceFile() {}
+
+void QuicInMemoryCache::ResourceFile::SetHostPathFromBase(StringPiece base) {
+ size_t path_start = base.find_first_of('/');
+ DCHECK_LT(0UL, path_start);
+ host_ = base.substr(0, path_start);
+ size_t query_start = base.find_first_of(',');
+ if (query_start > 0) {
+ path_ = base.substr(path_start, query_start - 1);
+ } else {
+ path_ = base.substr(path_start);
+ }
+}
+
+StringPiece QuicInMemoryCache::ResourceFile::RemoveScheme(StringPiece url) {
+ if (url.starts_with("https://")) {
+ url.remove_prefix(8);
+ } else if (url.starts_with("http://")) {
+ url.remove_prefix(7);
+ }
+ return url;
+}
+
+void QuicInMemoryCache::ResourceFile::HandleXOriginalUrl() {
+ StringPiece url(x_original_url_);
+ // Remove the protocol so we can add it below.
+ url = RemoveScheme(url);
+ SetHostPathFromBase(url);
+}
+
// static
QuicInMemoryCache* QuicInMemoryCache::GetInstance() {
return base::Singleton<QuicInMemoryCache>::get();
@@ -126,7 +215,7 @@ void QuicInMemoryCache::InitializeFromDirectory(const string& cache_directory) {
<< cache_directory;
FilePath directory(FilePath::FromUTF8Unsafe(cache_directory));
base::FileEnumerator file_list(directory, true, base::FileEnumerator::FILES);
-
+ list<std::unique_ptr<ResourceFile>> resource_files;
for (FilePath file_iter = file_list.Next(); !file_iter.empty();
file_iter = file_list.Next()) {
// Need to skip files in .svn directories
@@ -134,55 +223,40 @@ void QuicInMemoryCache::InitializeFromDirectory(const string& cache_directory) {
continue;
}
+ std::unique_ptr<ResourceFile> resource_file(
+ new ResourceFileImpl(file_iter));
+
// Tease apart filename into host and path.
- string file = file_iter.AsUTF8Unsafe();
- file.erase(0, cache_directory.length());
- if (file[0] == '/') {
- file.erase(0, 1);
+ StringPiece base(resource_file->file_name());
+ base.remove_prefix(cache_directory.length());
+ if (base[0] == '/') {
+ base.remove_prefix(1);
}
- string file_contents;
- base::ReadFileToString(file_iter, &file_contents);
- int file_len = static_cast<int>(file_contents.length());
- int headers_end =
- HttpUtil::LocateEndOfHeaders(file_contents.data(), file_len);
- if (headers_end < 1) {
- LOG(DFATAL) << "Headers invalid or empty, ignoring: " << file;
- continue;
- }
+ resource_file->SetHostPathFromBase(base);
+ resource_file->Read();
- string raw_headers =
- HttpUtil::AssembleRawHeaders(file_contents.data(), headers_end);
-
- scoped_refptr<HttpResponseHeaders> response_headers =
- new HttpResponseHeaders(raw_headers);
-
- string base;
- if (response_headers->GetNormalizedHeader("X-Original-Url", &base)) {
- response_headers->RemoveHeader("X-Original-Url");
- // Remove the protocol so we can add it below.
- if (base::StartsWith(base, "https://",
- base::CompareCase::INSENSITIVE_ASCII)) {
- base = base.substr(8);
- } else if (base::StartsWith(base, "http://",
- base::CompareCase::INSENSITIVE_ASCII)) {
- base = base.substr(7);
- }
- } else {
- base = file;
- }
+ AddResponse(resource_file->host(), resource_file->path(),
+ resource_file->spdy_headers(), resource_file->body());
+
+ resource_files.push_back(std::move(resource_file));
+ }
- size_t path_start = base.find_first_of('/');
- StringPiece host(StringPiece(base).substr(0, path_start));
- StringPiece path(StringPiece(base).substr(path_start));
- if (path.back() == ',') {
- path.remove_suffix(1);
+ for (const auto& resource_file : resource_files) {
+ list<ServerPushInfo> push_resources;
+ for (const auto& push_url : resource_file->push_urls()) {
+ GURL url(push_url);
+ const Response* response = GetResponse(url.host(), url.path());
+ if (!response) {
+ QUIC_BUG << "Push URL '" << push_url << "' not found.";
+ return;
+ }
+ push_resources.push_back(ServerPushInfo(url, response->headers(),
+ net::kV3LowestPriority,
+ response->body().as_string()));
}
- StringPiece body(file_contents.data() + headers_end,
- file_contents.size() - headers_end);
- SpdyHeaderBlock header_block;
- CreateSpdyHeadersFromHttpResponse(*response_headers, HTTP2, &header_block);
- AddResponse(host, path, header_block, body);
+ MaybeAddServerPushResources(resource_file->host(), resource_file->path(),
+ push_resources);
}
}
@@ -193,6 +267,8 @@ list<ServerPushInfo> QuicInMemoryCache::GetServerPushResources(
for (auto it = resource_range.first; it != resource_range.second; ++it) {
resources.push_back(it->second);
}
+ DVLOG(1) << "Found " << resources.size() << " push resources for "
+ << request_url;
return resources;
}
@@ -218,6 +294,7 @@ void QuicInMemoryCache::AddResponseImpl(
new_response->set_headers(response_headers);
new_response->set_body(response_body);
new_response->set_trailers(response_trailers);
+ DVLOG(1) << "Add response with key " << key;
responses_[key] = new_response;
}
@@ -229,14 +306,16 @@ void QuicInMemoryCache::MaybeAddServerPushResources(
StringPiece request_host,
StringPiece request_path,
list<ServerPushInfo> push_resources) {
- string request_url = request_host.as_string() + request_path.as_string();
+ string request_url = GetKey(request_host, request_path);
for (const auto& push_resource : push_resources) {
if (PushResourceExistsInCache(request_url, push_resource)) {
continue;
}
- DVLOG(1) << "Add request-resource association.";
+ DVLOG(1) << "Add request-resource association: request url " << request_url
+ << " push url " << push_resource.request_url
+ << " response headers " << push_resource.headers.DebugString();
server_push_resources_.insert(std::make_pair(request_url, push_resource));
string host = push_resource.request_url.host();
if (host.empty()) {
@@ -248,7 +327,7 @@ void QuicInMemoryCache::MaybeAddServerPushResources(
SpdyHeaderBlock headers = push_resource.headers;
StringPiece body = push_resource.body;
DVLOG(1) << "Add response for push resource: host " << host << " path "
- << path << " body " << body;
+ << path;
AddResponse(host, path, headers, body);
}
}
diff --git a/net/tools/quic/quic_in_memory_cache.h b/net/tools/quic/quic_in_memory_cache.h
index 0cedc1e..bfdc6b6 100644
--- a/net/tools/quic/quic_in_memory_cache.h
+++ b/net/tools/quic/quic_in_memory_cache.h
@@ -10,9 +10,11 @@
#include <unordered_map>
#include "base/containers/hash_tables.h"
+#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/strings/string_piece.h"
+#include "net/http/http_response_headers.h"
#include "net/quic/spdy_utils.h"
#include "net/spdy/spdy_framer.h"
#include "url/gurl.h"
@@ -45,13 +47,13 @@ class QuicInMemoryCache {
// comprising a response for the push request.
struct ServerPushInfo {
ServerPushInfo(GURL request_url,
- const net::SpdyHeaderBlock& headers,
- net::SpdyPriority priority,
+ const SpdyHeaderBlock& headers,
+ SpdyPriority priority,
string body);
ServerPushInfo(const ServerPushInfo& other);
GURL request_url;
- net::SpdyHeaderBlock headers;
- net::SpdyPriority priority;
+ SpdyHeaderBlock headers;
+ SpdyPriority priority;
string body;
};
@@ -88,6 +90,56 @@ class QuicInMemoryCache {
DISALLOW_COPY_AND_ASSIGN(Response);
};
+ // Class to manage loading a resource file into memory. There are
+ // two uses: called by InitializeFromDirectory to load resources
+ // from files, and recursively called when said resources specify
+ // server push associations.
+ class ResourceFile {
+ public:
+ explicit ResourceFile(const base::FilePath& file_name);
+ virtual ~ResourceFile();
+
+ // abstract: implementation details are chromium and internal
+ // version specific.
+ virtual void Read() = 0;
+ void SetHostPathFromBase(base::StringPiece base);
+
+ StringPiece host() { return host_; }
+ void set_host(base::StringPiece host) { host_ = host; }
+
+ StringPiece path() { return path_; }
+ void set_path(base::StringPiece path) { path_ = path; }
+
+ SpdyHeaderBlock spdy_headers() { return spdy_headers_; }
+
+ StringPiece body() { return body_; }
+
+ const std::vector<base::StringPiece>& push_urls() { return push_urls_; }
+
+ const std::string& file_name() { return file_name_string_; }
+
+ protected:
+ void HandleXOriginalUrl();
+ void HandlePushUrls(const std::vector<base::StringPiece>& push_urls);
+ StringPiece RemoveScheme(base::StringPiece url);
+
+ const string cache_directory_;
+ const base::FilePath file_name_;
+ const std::string file_name_string_;
+ string file_contents_;
+ base::StringPiece body_;
+ SpdyHeaderBlock spdy_headers_;
+ base::StringPiece x_original_url_;
+ std::vector<base::StringPiece> push_urls_;
+
+ private:
+ base::StringPiece host_;
+ base::StringPiece path_;
+ QuicInMemoryCache* cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(ResourceFile);
+ };
+
// Returns the singleton instance of the cache.
static QuicInMemoryCache* GetInstance();
diff --git a/net/tools/quic/quic_in_memory_cache_test.cc b/net/tools/quic/quic_in_memory_cache_test.cc
index ac9319e..5f2f96d 100644
--- a/net/tools/quic/quic_in_memory_cache_test.cc
+++ b/net/tools/quic/quic_in_memory_cache_test.cc
@@ -112,6 +112,24 @@ TEST_F(QuicInMemoryCacheTest, ReadsCacheDir) {
EXPECT_LT(0U, response->body().length());
}
+TEST_F(QuicInMemoryCacheTest, ReadsCacheDirWithServerPushResource) {
+ QuicInMemoryCache::GetInstance()->InitializeFromDirectory(CacheDirectory() +
+ "_with_push");
+ QuicInMemoryCache* cache = QuicInMemoryCache::GetInstance();
+ std::list<ServerPushInfo> resources =
+ cache->GetServerPushResources("quic.test.url/");
+ ASSERT_EQ(1UL, resources.size());
+}
+
+TEST_F(QuicInMemoryCacheTest, ReadsCacheDirWithServerPushResources) {
+ QuicInMemoryCache::GetInstance()->InitializeFromDirectory(CacheDirectory() +
+ "_with_push");
+ QuicInMemoryCache* cache = QuicInMemoryCache::GetInstance();
+ std::list<ServerPushInfo> resources =
+ cache->GetServerPushResources("quic.test.url/index2.html");
+ ASSERT_EQ(2UL, resources.size());
+}
+
TEST_F(QuicInMemoryCacheTest, UsesOriginalUrl) {
QuicInMemoryCache::GetInstance()->InitializeFromDirectory(CacheDirectory());
const QuicInMemoryCache::Response* response =
diff --git a/net/tools/quic/quic_simple_server_stream.cc b/net/tools/quic/quic_simple_server_stream.cc
index 8609999..b715574 100644
--- a/net/tools/quic/quic_simple_server_stream.cc
+++ b/net/tools/quic/quic_simple_server_stream.cc
@@ -142,15 +142,8 @@ void QuicSimpleServerStream::SendResponse() {
// Examing response status, if it was not pure integer as typical h2 response
// status, send error response.
- string request_url;
- if (!request_headers_[":scheme"].as_string().empty()) {
- request_url = request_headers_[":scheme"].as_string() + "://" +
- request_headers_[":authority"].as_string() +
- request_headers_[":path"].as_string();
- } else {
- request_url = request_headers_[":authority"].as_string() +
- request_headers_[":path"].as_string();
- }
+ string request_url = request_headers_[":authority"].as_string() +
+ request_headers_[":path"].as_string();
int response_code;
SpdyHeaderBlock response_headers = response->headers();
if (!base::StringToInt(response_headers[":status"], &response_code)) {