blob: c7ac912779000e53968a3289ea3ae2bc2e343639 [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
5#include "net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h"
6
7#include <utility>
8
9#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h"
10#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
11#include "net/third_party/quiche/src/quic/platform/api/quic_file_utils.h"
12#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
13#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
QUICHE team5015e2e2019-12-11 09:38:06 -080014#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
15#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050016
17using spdy::kV3LowestPriority;
18using spdy::SpdyHeaderBlock;
19
20namespace quic {
21
vasilvvc48c8712019-03-11 13:38:16 -070022QuicMemoryCacheBackend::ResourceFile::ResourceFile(const std::string& file_name)
QUICHE teama6ef0a62019-03-07 20:34:33 -050023 : file_name_(file_name) {}
24
25QuicMemoryCacheBackend::ResourceFile::~ResourceFile() = default;
26
27void QuicMemoryCacheBackend::ResourceFile::Read() {
28 ReadFileContents(file_name_, &file_contents_);
29
30 // First read the headers.
31 size_t start = 0;
32 while (start < file_contents_.length()) {
33 size_t pos = file_contents_.find("\n", start);
vasilvvc48c8712019-03-11 13:38:16 -070034 if (pos == std::string::npos) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050035 QUIC_LOG(DFATAL) << "Headers invalid or empty, ignoring: " << file_name_;
36 return;
37 }
38 size_t len = pos - start;
39 // Support both dos and unix line endings for convenience.
40 if (file_contents_[pos - 1] == '\r') {
41 len -= 1;
42 }
QUICHE team5015e2e2019-12-11 09:38:06 -080043 quiche::QuicheStringPiece line(file_contents_.data() + start, len);
QUICHE teama6ef0a62019-03-07 20:34:33 -050044 start = pos + 1;
45 // Headers end with an empty line.
46 if (line.empty()) {
47 break;
48 }
49 // Extract the status from the HTTP first line.
50 if (line.substr(0, 4) == "HTTP") {
51 pos = line.find(" ");
vasilvvc48c8712019-03-11 13:38:16 -070052 if (pos == std::string::npos) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050053 QUIC_LOG(DFATAL) << "Headers invalid or empty, ignoring: "
54 << file_name_;
55 return;
56 }
57 spdy_headers_[":status"] = line.substr(pos + 1, 3);
58 continue;
59 }
60 // Headers are "key: value".
61 pos = line.find(": ");
vasilvvc48c8712019-03-11 13:38:16 -070062 if (pos == std::string::npos) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050063 QUIC_LOG(DFATAL) << "Headers invalid or empty, ignoring: " << file_name_;
64 return;
65 }
66 spdy_headers_.AppendValueOrAddHeader(
QUICHE team5015e2e2019-12-11 09:38:06 -080067 quiche::QuicheTextUtils::ToLower(line.substr(0, pos)),
68 line.substr(pos + 2));
QUICHE teama6ef0a62019-03-07 20:34:33 -050069 }
70
71 // The connection header is prohibited in HTTP/2.
72 spdy_headers_.erase("connection");
73
74 // Override the URL with the X-Original-Url header, if present.
75 auto it = spdy_headers_.find("x-original-url");
76 if (it != spdy_headers_.end()) {
77 x_original_url_ = it->second;
78 HandleXOriginalUrl();
79 }
80
81 // X-Push-URL header is a relatively quick way to support sever push
82 // in the toy server. A production server should use link=preload
83 // stuff as described in https://w3c.github.io/preload/.
84 it = spdy_headers_.find("x-push-url");
85 if (it != spdy_headers_.end()) {
QUICHE team5015e2e2019-12-11 09:38:06 -080086 quiche::QuicheStringPiece push_urls = it->second;
QUICHE teama6ef0a62019-03-07 20:34:33 -050087 size_t start = 0;
88 while (start < push_urls.length()) {
89 size_t pos = push_urls.find('\0', start);
vasilvvc48c8712019-03-11 13:38:16 -070090 if (pos == std::string::npos) {
QUICHE team5015e2e2019-12-11 09:38:06 -080091 push_urls_.push_back(quiche::QuicheStringPiece(
92 push_urls.data() + start, push_urls.length() - start));
QUICHE teama6ef0a62019-03-07 20:34:33 -050093 break;
94 }
QUICHE team5015e2e2019-12-11 09:38:06 -080095 push_urls_.push_back(
96 quiche::QuicheStringPiece(push_urls.data() + start, pos));
QUICHE teama6ef0a62019-03-07 20:34:33 -050097 start += pos + 1;
98 }
99 }
100
QUICHE team5015e2e2019-12-11 09:38:06 -0800101 body_ = quiche::QuicheStringPiece(file_contents_.data() + start,
102 file_contents_.size() - start);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500103}
104
105void QuicMemoryCacheBackend::ResourceFile::SetHostPathFromBase(
QUICHE team5015e2e2019-12-11 09:38:06 -0800106 quiche::QuicheStringPiece base) {
rch3706b232019-12-12 21:40:54 -0800107 DCHECK(base[0] != '/') << base;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500108 size_t path_start = base.find_first_of('/');
rchf0ff4932019-12-16 16:25:56 -0800109 if (path_start == quiche::QuicheStringPiece::npos) {
110 host_ = std::string(base);
111 path_ = "";
112 return;
113 }
114
rch3706b232019-12-12 21:40:54 -0800115 host_ = std::string(base.substr(0, path_start));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500116 size_t query_start = base.find_first_of(',');
117 if (query_start > 0) {
rch3706b232019-12-12 21:40:54 -0800118 path_ = std::string(base.substr(path_start, query_start - 1));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500119 } else {
rch3706b232019-12-12 21:40:54 -0800120 path_ = std::string(base.substr(path_start));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500121 }
122}
123
QUICHE team5015e2e2019-12-11 09:38:06 -0800124quiche::QuicheStringPiece QuicMemoryCacheBackend::ResourceFile::RemoveScheme(
125 quiche::QuicheStringPiece url) {
126 if (quiche::QuicheTextUtils::StartsWith(url, "https://")) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500127 url.remove_prefix(8);
QUICHE team5015e2e2019-12-11 09:38:06 -0800128 } else if (quiche::QuicheTextUtils::StartsWith(url, "http://")) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500129 url.remove_prefix(7);
130 }
131 return url;
132}
133
134void QuicMemoryCacheBackend::ResourceFile::HandleXOriginalUrl() {
QUICHE team5015e2e2019-12-11 09:38:06 -0800135 quiche::QuicheStringPiece url(x_original_url_);
rch3706b232019-12-12 21:40:54 -0800136 SetHostPathFromBase(RemoveScheme(url));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500137}
138
139const QuicBackendResponse* QuicMemoryCacheBackend::GetResponse(
QUICHE team5015e2e2019-12-11 09:38:06 -0800140 quiche::QuicheStringPiece host,
141 quiche::QuicheStringPiece path) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500142 QuicWriterMutexLock lock(&response_mutex_);
143
144 auto it = responses_.find(GetKey(host, path));
145 if (it == responses_.end()) {
rch7bd54762019-10-15 10:53:24 -0700146 uint64_t ignored = 0;
147 if (generate_bytes_response_) {
QUICHE team5015e2e2019-12-11 09:38:06 -0800148 if (quiche::QuicheTextUtils::StringToUint64(
149 quiche::QuicheStringPiece(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
166typedef QuicBackendResponse::ServerPushInfo ServerPushInfo;
167typedef QuicBackendResponse::SpecialResponseType SpecialResponseType;
168
QUICHE team5015e2e2019-12-11 09:38:06 -0800169void QuicMemoryCacheBackend::AddSimpleResponse(quiche::QuicheStringPiece host,
170 quiche::QuicheStringPiece path,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500171 int response_code,
QUICHE team5015e2e2019-12-11 09:38:06 -0800172 quiche::QuicheStringPiece body) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500173 SpdyHeaderBlock 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(
QUICHE team5015e2e2019-12-11 09:38:06 -0800182 quiche::QuicheStringPiece host,
183 quiche::QuicheStringPiece path,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500184 int response_code,
QUICHE team5015e2e2019-12-11 09:38:06 -0800185 quiche::QuicheStringPiece 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
QUICHE team5015e2e2019-12-11 09:38:06 -0800196void QuicMemoryCacheBackend::AddResponse(
197 quiche::QuicheStringPiece host,
198 quiche::QuicheStringPiece path,
199 SpdyHeaderBlock response_headers,
200 quiche::QuicheStringPiece response_body) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500201 AddResponseImpl(host, path, QuicBackendResponse::REGULAR_RESPONSE,
202 std::move(response_headers), response_body, SpdyHeaderBlock(),
203 0);
204}
205
QUICHE team5015e2e2019-12-11 09:38:06 -0800206void QuicMemoryCacheBackend::AddResponse(
207 quiche::QuicheStringPiece host,
208 quiche::QuicheStringPiece path,
209 SpdyHeaderBlock response_headers,
210 quiche::QuicheStringPiece response_body,
211 SpdyHeaderBlock response_trailers) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500212 AddResponseImpl(host, path, QuicBackendResponse::REGULAR_RESPONSE,
213 std::move(response_headers), response_body,
214 std::move(response_trailers), 0);
215}
216
217void QuicMemoryCacheBackend::AddSpecialResponse(
QUICHE team5015e2e2019-12-11 09:38:06 -0800218 quiche::QuicheStringPiece host,
219 quiche::QuicheStringPiece path,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500220 SpecialResponseType response_type) {
221 AddResponseImpl(host, path, response_type, SpdyHeaderBlock(), "",
222 SpdyHeaderBlock(), 0);
223}
224
225void QuicMemoryCacheBackend::AddSpecialResponse(
QUICHE team5015e2e2019-12-11 09:38:06 -0800226 quiche::QuicheStringPiece host,
227 quiche::QuicheStringPiece path,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500228 spdy::SpdyHeaderBlock response_headers,
QUICHE team5015e2e2019-12-11 09:38:06 -0800229 quiche::QuicheStringPiece response_body,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500230 SpecialResponseType response_type) {
231 AddResponseImpl(host, path, response_type, std::move(response_headers),
232 response_body, SpdyHeaderBlock(), 0);
233}
234
235void QuicMemoryCacheBackend::AddStopSendingResponse(
QUICHE team5015e2e2019-12-11 09:38:06 -0800236 quiche::QuicheStringPiece host,
237 quiche::QuicheStringPiece path,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500238 spdy::SpdyHeaderBlock response_headers,
QUICHE team5015e2e2019-12-11 09:38:06 -0800239 quiche::QuicheStringPiece response_body,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500240 uint16_t stop_sending_code) {
241 AddResponseImpl(host, path, SpecialResponseType::STOP_SENDING,
242 std::move(response_headers), response_body, SpdyHeaderBlock(),
243 stop_sending_code);
244}
245
246QuicMemoryCacheBackend::QuicMemoryCacheBackend() : cache_initialized_(false) {}
247
248bool QuicMemoryCacheBackend::InitializeBackend(
vasilvvc48c8712019-03-11 13:38:16 -0700249 const std::string& cache_directory) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500250 if (cache_directory.empty()) {
251 QUIC_BUG << "cache_directory must not be empty.";
252 return false;
253 }
254 QUIC_LOG(INFO)
255 << "Attempting to initialize QuicMemoryCacheBackend from directory: "
256 << cache_directory;
vasilvvc48c8712019-03-11 13:38:16 -0700257 std::vector<std::string> files = ReadFileContents(cache_directory);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500258 std::list<std::unique_ptr<ResourceFile>> resource_files;
259 for (const auto& filename : files) {
260 std::unique_ptr<ResourceFile> resource_file(new ResourceFile(filename));
261
262 // Tease apart filename into host and path.
rch3706b232019-12-12 21:40:54 -0800263 std::string base(resource_file->file_name());
264 // Transform windows path separators to URL path separators.
265 for (size_t i = 0; i < base.length(); ++i) {
266 if (base[i] == '\\') {
267 base[i] = '/';
268 }
269 }
270 base.erase(0, cache_directory.length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500271 if (base[0] == '/') {
rch3706b232019-12-12 21:40:54 -0800272 base.erase(0, 1);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500273 }
274
275 resource_file->SetHostPathFromBase(base);
276 resource_file->Read();
277
278 AddResponse(resource_file->host(), resource_file->path(),
279 resource_file->spdy_headers().Clone(), resource_file->body());
280
281 resource_files.push_back(std::move(resource_file));
282 }
283
284 for (const auto& resource_file : resource_files) {
285 std::list<ServerPushInfo> push_resources;
286 for (const auto& push_url : resource_file->push_urls()) {
287 QuicUrl url(push_url);
288 const QuicBackendResponse* response = GetResponse(url.host(), url.path());
289 if (!response) {
290 QUIC_BUG << "Push URL '" << push_url << "' not found.";
291 return false;
292 }
293 push_resources.push_back(ServerPushInfo(url, response->headers().Clone(),
294 kV3LowestPriority,
vasilvvc48c8712019-03-11 13:38:16 -0700295 (std::string(response->body()))));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500296 }
297 MaybeAddServerPushResources(resource_file->host(), resource_file->path(),
298 push_resources);
299 }
rch7bd54762019-10-15 10:53:24 -0700300
QUICHE teama6ef0a62019-03-07 20:34:33 -0500301 cache_initialized_ = true;
302 return true;
303}
304
rch7bd54762019-10-15 10:53:24 -0700305void QuicMemoryCacheBackend::GenerateDynamicResponses() {
306 QuicWriterMutexLock lock(&response_mutex_);
307 // Add a generate bytes response.
308 spdy::SpdyHeaderBlock response_headers;
rch7bd54762019-10-15 10:53:24 -0700309 response_headers[":status"] = "200";
310 generate_bytes_response_ = std::make_unique<QuicBackendResponse>();
311 generate_bytes_response_->set_headers(std::move(response_headers));
312 generate_bytes_response_->set_response_type(
313 QuicBackendResponse::GENERATE_BYTES);
314}
315
QUICHE teama6ef0a62019-03-07 20:34:33 -0500316bool QuicMemoryCacheBackend::IsBackendInitialized() const {
317 return cache_initialized_;
318}
319
320void QuicMemoryCacheBackend::FetchResponseFromBackend(
321 const SpdyHeaderBlock& request_headers,
dschinazi17d42422019-06-18 16:35:07 -0700322 const std::string& /*request_body*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500323 QuicSimpleServerBackend::RequestHandler* quic_stream) {
324 const QuicBackendResponse* quic_response = nullptr;
325 // Find response in cache. If not found, send error response.
326 auto authority = request_headers.find(":authority");
327 auto path = request_headers.find(":path");
328 if (authority != request_headers.end() && path != request_headers.end()) {
329 quic_response = GetResponse(authority->second, path->second);
330 }
331
vasilvvc48c8712019-03-11 13:38:16 -0700332 std::string request_url =
333 std::string(authority->second) + std::string(path->second);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500334 std::list<ServerPushInfo> resources = GetServerPushResources(request_url);
335 QUIC_DVLOG(1)
336 << "Fetching QUIC response from backend in-memory cache for url "
337 << request_url;
338 quic_stream->OnResponseBackendComplete(quic_response, resources);
339}
340
341// The memory cache does not have a per-stream handler
342void QuicMemoryCacheBackend::CloseBackendResponseStream(
dschinazi17d42422019-06-18 16:35:07 -0700343 QuicSimpleServerBackend::RequestHandler* /*quic_stream*/) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500344
345std::list<ServerPushInfo> QuicMemoryCacheBackend::GetServerPushResources(
vasilvvc48c8712019-03-11 13:38:16 -0700346 std::string request_url) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500347 QuicWriterMutexLock lock(&response_mutex_);
348
349 std::list<ServerPushInfo> resources;
350 auto resource_range = server_push_resources_.equal_range(request_url);
351 for (auto it = resource_range.first; it != resource_range.second; ++it) {
352 resources.push_back(it->second);
353 }
354 QUIC_DVLOG(1) << "Found " << resources.size() << " push resources for "
355 << request_url;
356 return resources;
357}
358
359QuicMemoryCacheBackend::~QuicMemoryCacheBackend() {
360 {
361 QuicWriterMutexLock lock(&response_mutex_);
362 responses_.clear();
363 }
364}
365
QUICHE team5015e2e2019-12-11 09:38:06 -0800366void QuicMemoryCacheBackend::AddResponseImpl(
367 quiche::QuicheStringPiece host,
368 quiche::QuicheStringPiece path,
369 SpecialResponseType response_type,
370 SpdyHeaderBlock response_headers,
371 quiche::QuicheStringPiece response_body,
372 SpdyHeaderBlock response_trailers,
373 uint16_t stop_sending_code) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500374 QuicWriterMutexLock lock(&response_mutex_);
375
376 DCHECK(!host.empty()) << "Host must be populated, e.g. \"www.google.com\"";
vasilvvc48c8712019-03-11 13:38:16 -0700377 std::string key = GetKey(host, path);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500378 if (QuicContainsKey(responses_, key)) {
379 QUIC_BUG << "Response for '" << key << "' already exists!";
380 return;
381 }
vasilvv0fc587f2019-09-06 13:33:08 -0700382 auto new_response = std::make_unique<QuicBackendResponse>();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500383 new_response->set_response_type(response_type);
384 new_response->set_headers(std::move(response_headers));
385 new_response->set_body(response_body);
386 new_response->set_trailers(std::move(response_trailers));
387 new_response->set_stop_sending_code(stop_sending_code);
388 QUIC_DVLOG(1) << "Add response with key " << key;
389 responses_[key] = std::move(new_response);
390}
391
QUICHE team5015e2e2019-12-11 09:38:06 -0800392std::string QuicMemoryCacheBackend::GetKey(
393 quiche::QuicheStringPiece host,
394 quiche::QuicheStringPiece path) const {
vasilvvc48c8712019-03-11 13:38:16 -0700395 std::string host_string = std::string(host);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500396 size_t port = host_string.find(':');
vasilvvc48c8712019-03-11 13:38:16 -0700397 if (port != std::string::npos)
398 host_string = std::string(host_string.c_str(), port);
399 return host_string + std::string(path);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500400}
401
402void QuicMemoryCacheBackend::MaybeAddServerPushResources(
QUICHE team5015e2e2019-12-11 09:38:06 -0800403 quiche::QuicheStringPiece request_host,
404 quiche::QuicheStringPiece request_path,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500405 std::list<ServerPushInfo> push_resources) {
vasilvvc48c8712019-03-11 13:38:16 -0700406 std::string request_url = GetKey(request_host, request_path);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500407
408 for (const auto& push_resource : push_resources) {
409 if (PushResourceExistsInCache(request_url, push_resource)) {
410 continue;
411 }
412
413 QUIC_DVLOG(1) << "Add request-resource association: request url "
414 << request_url << " push url "
415 << push_resource.request_url.ToString()
416 << " response headers "
417 << push_resource.headers.DebugString();
418 {
419 QuicWriterMutexLock lock(&response_mutex_);
420 server_push_resources_.insert(std::make_pair(request_url, push_resource));
421 }
vasilvvc48c8712019-03-11 13:38:16 -0700422 std::string host = push_resource.request_url.host();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500423 if (host.empty()) {
vasilvvc48c8712019-03-11 13:38:16 -0700424 host = std::string(request_host);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500425 }
vasilvvc48c8712019-03-11 13:38:16 -0700426 std::string path = push_resource.request_url.path();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500427 bool found_existing_response = false;
428 {
429 QuicWriterMutexLock lock(&response_mutex_);
430 found_existing_response = QuicContainsKey(responses_, GetKey(host, path));
431 }
432 if (!found_existing_response) {
433 // Add a server push response to responses map, if it is not in the map.
QUICHE team5015e2e2019-12-11 09:38:06 -0800434 quiche::QuicheStringPiece body = push_resource.body;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500435 QUIC_DVLOG(1) << "Add response for push resource: host " << host
436 << " path " << path;
437 AddResponse(host, path, push_resource.headers.Clone(), body);
438 }
439 }
440}
441
442bool QuicMemoryCacheBackend::PushResourceExistsInCache(
vasilvvc48c8712019-03-11 13:38:16 -0700443 std::string original_request_url,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500444 ServerPushInfo resource) {
445 QuicWriterMutexLock lock(&response_mutex_);
446 auto resource_range =
447 server_push_resources_.equal_range(original_request_url);
448 for (auto it = resource_range.first; it != resource_range.second; ++it) {
449 ServerPushInfo push_resource = it->second;
450 if (push_resource.request_url.ToString() ==
451 resource.request_url.ToString()) {
452 return true;
453 }
454 }
455 return false;
456}
457
458} // namespace quic