| // Copyright 2013 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" | |
| #include "net/third_party/quiche/src/quic/tools/quic_backend_response.h" | |
| namespace quic { | |
| namespace test { | |
| namespace { | |
| typedef QuicBackendResponse Response; | |
| typedef QuicBackendResponse::ServerPushInfo ServerPushInfo; | |
| } // namespace | |
| class QuicMemoryCacheBackendTest : public QuicTest { | |
| protected: | |
| void CreateRequest(std::string host, | |
| std::string path, | |
| spdy::SpdyHeaderBlock* headers) { | |
| (*headers)[":method"] = "GET"; | |
| (*headers)[":path"] = path; | |
| (*headers)[":authority"] = host; | |
| (*headers)[":scheme"] = "https"; | |
| } | |
| std::string CacheDirectory() { return QuicGetTestMemoryCachePath(); } | |
| QuicMemoryCacheBackend cache_; | |
| }; | |
| TEST_F(QuicMemoryCacheBackendTest, GetResponseNoMatch) { | |
| const Response* response = | |
| cache_.GetResponse("mail.google.com", "/index.html"); | |
| ASSERT_FALSE(response); | |
| } | |
| TEST_F(QuicMemoryCacheBackendTest, AddSimpleResponseGetResponse) { | |
| std::string response_body("hello response"); | |
| cache_.AddSimpleResponse("www.google.com", "/", 200, response_body); | |
| spdy::SpdyHeaderBlock request_headers; | |
| CreateRequest("www.google.com", "/", &request_headers); | |
| const Response* response = cache_.GetResponse("www.google.com", "/"); | |
| ASSERT_TRUE(response); | |
| ASSERT_TRUE(QuicContainsKey(response->headers(), ":status")); | |
| EXPECT_EQ("200", response->headers().find(":status")->second); | |
| EXPECT_EQ(response_body.size(), response->body().length()); | |
| } | |
| TEST_F(QuicMemoryCacheBackendTest, AddResponse) { | |
| const std::string kRequestHost = "www.foo.com"; | |
| const std::string kRequestPath = "/"; | |
| const std::string kResponseBody("hello response"); | |
| spdy::SpdyHeaderBlock response_headers; | |
| response_headers[":version"] = "HTTP/1.1"; | |
| response_headers[":status"] = "200"; | |
| response_headers["content-length"] = | |
| QuicTextUtils::Uint64ToString(kResponseBody.size()); | |
| spdy::SpdyHeaderBlock response_trailers; | |
| response_trailers["key-1"] = "value-1"; | |
| response_trailers["key-2"] = "value-2"; | |
| response_trailers["key-3"] = "value-3"; | |
| cache_.AddResponse(kRequestHost, "/", response_headers.Clone(), kResponseBody, | |
| response_trailers.Clone()); | |
| const Response* response = cache_.GetResponse(kRequestHost, kRequestPath); | |
| EXPECT_EQ(response->headers(), response_headers); | |
| EXPECT_EQ(response->body(), kResponseBody); | |
| EXPECT_EQ(response->trailers(), response_trailers); | |
| } | |
| TEST_F(QuicMemoryCacheBackendTest, ReadsCacheDir) { | |
| cache_.InitializeBackend(CacheDirectory()); | |
| const Response* response = | |
| cache_.GetResponse("test.example.com", "/index.html"); | |
| ASSERT_TRUE(response); | |
| ASSERT_TRUE(QuicContainsKey(response->headers(), ":status")); | |
| EXPECT_EQ("200", response->headers().find(":status")->second); | |
| // Connection headers are not valid in HTTP/2. | |
| EXPECT_FALSE(QuicContainsKey(response->headers(), "connection")); | |
| EXPECT_LT(0U, response->body().length()); | |
| } | |
| TEST_F(QuicMemoryCacheBackendTest, ReadsCacheDirWithServerPushResource) { | |
| cache_.InitializeBackend(CacheDirectory() + "_with_push"); | |
| std::list<ServerPushInfo> resources = | |
| cache_.GetServerPushResources("test.example.com/"); | |
| ASSERT_EQ(1UL, resources.size()); | |
| } | |
| TEST_F(QuicMemoryCacheBackendTest, ReadsCacheDirWithServerPushResources) { | |
| cache_.InitializeBackend(CacheDirectory() + "_with_push"); | |
| std::list<ServerPushInfo> resources = | |
| cache_.GetServerPushResources("test.example.com/index2.html"); | |
| ASSERT_EQ(2UL, resources.size()); | |
| } | |
| TEST_F(QuicMemoryCacheBackendTest, UsesOriginalUrl) { | |
| cache_.InitializeBackend(CacheDirectory()); | |
| const Response* response = | |
| cache_.GetResponse("test.example.com", "/site_map.html"); | |
| ASSERT_TRUE(response); | |
| ASSERT_TRUE(QuicContainsKey(response->headers(), ":status")); | |
| EXPECT_EQ("200", response->headers().find(":status")->second); | |
| // Connection headers are not valid in HTTP/2. | |
| EXPECT_FALSE(QuicContainsKey(response->headers(), "connection")); | |
| EXPECT_LT(0U, response->body().length()); | |
| } | |
| TEST_F(QuicMemoryCacheBackendTest, DefaultResponse) { | |
| // Verify GetResponse returns nullptr when no default is set. | |
| const Response* response = cache_.GetResponse("www.google.com", "/"); | |
| ASSERT_FALSE(response); | |
| // Add a default response. | |
| spdy::SpdyHeaderBlock response_headers; | |
| response_headers[":version"] = "HTTP/1.1"; | |
| response_headers[":status"] = "200"; | |
| response_headers["content-length"] = "0"; | |
| Response* default_response = new Response; | |
| default_response->set_headers(std::move(response_headers)); | |
| cache_.AddDefaultResponse(default_response); | |
| // Now we should get the default response for the original request. | |
| response = cache_.GetResponse("www.google.com", "/"); | |
| ASSERT_TRUE(response); | |
| ASSERT_TRUE(QuicContainsKey(response->headers(), ":status")); | |
| EXPECT_EQ("200", response->headers().find(":status")->second); | |
| // Now add a set response for / and make sure it is returned | |
| cache_.AddSimpleResponse("www.google.com", "/", 302, ""); | |
| response = cache_.GetResponse("www.google.com", "/"); | |
| ASSERT_TRUE(response); | |
| ASSERT_TRUE(QuicContainsKey(response->headers(), ":status")); | |
| EXPECT_EQ("302", response->headers().find(":status")->second); | |
| // We should get the default response for other requests. | |
| response = cache_.GetResponse("www.google.com", "/asd"); | |
| ASSERT_TRUE(response); | |
| ASSERT_TRUE(QuicContainsKey(response->headers(), ":status")); | |
| EXPECT_EQ("200", response->headers().find(":status")->second); | |
| } | |
| TEST_F(QuicMemoryCacheBackendTest, AddSimpleResponseWithServerPushResources) { | |
| std::string request_host = "www.foo.com"; | |
| std::string response_body("hello response"); | |
| const size_t kNumResources = 5; | |
| int NumResources = 5; | |
| std::list<ServerPushInfo> push_resources; | |
| std::string scheme = "http"; | |
| for (int i = 0; i < NumResources; ++i) { | |
| std::string path = "/server_push_src" + QuicTextUtils::Uint64ToString(i); | |
| std::string url = scheme + "://" + request_host + path; | |
| QuicUrl resource_url(url); | |
| std::string body = | |
| QuicStrCat("This is server push response body for ", path); | |
| spdy::SpdyHeaderBlock response_headers; | |
| response_headers[":version"] = "HTTP/1.1"; | |
| response_headers[":status"] = "200"; | |
| response_headers["content-length"] = | |
| QuicTextUtils::Uint64ToString(body.size()); | |
| push_resources.push_back( | |
| ServerPushInfo(resource_url, response_headers.Clone(), i, body)); | |
| } | |
| cache_.AddSimpleResponseWithServerPushResources( | |
| request_host, "/", 200, response_body, push_resources); | |
| std::string request_url = request_host + "/"; | |
| std::list<ServerPushInfo> resources = | |
| cache_.GetServerPushResources(request_url); | |
| ASSERT_EQ(kNumResources, resources.size()); | |
| for (const auto& push_resource : push_resources) { | |
| ServerPushInfo resource = resources.front(); | |
| EXPECT_EQ(resource.request_url.ToString(), | |
| push_resource.request_url.ToString()); | |
| EXPECT_EQ(resource.priority, push_resource.priority); | |
| resources.pop_front(); | |
| } | |
| } | |
| TEST_F(QuicMemoryCacheBackendTest, GetServerPushResourcesAndPushResponses) { | |
| std::string request_host = "www.foo.com"; | |
| std::string response_body("hello response"); | |
| const size_t kNumResources = 4; | |
| int NumResources = 4; | |
| std::string scheme = "http"; | |
| std::string push_response_status[kNumResources] = {"200", "200", "301", | |
| "404"}; | |
| std::list<ServerPushInfo> push_resources; | |
| for (int i = 0; i < NumResources; ++i) { | |
| std::string path = "/server_push_src" + QuicTextUtils::Uint64ToString(i); | |
| std::string url = scheme + "://" + request_host + path; | |
| QuicUrl resource_url(url); | |
| std::string body = "This is server push response body for " + path; | |
| spdy::SpdyHeaderBlock response_headers; | |
| response_headers[":version"] = "HTTP/1.1"; | |
| response_headers[":status"] = push_response_status[i]; | |
| response_headers["content-length"] = | |
| QuicTextUtils::Uint64ToString(body.size()); | |
| push_resources.push_back( | |
| ServerPushInfo(resource_url, response_headers.Clone(), i, body)); | |
| } | |
| cache_.AddSimpleResponseWithServerPushResources( | |
| request_host, "/", 200, response_body, push_resources); | |
| std::string request_url = request_host + "/"; | |
| std::list<ServerPushInfo> resources = | |
| cache_.GetServerPushResources(request_url); | |
| ASSERT_EQ(kNumResources, resources.size()); | |
| int i = 0; | |
| for (const auto& push_resource : push_resources) { | |
| QuicUrl url = resources.front().request_url; | |
| std::string host = url.host(); | |
| std::string path = url.path(); | |
| const Response* response = cache_.GetResponse(host, path); | |
| ASSERT_TRUE(response); | |
| ASSERT_TRUE(QuicContainsKey(response->headers(), ":status")); | |
| EXPECT_EQ(push_response_status[i++], | |
| response->headers().find(":status")->second); | |
| EXPECT_EQ(push_resource.body, response->body()); | |
| resources.pop_front(); | |
| } | |
| } | |
| } // namespace test | |
| } // namespace quic |