1 // Copyright 2013 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 "quiche/quic/tools/quic_memory_cache_backend.h"
6
7 #include <vector>
8
9 #include "absl/strings/match.h"
10 #include "absl/strings/str_cat.h"
11 #include "quiche/quic/platform/api/quic_test.h"
12 #include "quiche/quic/tools/quic_backend_response.h"
13 #include "quiche/common/platform/api/quiche_file_utils.h"
14 #include "quiche/common/platform/api/quiche_test.h"
15
16 namespace quic {
17 namespace test {
18
19 namespace {
20 using Response = QuicBackendResponse;
21 } // namespace
22
23 class QuicMemoryCacheBackendTest : public QuicTest {
24 protected:
CreateRequest(std::string host,std::string path,spdy::Http2HeaderBlock * headers)25 void CreateRequest(std::string host, std::string path,
26 spdy::Http2HeaderBlock* headers) {
27 (*headers)[":method"] = "GET";
28 (*headers)[":path"] = path;
29 (*headers)[":authority"] = host;
30 (*headers)[":scheme"] = "https";
31 }
32
CacheDirectory()33 std::string CacheDirectory() {
34 return quiche::test::QuicheGetTestMemoryCachePath();
35 }
36
37 QuicMemoryCacheBackend cache_;
38 };
39
TEST_F(QuicMemoryCacheBackendTest,GetResponseNoMatch)40 TEST_F(QuicMemoryCacheBackendTest, GetResponseNoMatch) {
41 const Response* response =
42 cache_.GetResponse("mail.google.com", "/index.html");
43 ASSERT_FALSE(response);
44 }
45
TEST_F(QuicMemoryCacheBackendTest,AddSimpleResponseGetResponse)46 TEST_F(QuicMemoryCacheBackendTest, AddSimpleResponseGetResponse) {
47 std::string response_body("hello response");
48 cache_.AddSimpleResponse("www.google.com", "/", 200, response_body);
49
50 spdy::Http2HeaderBlock request_headers;
51 CreateRequest("www.google.com", "/", &request_headers);
52 const Response* response = cache_.GetResponse("www.google.com", "/");
53 ASSERT_TRUE(response);
54 ASSERT_TRUE(response->headers().contains(":status"));
55 EXPECT_EQ("200", response->headers().find(":status")->second);
56 EXPECT_EQ(response_body.size(), response->body().length());
57 }
58
TEST_F(QuicMemoryCacheBackendTest,AddResponse)59 TEST_F(QuicMemoryCacheBackendTest, AddResponse) {
60 const std::string kRequestHost = "www.foo.com";
61 const std::string kRequestPath = "/";
62 const std::string kResponseBody("hello response");
63
64 spdy::Http2HeaderBlock response_headers;
65 response_headers[":status"] = "200";
66 response_headers["content-length"] = absl::StrCat(kResponseBody.size());
67
68 spdy::Http2HeaderBlock response_trailers;
69 response_trailers["key-1"] = "value-1";
70 response_trailers["key-2"] = "value-2";
71 response_trailers["key-3"] = "value-3";
72
73 cache_.AddResponse(kRequestHost, "/", response_headers.Clone(), kResponseBody,
74 response_trailers.Clone());
75
76 const Response* response = cache_.GetResponse(kRequestHost, kRequestPath);
77 EXPECT_EQ(response->headers(), response_headers);
78 EXPECT_EQ(response->body(), kResponseBody);
79 EXPECT_EQ(response->trailers(), response_trailers);
80 }
81
82 // TODO(crbug.com/1249712) This test is failing on iOS.
83 #if defined(OS_IOS)
84 #define MAYBE_ReadsCacheDir DISABLED_ReadsCacheDir
85 #else
86 #define MAYBE_ReadsCacheDir ReadsCacheDir
87 #endif
TEST_F(QuicMemoryCacheBackendTest,MAYBE_ReadsCacheDir)88 TEST_F(QuicMemoryCacheBackendTest, MAYBE_ReadsCacheDir) {
89 cache_.InitializeBackend(CacheDirectory());
90 const Response* response =
91 cache_.GetResponse("test.example.com", "/index.html");
92 ASSERT_TRUE(response);
93 ASSERT_TRUE(response->headers().contains(":status"));
94 EXPECT_EQ("200", response->headers().find(":status")->second);
95 // Connection headers are not valid in HTTP/2.
96 EXPECT_FALSE(response->headers().contains("connection"));
97 EXPECT_LT(0U, response->body().length());
98 }
99
100 // TODO(crbug.com/1249712) This test is failing on iOS.
101 #if defined(OS_IOS)
102 #define MAYBE_UsesOriginalUrl DISABLED_UsesOriginalUrl
103 #else
104 #define MAYBE_UsesOriginalUrl UsesOriginalUrl
105 #endif
TEST_F(QuicMemoryCacheBackendTest,MAYBE_UsesOriginalUrl)106 TEST_F(QuicMemoryCacheBackendTest, MAYBE_UsesOriginalUrl) {
107 cache_.InitializeBackend(CacheDirectory());
108 const Response* response =
109 cache_.GetResponse("test.example.com", "/site_map.html");
110 ASSERT_TRUE(response);
111 ASSERT_TRUE(response->headers().contains(":status"));
112 EXPECT_EQ("200", response->headers().find(":status")->second);
113 // Connection headers are not valid in HTTP/2.
114 EXPECT_FALSE(response->headers().contains("connection"));
115 EXPECT_LT(0U, response->body().length());
116 }
117
118 // TODO(crbug.com/1249712) This test is failing on iOS.
119 #if defined(OS_IOS)
120 #define MAYBE_UsesOriginalUrlOnly DISABLED_UsesOriginalUrlOnly
121 #else
122 #define MAYBE_UsesOriginalUrlOnly UsesOriginalUrlOnly
123 #endif
TEST_F(QuicMemoryCacheBackendTest,MAYBE_UsesOriginalUrlOnly)124 TEST_F(QuicMemoryCacheBackendTest, MAYBE_UsesOriginalUrlOnly) {
125 // Tests that if the URL cannot be inferred correctly from the path
126 // because the directory does not include the hostname, that the
127 // X-Original-Url header's value will be used.
128 std::string dir;
129 std::string path = "map.html";
130 std::vector<std::string> files;
131 ASSERT_TRUE(quiche::EnumerateDirectoryRecursively(CacheDirectory(), files));
132 for (const std::string& file : files) {
133 if (absl::EndsWithIgnoreCase(file, "map.html")) {
134 dir = file;
135 dir.erase(dir.length() - path.length() - 1);
136 break;
137 }
138 }
139 ASSERT_NE("", dir);
140
141 cache_.InitializeBackend(dir);
142 const Response* response =
143 cache_.GetResponse("test.example.com", "/site_map.html");
144 ASSERT_TRUE(response);
145 ASSERT_TRUE(response->headers().contains(":status"));
146 EXPECT_EQ("200", response->headers().find(":status")->second);
147 // Connection headers are not valid in HTTP/2.
148 EXPECT_FALSE(response->headers().contains("connection"));
149 EXPECT_LT(0U, response->body().length());
150 }
151
TEST_F(QuicMemoryCacheBackendTest,DefaultResponse)152 TEST_F(QuicMemoryCacheBackendTest, DefaultResponse) {
153 // Verify GetResponse returns nullptr when no default is set.
154 const Response* response = cache_.GetResponse("www.google.com", "/");
155 ASSERT_FALSE(response);
156
157 // Add a default response.
158 spdy::Http2HeaderBlock response_headers;
159 response_headers[":status"] = "200";
160 response_headers["content-length"] = "0";
161 Response* default_response = new Response;
162 default_response->set_headers(std::move(response_headers));
163 cache_.AddDefaultResponse(default_response);
164
165 // Now we should get the default response for the original request.
166 response = cache_.GetResponse("www.google.com", "/");
167 ASSERT_TRUE(response);
168 ASSERT_TRUE(response->headers().contains(":status"));
169 EXPECT_EQ("200", response->headers().find(":status")->second);
170
171 // Now add a set response for / and make sure it is returned
172 cache_.AddSimpleResponse("www.google.com", "/", 302, "");
173 response = cache_.GetResponse("www.google.com", "/");
174 ASSERT_TRUE(response);
175 ASSERT_TRUE(response->headers().contains(":status"));
176 EXPECT_EQ("302", response->headers().find(":status")->second);
177
178 // We should get the default response for other requests.
179 response = cache_.GetResponse("www.google.com", "/asd");
180 ASSERT_TRUE(response);
181 ASSERT_TRUE(response->headers().contains(":status"));
182 EXPECT_EQ("200", response->headers().find(":status")->second);
183 }
184
185 } // namespace test
186 } // namespace quic
187