blob: df2f6048f971dc19a0fa4fba6d25fd3a78ceb08e [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// 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
QUICHE team5be974e2020-12-29 18:35:24 -05005#include "quic/tools/quic_memory_cache_backend.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -05006
7#include <utility>
8
vasilvv89fe24d2020-10-26 14:55:28 -07009#include "absl/strings/match.h"
vasilvv23846f32020-10-27 09:53:28 -070010#include "absl/strings/numbers.h"
vasilvv6c9e9c32020-10-08 08:16:57 -070011#include "absl/strings/string_view.h"
QUICHE team5be974e2020-12-29 18:35:24 -050012#include "quic/core/http/spdy_utils.h"
13#include "quic/platform/api/quic_bug_tracker.h"
14#include "quic/platform/api/quic_file_utils.h"
15#include "quic/platform/api/quic_logging.h"
16#include "quic/platform/api/quic_map_util.h"
17#include "common/platform/api/quiche_text_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050018
QUICHE team82103522020-10-22 08:15:09 -070019using spdy::Http2HeaderBlock;
QUICHE teama6ef0a62019-03-07 20:34:33 -050020using spdy::kV3LowestPriority;
QUICHE teama6ef0a62019-03-07 20:34:33 -050021
22namespace quic {
23
vasilvvc48c8712019-03-11 13:38:16 -070024QuicMemoryCacheBackend::ResourceFile::ResourceFile(const std::string& file_name)
QUICHE teama6ef0a62019-03-07 20:34:33 -050025 : file_name_(file_name) {}
26
27QuicMemoryCacheBackend::ResourceFile::~ResourceFile() = default;
28
29void QuicMemoryCacheBackend::ResourceFile::Read() {
30 ReadFileContents(file_name_, &file_contents_);
31
32 // First read the headers.
33 size_t start = 0;
34 while (start < file_contents_.length()) {
35 size_t pos = file_contents_.find("\n", start);
vasilvvc48c8712019-03-11 13:38:16 -070036 if (pos == std::string::npos) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050037 QUIC_LOG(DFATAL) << "Headers invalid or empty, ignoring: " << file_name_;
38 return;
39 }
40 size_t len = pos - start;
41 // Support both dos and unix line endings for convenience.
42 if (file_contents_[pos - 1] == '\r') {
43 len -= 1;
44 }
vasilvv6c9e9c32020-10-08 08:16:57 -070045 absl::string_view line(file_contents_.data() + start, len);
QUICHE teama6ef0a62019-03-07 20:34:33 -050046 start = pos + 1;
47 // Headers end with an empty line.
48 if (line.empty()) {
49 break;
50 }
51 // Extract the status from the HTTP first line.
52 if (line.substr(0, 4) == "HTTP") {
53 pos = line.find(" ");
vasilvvc48c8712019-03-11 13:38:16 -070054 if (pos == std::string::npos) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050055 QUIC_LOG(DFATAL) << "Headers invalid or empty, ignoring: "
56 << file_name_;
57 return;
58 }
59 spdy_headers_[":status"] = line.substr(pos + 1, 3);
60 continue;
61 }
62 // Headers are "key: value".
63 pos = line.find(": ");
vasilvvc48c8712019-03-11 13:38:16 -070064 if (pos == std::string::npos) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050065 QUIC_LOG(DFATAL) << "Headers invalid or empty, ignoring: " << file_name_;
66 return;
67 }
68 spdy_headers_.AppendValueOrAddHeader(
QUICHE team5015e2e2019-12-11 09:38:06 -080069 quiche::QuicheTextUtils::ToLower(line.substr(0, pos)),
70 line.substr(pos + 2));
QUICHE teama6ef0a62019-03-07 20:34:33 -050071 }
72
73 // The connection header is prohibited in HTTP/2.
74 spdy_headers_.erase("connection");
75
76 // Override the URL with the X-Original-Url header, if present.
77 auto it = spdy_headers_.find("x-original-url");
78 if (it != spdy_headers_.end()) {
79 x_original_url_ = it->second;
80 HandleXOriginalUrl();
81 }
82
83 // X-Push-URL header is a relatively quick way to support sever push
84 // in the toy server. A production server should use link=preload
85 // stuff as described in https://w3c.github.io/preload/.
86 it = spdy_headers_.find("x-push-url");
87 if (it != spdy_headers_.end()) {
vasilvv6c9e9c32020-10-08 08:16:57 -070088 absl::string_view push_urls = it->second;
QUICHE teama6ef0a62019-03-07 20:34:33 -050089 size_t start = 0;
90 while (start < push_urls.length()) {
91 size_t pos = push_urls.find('\0', start);
vasilvvc48c8712019-03-11 13:38:16 -070092 if (pos == std::string::npos) {
vasilvv6c9e9c32020-10-08 08:16:57 -070093 push_urls_.push_back(absl::string_view(push_urls.data() + start,
94 push_urls.length() - start));
QUICHE teama6ef0a62019-03-07 20:34:33 -050095 break;
96 }
vasilvv6c9e9c32020-10-08 08:16:57 -070097 push_urls_.push_back(absl::string_view(push_urls.data() + start, pos));
QUICHE teama6ef0a62019-03-07 20:34:33 -050098 start += pos + 1;
99 }
100 }
101
vasilvv6c9e9c32020-10-08 08:16:57 -0700102 body_ = absl::string_view(file_contents_.data() + start,
103 file_contents_.size() - start);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500104}
105
106void QuicMemoryCacheBackend::ResourceFile::SetHostPathFromBase(
vasilvv6c9e9c32020-10-08 08:16:57 -0700107 absl::string_view base) {
rch3706b232019-12-12 21:40:54 -0800108 DCHECK(base[0] != '/') << base;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500109 size_t path_start = base.find_first_of('/');
vasilvv6c9e9c32020-10-08 08:16:57 -0700110 if (path_start == absl::string_view::npos) {
rchf0ff4932019-12-16 16:25:56 -0800111 host_ = std::string(base);
112 path_ = "";
113 return;
114 }
115
rch3706b232019-12-12 21:40:54 -0800116 host_ = std::string(base.substr(0, path_start));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500117 size_t query_start = base.find_first_of(',');
118 if (query_start > 0) {
rch3706b232019-12-12 21:40:54 -0800119 path_ = std::string(base.substr(path_start, query_start - 1));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500120 } else {
rch3706b232019-12-12 21:40:54 -0800121 path_ = std::string(base.substr(path_start));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500122 }
123}
124
vasilvv6c9e9c32020-10-08 08:16:57 -0700125absl::string_view QuicMemoryCacheBackend::ResourceFile::RemoveScheme(
126 absl::string_view url) {
vasilvv89fe24d2020-10-26 14:55:28 -0700127 if (absl::StartsWith(url, "https://")) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500128 url.remove_prefix(8);
vasilvv89fe24d2020-10-26 14:55:28 -0700129 } else if (absl::StartsWith(url, "http://")) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500130 url.remove_prefix(7);
131 }
132 return url;
133}
134
135void QuicMemoryCacheBackend::ResourceFile::HandleXOriginalUrl() {
vasilvv6c9e9c32020-10-08 08:16:57 -0700136 absl::string_view url(x_original_url_);
rch3706b232019-12-12 21:40:54 -0800137 SetHostPathFromBase(RemoveScheme(url));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500138}
139
140const QuicBackendResponse* QuicMemoryCacheBackend::GetResponse(
vasilvv6c9e9c32020-10-08 08:16:57 -0700141 absl::string_view host,
142 absl::string_view path) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500143 QuicWriterMutexLock lock(&response_mutex_);
144
145 auto it = responses_.find(GetKey(host, path));
146 if (it == responses_.end()) {
rch7bd54762019-10-15 10:53:24 -0700147 uint64_t ignored = 0;
148 if (generate_bytes_response_) {
vasilvv23846f32020-10-27 09:53:28 -0700149 if (absl::SimpleAtoi(absl::string_view(path.data() + 1, path.size() - 1),
150 &ignored)) {
rch7bd54762019-10-15 10:53:24 -0700151 // The actual parsed length is ignored here and will be recomputed
152 // by the caller.
153 return generate_bytes_response_.get();
154 }
155 }
bnc5de87052019-05-03 14:21:53 -0700156 QUIC_DVLOG(1) << "Get response for resource failed: host " << host
157 << " path " << path;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500158 if (default_response_) {
159 return default_response_.get();
160 }
161 return nullptr;
162 }
163 return it->second.get();
164}
165
renjietang58b3af32020-11-11 15:48:58 -0800166using ServerPushInfo = QuicBackendResponse::ServerPushInfo;
167using SpecialResponseType = QuicBackendResponse::SpecialResponseType;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500168
vasilvv6c9e9c32020-10-08 08:16:57 -0700169void QuicMemoryCacheBackend::AddSimpleResponse(absl::string_view host,
170 absl::string_view path,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500171 int response_code,
vasilvv6c9e9c32020-10-08 08:16:57 -0700172 absl::string_view body) {
QUICHE team82103522020-10-22 08:15:09 -0700173 Http2HeaderBlock response_headers;
QUICHE team5015e2e2019-12-11 09:38:06 -0800174 response_headers[":status"] =
175 quiche::QuicheTextUtils::Uint64ToString(response_code);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500176 response_headers["content-length"] =
QUICHE team5015e2e2019-12-11 09:38:06 -0800177 quiche::QuicheTextUtils::Uint64ToString(body.length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500178 AddResponse(host, path, std::move(response_headers), body);
179}
180
181void QuicMemoryCacheBackend::AddSimpleResponseWithServerPushResources(
vasilvv6c9e9c32020-10-08 08:16:57 -0700182 absl::string_view host,
183 absl::string_view path,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500184 int response_code,
vasilvv6c9e9c32020-10-08 08:16:57 -0700185 absl::string_view body,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500186 std::list<ServerPushInfo> push_resources) {
187 AddSimpleResponse(host, path, response_code, body);
188 MaybeAddServerPushResources(host, path, push_resources);
189}
190
191void QuicMemoryCacheBackend::AddDefaultResponse(QuicBackendResponse* response) {
192 QuicWriterMutexLock lock(&response_mutex_);
193 default_response_.reset(response);
194}
195
vasilvv6c9e9c32020-10-08 08:16:57 -0700196void QuicMemoryCacheBackend::AddResponse(absl::string_view host,
197 absl::string_view path,
QUICHE team82103522020-10-22 08:15:09 -0700198 Http2HeaderBlock response_headers,
vasilvv6c9e9c32020-10-08 08:16:57 -0700199 absl::string_view response_body) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500200 AddResponseImpl(host, path, QuicBackendResponse::REGULAR_RESPONSE,
renjietang9f902a42020-08-27 16:03:24 -0700201 std::move(response_headers), response_body,
QUICHE team82103522020-10-22 08:15:09 -0700202 Http2HeaderBlock());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500203}
204
vasilvv6c9e9c32020-10-08 08:16:57 -0700205void QuicMemoryCacheBackend::AddResponse(absl::string_view host,
206 absl::string_view path,
QUICHE team82103522020-10-22 08:15:09 -0700207 Http2HeaderBlock response_headers,
vasilvv6c9e9c32020-10-08 08:16:57 -0700208 absl::string_view response_body,
QUICHE team82103522020-10-22 08:15:09 -0700209 Http2HeaderBlock response_trailers) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500210 AddResponseImpl(host, path, QuicBackendResponse::REGULAR_RESPONSE,
211 std::move(response_headers), response_body,
renjietang9f902a42020-08-27 16:03:24 -0700212 std::move(response_trailers));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500213}
214
215void QuicMemoryCacheBackend::AddSpecialResponse(
vasilvv6c9e9c32020-10-08 08:16:57 -0700216 absl::string_view host,
217 absl::string_view path,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500218 SpecialResponseType response_type) {
QUICHE team82103522020-10-22 08:15:09 -0700219 AddResponseImpl(host, path, response_type, Http2HeaderBlock(), "",
220 Http2HeaderBlock());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500221}
222
223void QuicMemoryCacheBackend::AddSpecialResponse(
vasilvv6c9e9c32020-10-08 08:16:57 -0700224 absl::string_view host,
225 absl::string_view path,
QUICHE team82103522020-10-22 08:15:09 -0700226 spdy::Http2HeaderBlock response_headers,
vasilvv6c9e9c32020-10-08 08:16:57 -0700227 absl::string_view response_body,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500228 SpecialResponseType response_type) {
229 AddResponseImpl(host, path, response_type, std::move(response_headers),
QUICHE team82103522020-10-22 08:15:09 -0700230 response_body, Http2HeaderBlock());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500231}
232
233QuicMemoryCacheBackend::QuicMemoryCacheBackend() : cache_initialized_(false) {}
234
235bool QuicMemoryCacheBackend::InitializeBackend(
vasilvvc48c8712019-03-11 13:38:16 -0700236 const std::string& cache_directory) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500237 if (cache_directory.empty()) {
238 QUIC_BUG << "cache_directory must not be empty.";
239 return false;
240 }
241 QUIC_LOG(INFO)
242 << "Attempting to initialize QuicMemoryCacheBackend from directory: "
243 << cache_directory;
vasilvvc48c8712019-03-11 13:38:16 -0700244 std::vector<std::string> files = ReadFileContents(cache_directory);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500245 std::list<std::unique_ptr<ResourceFile>> resource_files;
246 for (const auto& filename : files) {
247 std::unique_ptr<ResourceFile> resource_file(new ResourceFile(filename));
248
249 // Tease apart filename into host and path.
rch3706b232019-12-12 21:40:54 -0800250 std::string base(resource_file->file_name());
251 // Transform windows path separators to URL path separators.
252 for (size_t i = 0; i < base.length(); ++i) {
253 if (base[i] == '\\') {
254 base[i] = '/';
255 }
256 }
257 base.erase(0, cache_directory.length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500258 if (base[0] == '/') {
rch3706b232019-12-12 21:40:54 -0800259 base.erase(0, 1);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500260 }
261
262 resource_file->SetHostPathFromBase(base);
263 resource_file->Read();
264
265 AddResponse(resource_file->host(), resource_file->path(),
266 resource_file->spdy_headers().Clone(), resource_file->body());
267
268 resource_files.push_back(std::move(resource_file));
269 }
270
271 for (const auto& resource_file : resource_files) {
272 std::list<ServerPushInfo> push_resources;
273 for (const auto& push_url : resource_file->push_urls()) {
274 QuicUrl url(push_url);
275 const QuicBackendResponse* response = GetResponse(url.host(), url.path());
276 if (!response) {
277 QUIC_BUG << "Push URL '" << push_url << "' not found.";
278 return false;
279 }
280 push_resources.push_back(ServerPushInfo(url, response->headers().Clone(),
281 kV3LowestPriority,
vasilvvc48c8712019-03-11 13:38:16 -0700282 (std::string(response->body()))));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500283 }
284 MaybeAddServerPushResources(resource_file->host(), resource_file->path(),
285 push_resources);
286 }
rch7bd54762019-10-15 10:53:24 -0700287
QUICHE teama6ef0a62019-03-07 20:34:33 -0500288 cache_initialized_ = true;
289 return true;
290}
291
rch7bd54762019-10-15 10:53:24 -0700292void QuicMemoryCacheBackend::GenerateDynamicResponses() {
293 QuicWriterMutexLock lock(&response_mutex_);
294 // Add a generate bytes response.
QUICHE team82103522020-10-22 08:15:09 -0700295 spdy::Http2HeaderBlock response_headers;
rch7bd54762019-10-15 10:53:24 -0700296 response_headers[":status"] = "200";
297 generate_bytes_response_ = std::make_unique<QuicBackendResponse>();
298 generate_bytes_response_->set_headers(std::move(response_headers));
299 generate_bytes_response_->set_response_type(
300 QuicBackendResponse::GENERATE_BYTES);
301}
302
QUICHE teama6ef0a62019-03-07 20:34:33 -0500303bool QuicMemoryCacheBackend::IsBackendInitialized() const {
304 return cache_initialized_;
305}
306
307void QuicMemoryCacheBackend::FetchResponseFromBackend(
QUICHE team82103522020-10-22 08:15:09 -0700308 const Http2HeaderBlock& request_headers,
dschinazi17d42422019-06-18 16:35:07 -0700309 const std::string& /*request_body*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500310 QuicSimpleServerBackend::RequestHandler* quic_stream) {
311 const QuicBackendResponse* quic_response = nullptr;
312 // Find response in cache. If not found, send error response.
313 auto authority = request_headers.find(":authority");
314 auto path = request_headers.find(":path");
315 if (authority != request_headers.end() && path != request_headers.end()) {
316 quic_response = GetResponse(authority->second, path->second);
317 }
318
vasilvvc48c8712019-03-11 13:38:16 -0700319 std::string request_url =
320 std::string(authority->second) + std::string(path->second);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500321 std::list<ServerPushInfo> resources = GetServerPushResources(request_url);
322 QUIC_DVLOG(1)
323 << "Fetching QUIC response from backend in-memory cache for url "
324 << request_url;
325 quic_stream->OnResponseBackendComplete(quic_response, resources);
326}
327
328// The memory cache does not have a per-stream handler
329void QuicMemoryCacheBackend::CloseBackendResponseStream(
dschinazi17d42422019-06-18 16:35:07 -0700330 QuicSimpleServerBackend::RequestHandler* /*quic_stream*/) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500331
332std::list<ServerPushInfo> QuicMemoryCacheBackend::GetServerPushResources(
vasilvvc48c8712019-03-11 13:38:16 -0700333 std::string request_url) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500334 QuicWriterMutexLock lock(&response_mutex_);
335
336 std::list<ServerPushInfo> resources;
337 auto resource_range = server_push_resources_.equal_range(request_url);
338 for (auto it = resource_range.first; it != resource_range.second; ++it) {
339 resources.push_back(it->second);
340 }
341 QUIC_DVLOG(1) << "Found " << resources.size() << " push resources for "
342 << request_url;
343 return resources;
344}
345
346QuicMemoryCacheBackend::~QuicMemoryCacheBackend() {
347 {
348 QuicWriterMutexLock lock(&response_mutex_);
349 responses_.clear();
350 }
351}
352
QUICHE team5015e2e2019-12-11 09:38:06 -0800353void QuicMemoryCacheBackend::AddResponseImpl(
vasilvv6c9e9c32020-10-08 08:16:57 -0700354 absl::string_view host,
355 absl::string_view path,
QUICHE team5015e2e2019-12-11 09:38:06 -0800356 SpecialResponseType response_type,
QUICHE team82103522020-10-22 08:15:09 -0700357 Http2HeaderBlock response_headers,
vasilvv6c9e9c32020-10-08 08:16:57 -0700358 absl::string_view response_body,
QUICHE team82103522020-10-22 08:15:09 -0700359 Http2HeaderBlock response_trailers) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500360 QuicWriterMutexLock lock(&response_mutex_);
361
362 DCHECK(!host.empty()) << "Host must be populated, e.g. \"www.google.com\"";
vasilvvc48c8712019-03-11 13:38:16 -0700363 std::string key = GetKey(host, path);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500364 if (QuicContainsKey(responses_, key)) {
365 QUIC_BUG << "Response for '" << key << "' already exists!";
366 return;
367 }
vasilvv0fc587f2019-09-06 13:33:08 -0700368 auto new_response = std::make_unique<QuicBackendResponse>();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500369 new_response->set_response_type(response_type);
370 new_response->set_headers(std::move(response_headers));
371 new_response->set_body(response_body);
372 new_response->set_trailers(std::move(response_trailers));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500373 QUIC_DVLOG(1) << "Add response with key " << key;
374 responses_[key] = std::move(new_response);
375}
376
vasilvv6c9e9c32020-10-08 08:16:57 -0700377std::string QuicMemoryCacheBackend::GetKey(absl::string_view host,
378 absl::string_view path) const {
vasilvvc48c8712019-03-11 13:38:16 -0700379 std::string host_string = std::string(host);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500380 size_t port = host_string.find(':');
vasilvvc48c8712019-03-11 13:38:16 -0700381 if (port != std::string::npos)
382 host_string = std::string(host_string.c_str(), port);
383 return host_string + std::string(path);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500384}
385
386void QuicMemoryCacheBackend::MaybeAddServerPushResources(
vasilvv6c9e9c32020-10-08 08:16:57 -0700387 absl::string_view request_host,
388 absl::string_view request_path,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500389 std::list<ServerPushInfo> push_resources) {
vasilvvc48c8712019-03-11 13:38:16 -0700390 std::string request_url = GetKey(request_host, request_path);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500391
392 for (const auto& push_resource : push_resources) {
393 if (PushResourceExistsInCache(request_url, push_resource)) {
394 continue;
395 }
396
397 QUIC_DVLOG(1) << "Add request-resource association: request url "
398 << request_url << " push url "
399 << push_resource.request_url.ToString()
400 << " response headers "
401 << push_resource.headers.DebugString();
402 {
403 QuicWriterMutexLock lock(&response_mutex_);
404 server_push_resources_.insert(std::make_pair(request_url, push_resource));
405 }
vasilvvc48c8712019-03-11 13:38:16 -0700406 std::string host = push_resource.request_url.host();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500407 if (host.empty()) {
vasilvvc48c8712019-03-11 13:38:16 -0700408 host = std::string(request_host);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500409 }
vasilvvc48c8712019-03-11 13:38:16 -0700410 std::string path = push_resource.request_url.path();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500411 bool found_existing_response = false;
412 {
413 QuicWriterMutexLock lock(&response_mutex_);
414 found_existing_response = QuicContainsKey(responses_, GetKey(host, path));
415 }
416 if (!found_existing_response) {
417 // Add a server push response to responses map, if it is not in the map.
vasilvv6c9e9c32020-10-08 08:16:57 -0700418 absl::string_view body = push_resource.body;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500419 QUIC_DVLOG(1) << "Add response for push resource: host " << host
420 << " path " << path;
421 AddResponse(host, path, push_resource.headers.Clone(), body);
422 }
423 }
424}
425
426bool QuicMemoryCacheBackend::PushResourceExistsInCache(
vasilvvc48c8712019-03-11 13:38:16 -0700427 std::string original_request_url,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500428 ServerPushInfo resource) {
429 QuicWriterMutexLock lock(&response_mutex_);
430 auto resource_range =
431 server_push_resources_.equal_range(original_request_url);
432 for (auto it = resource_range.first; it != resource_range.second; ++it) {
433 ServerPushInfo push_resource = it->second;
434 if (push_resource.request_url.ToString() ==
435 resource.request_url.ToString()) {
436 return true;
437 }
438 }
439 return false;
440}
441
442} // namespace quic