| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/tools/quic/quic_http_response_cache.h" | 5 #include "net/tools/quic/quic_http_response_cache.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/files/file_enumerator.h" | 9 #include "base/files/file_enumerator.h" |
| 10 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
| 11 #include "base/memory/ptr_util.h" | 11 #include "base/memory/ptr_util.h" |
| 12 #include "base/stl_util.h" | 12 #include "base/stl_util.h" |
| 13 #include "net/http/http_util.h" | 13 #include "net/http/http_util.h" |
| 14 #include "net/quic/platform/api/quic_bug_tracker.h" | 14 #include "net/quic/platform/api/quic_bug_tracker.h" |
| 15 #include "net/quic/platform/api/quic_logging.h" | |
| 16 #include "net/quic/platform/api/quic_text_utils.h" | 15 #include "net/quic/platform/api/quic_text_utils.h" |
| 17 #include "net/spdy/spdy_http_utils.h" | 16 #include "net/spdy/spdy_http_utils.h" |
| 18 | 17 |
| 19 using base::FilePath; | 18 using base::FilePath; |
| 20 using base::IntToString; | 19 using base::IntToString; |
| 21 using base::StringPiece; | 20 using base::StringPiece; |
| 22 using std::string; | 21 using std::string; |
| 23 | 22 |
| 24 namespace net { | 23 namespace net { |
| 25 | 24 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 46 QuicHttpResponseCache::Response::~Response() {} | 45 QuicHttpResponseCache::Response::~Response() {} |
| 47 | 46 |
| 48 void QuicHttpResponseCache::ResourceFile::Read() { | 47 void QuicHttpResponseCache::ResourceFile::Read() { |
| 49 base::ReadFileToString(FilePath(file_name_), &file_contents_); | 48 base::ReadFileToString(FilePath(file_name_), &file_contents_); |
| 50 | 49 |
| 51 // First read the headers. | 50 // First read the headers. |
| 52 size_t start = 0; | 51 size_t start = 0; |
| 53 while (start < file_contents_.length()) { | 52 while (start < file_contents_.length()) { |
| 54 size_t pos = file_contents_.find("\n", start); | 53 size_t pos = file_contents_.find("\n", start); |
| 55 if (pos == string::npos) { | 54 if (pos == string::npos) { |
| 56 QUIC_LOG(DFATAL) << "Headers invalid or empty, ignoring: " | 55 LOG(DFATAL) << "Headers invalid or empty, ignoring: " |
| 57 << file_name_.value(); | 56 << file_name_.value(); |
| 58 return; | 57 return; |
| 59 } | 58 } |
| 60 size_t len = pos - start; | 59 size_t len = pos - start; |
| 61 // Support both dos and unix line endings for convenience. | 60 // Support both dos and unix line endings for convenience. |
| 62 if (file_contents_[pos - 1] == '\r') { | 61 if (file_contents_[pos - 1] == '\r') { |
| 63 len -= 1; | 62 len -= 1; |
| 64 } | 63 } |
| 65 StringPiece line(file_contents_.data() + start, len); | 64 StringPiece line(file_contents_.data() + start, len); |
| 66 start = pos + 1; | 65 start = pos + 1; |
| 67 // Headers end with an empty line. | 66 // Headers end with an empty line. |
| 68 if (line.empty()) { | 67 if (line.empty()) { |
| 69 break; | 68 break; |
| 70 } | 69 } |
| 71 // Extract the status from the HTTP first line. | 70 // Extract the status from the HTTP first line. |
| 72 if (line.substr(0, 4) == "HTTP") { | 71 if (line.substr(0, 4) == "HTTP") { |
| 73 pos = line.find(" "); | 72 pos = line.find(" "); |
| 74 if (pos == string::npos) { | 73 if (pos == string::npos) { |
| 75 QUIC_LOG(DFATAL) << "Headers invalid or empty, ignoring: " | 74 LOG(DFATAL) << "Headers invalid or empty, ignoring: " |
| 76 << file_name_.value(); | 75 << file_name_.value(); |
| 77 return; | 76 return; |
| 78 } | 77 } |
| 79 spdy_headers_[":status"] = line.substr(pos + 1, 3); | 78 spdy_headers_[":status"] = line.substr(pos + 1, 3); |
| 80 continue; | 79 continue; |
| 81 } | 80 } |
| 82 // Headers are "key: value". | 81 // Headers are "key: value". |
| 83 pos = line.find(": "); | 82 pos = line.find(": "); |
| 84 if (pos == string::npos) { | 83 if (pos == string::npos) { |
| 85 QUIC_LOG(DFATAL) << "Headers invalid or empty, ignoring: " | 84 LOG(DFATAL) << "Headers invalid or empty, ignoring: " |
| 86 << file_name_.value(); | 85 << file_name_.value(); |
| 87 return; | 86 return; |
| 88 } | 87 } |
| 89 spdy_headers_.AppendValueOrAddHeader( | 88 spdy_headers_.AppendValueOrAddHeader( |
| 90 QuicTextUtils::ToLower(line.substr(0, pos)), line.substr(pos + 2)); | 89 QuicTextUtils::ToLower(line.substr(0, pos)), line.substr(pos + 2)); |
| 91 } | 90 } |
| 92 | 91 |
| 93 // The connection header is prohibited in HTTP/2. | 92 // The connection header is prohibited in HTTP/2. |
| 94 spdy_headers_.erase("connection"); | 93 spdy_headers_.erase("connection"); |
| 95 | 94 |
| 96 // Override the URL with the X-Original-Url header, if present. | 95 // Override the URL with the X-Original-Url header, if present. |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 229 } | 228 } |
| 230 | 229 |
| 231 QuicHttpResponseCache::QuicHttpResponseCache() {} | 230 QuicHttpResponseCache::QuicHttpResponseCache() {} |
| 232 | 231 |
| 233 void QuicHttpResponseCache::InitializeFromDirectory( | 232 void QuicHttpResponseCache::InitializeFromDirectory( |
| 234 const string& cache_directory) { | 233 const string& cache_directory) { |
| 235 if (cache_directory.empty()) { | 234 if (cache_directory.empty()) { |
| 236 QUIC_BUG << "cache_directory must not be empty."; | 235 QUIC_BUG << "cache_directory must not be empty."; |
| 237 return; | 236 return; |
| 238 } | 237 } |
| 239 QUIC_LOG(INFO) | 238 VLOG(1) << "Attempting to initialize QuicHttpResponseCache from directory: " |
| 240 << "Attempting to initialize QuicHttpResponseCache from directory: " | 239 << cache_directory; |
| 241 << cache_directory; | |
| 242 FilePath directory(FilePath::FromUTF8Unsafe(cache_directory)); | 240 FilePath directory(FilePath::FromUTF8Unsafe(cache_directory)); |
| 243 base::FileEnumerator file_list(directory, true, base::FileEnumerator::FILES); | 241 base::FileEnumerator file_list(directory, true, base::FileEnumerator::FILES); |
| 244 std::list<std::unique_ptr<ResourceFile>> resource_files; | 242 std::list<std::unique_ptr<ResourceFile>> resource_files; |
| 245 for (FilePath file_iter = file_list.Next(); !file_iter.empty(); | 243 for (FilePath file_iter = file_list.Next(); !file_iter.empty(); |
| 246 file_iter = file_list.Next()) { | 244 file_iter = file_list.Next()) { |
| 247 // Need to skip files in .svn directories | 245 // Need to skip files in .svn directories |
| 248 if (file_iter.value().find(FILE_PATH_LITERAL("/.svn/")) != string::npos) { | 246 if (file_iter.value().find(FILE_PATH_LITERAL("/.svn/")) != string::npos) { |
| 249 continue; | 247 continue; |
| 250 } | 248 } |
| 251 | 249 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 287 | 285 |
| 288 std::list<ServerPushInfo> QuicHttpResponseCache::GetServerPushResources( | 286 std::list<ServerPushInfo> QuicHttpResponseCache::GetServerPushResources( |
| 289 string request_url) { | 287 string request_url) { |
| 290 QuicWriterMutexLock lock(&response_mutex_); | 288 QuicWriterMutexLock lock(&response_mutex_); |
| 291 | 289 |
| 292 std::list<ServerPushInfo> resources; | 290 std::list<ServerPushInfo> resources; |
| 293 auto resource_range = server_push_resources_.equal_range(request_url); | 291 auto resource_range = server_push_resources_.equal_range(request_url); |
| 294 for (auto it = resource_range.first; it != resource_range.second; ++it) { | 292 for (auto it = resource_range.first; it != resource_range.second; ++it) { |
| 295 resources.push_back(it->second); | 293 resources.push_back(it->second); |
| 296 } | 294 } |
| 297 QUIC_DVLOG(1) << "Found " << resources.size() << " push resources for " | 295 DVLOG(1) << "Found " << resources.size() << " push resources for " |
| 298 << request_url; | 296 << request_url; |
| 299 return resources; | 297 return resources; |
| 300 } | 298 } |
| 301 | 299 |
| 302 QuicHttpResponseCache::~QuicHttpResponseCache() { | 300 QuicHttpResponseCache::~QuicHttpResponseCache() { |
| 303 { | 301 { |
| 304 QuicWriterMutexLock lock(&response_mutex_); | 302 QuicWriterMutexLock lock(&response_mutex_); |
| 305 responses_.clear(); | 303 responses_.clear(); |
| 306 } | 304 } |
| 307 } | 305 } |
| 308 | 306 |
| 309 void QuicHttpResponseCache::AddResponseImpl(StringPiece host, | 307 void QuicHttpResponseCache::AddResponseImpl(StringPiece host, |
| 310 StringPiece path, | 308 StringPiece path, |
| 311 SpecialResponseType response_type, | 309 SpecialResponseType response_type, |
| 312 SpdyHeaderBlock response_headers, | 310 SpdyHeaderBlock response_headers, |
| 313 StringPiece response_body, | 311 StringPiece response_body, |
| 314 SpdyHeaderBlock response_trailers) { | 312 SpdyHeaderBlock response_trailers) { |
| 315 QuicWriterMutexLock lock(&response_mutex_); | 313 QuicWriterMutexLock lock(&response_mutex_); |
| 316 | 314 |
| 317 DCHECK(!host.empty()) << "Host must be populated, e.g. \"www.google.com\""; | 315 DCHECK(!host.empty()) << "Host must be populated, e.g. \"www.google.com\""; |
| 318 string key = GetKey(host, path); | 316 string key = GetKey(host, path); |
| 319 if (base::ContainsKey(responses_, key)) { | 317 if (base::ContainsKey(responses_, key)) { |
| 320 QUIC_BUG << "Response for '" << key << "' already exists!"; | 318 QUIC_BUG << "Response for '" << key << "' already exists!"; |
| 321 return; | 319 return; |
| 322 } | 320 } |
| 323 std::unique_ptr<Response> new_response = base::MakeUnique<Response>(); | 321 std::unique_ptr<Response> new_response = base::MakeUnique<Response>(); |
| 324 new_response->set_response_type(response_type); | 322 new_response->set_response_type(response_type); |
| 325 new_response->set_headers(std::move(response_headers)); | 323 new_response->set_headers(std::move(response_headers)); |
| 326 new_response->set_body(response_body); | 324 new_response->set_body(response_body); |
| 327 new_response->set_trailers(std::move(response_trailers)); | 325 new_response->set_trailers(std::move(response_trailers)); |
| 328 QUIC_DVLOG(1) << "Add response with key " << key; | 326 DVLOG(1) << "Add response with key " << key; |
| 329 responses_[key] = std::move(new_response); | 327 responses_[key] = std::move(new_response); |
| 330 } | 328 } |
| 331 | 329 |
| 332 string QuicHttpResponseCache::GetKey(StringPiece host, StringPiece path) const { | 330 string QuicHttpResponseCache::GetKey(StringPiece host, StringPiece path) const { |
| 333 return host.as_string() + path.as_string(); | 331 return host.as_string() + path.as_string(); |
| 334 } | 332 } |
| 335 | 333 |
| 336 void QuicHttpResponseCache::MaybeAddServerPushResources( | 334 void QuicHttpResponseCache::MaybeAddServerPushResources( |
| 337 StringPiece request_host, | 335 StringPiece request_host, |
| 338 StringPiece request_path, | 336 StringPiece request_path, |
| 339 std::list<ServerPushInfo> push_resources) { | 337 std::list<ServerPushInfo> push_resources) { |
| 340 string request_url = GetKey(request_host, request_path); | 338 string request_url = GetKey(request_host, request_path); |
| 341 | 339 |
| 342 for (const auto& push_resource : push_resources) { | 340 for (const auto& push_resource : push_resources) { |
| 343 if (PushResourceExistsInCache(request_url, push_resource)) { | 341 if (PushResourceExistsInCache(request_url, push_resource)) { |
| 344 continue; | 342 continue; |
| 345 } | 343 } |
| 346 | 344 |
| 347 QUIC_DVLOG(1) << "Add request-resource association: request url " | 345 DVLOG(1) << "Add request-resource association: request url " << request_url |
| 348 << request_url << " push url " << push_resource.request_url | 346 << " push url " << push_resource.request_url |
| 349 << " response headers " | 347 << " response headers " << push_resource.headers.DebugString(); |
| 350 << push_resource.headers.DebugString(); | |
| 351 { | 348 { |
| 352 QuicWriterMutexLock lock(&response_mutex_); | 349 QuicWriterMutexLock lock(&response_mutex_); |
| 353 server_push_resources_.insert(std::make_pair(request_url, push_resource)); | 350 server_push_resources_.insert(std::make_pair(request_url, push_resource)); |
| 354 } | 351 } |
| 355 string host = push_resource.request_url.host(); | 352 string host = push_resource.request_url.host(); |
| 356 if (host.empty()) { | 353 if (host.empty()) { |
| 357 host = request_host.as_string(); | 354 host = request_host.as_string(); |
| 358 } | 355 } |
| 359 string path = push_resource.request_url.path(); | 356 string path = push_resource.request_url.path(); |
| 360 bool found_existing_response = false; | 357 bool found_existing_response = false; |
| 361 { | 358 { |
| 362 QuicWriterMutexLock lock(&response_mutex_); | 359 QuicWriterMutexLock lock(&response_mutex_); |
| 363 found_existing_response = | 360 found_existing_response = |
| 364 base::ContainsKey(responses_, GetKey(host, path)); | 361 base::ContainsKey(responses_, GetKey(host, path)); |
| 365 } | 362 } |
| 366 if (!found_existing_response) { | 363 if (!found_existing_response) { |
| 367 // Add a server push response to responses map, if it is not in the map. | 364 // Add a server push response to responses map, if it is not in the map. |
| 368 StringPiece body = push_resource.body; | 365 StringPiece body = push_resource.body; |
| 369 QUIC_DVLOG(1) << "Add response for push resource: host " << host | 366 DVLOG(1) << "Add response for push resource: host " << host << " path " |
| 370 << " path " << path; | 367 << path; |
| 371 AddResponse(host, path, push_resource.headers.Clone(), body); | 368 AddResponse(host, path, push_resource.headers.Clone(), body); |
| 372 } | 369 } |
| 373 } | 370 } |
| 374 } | 371 } |
| 375 | 372 |
| 376 bool QuicHttpResponseCache::PushResourceExistsInCache( | 373 bool QuicHttpResponseCache::PushResourceExistsInCache( |
| 377 string original_request_url, | 374 string original_request_url, |
| 378 ServerPushInfo resource) { | 375 ServerPushInfo resource) { |
| 379 QuicWriterMutexLock lock(&response_mutex_); | 376 QuicWriterMutexLock lock(&response_mutex_); |
| 380 auto resource_range = | 377 auto resource_range = |
| 381 server_push_resources_.equal_range(original_request_url); | 378 server_push_resources_.equal_range(original_request_url); |
| 382 for (auto it = resource_range.first; it != resource_range.second; ++it) { | 379 for (auto it = resource_range.first; it != resource_range.second; ++it) { |
| 383 ServerPushInfo push_resource = it->second; | 380 ServerPushInfo push_resource = it->second; |
| 384 if (push_resource.request_url.spec() == resource.request_url.spec()) { | 381 if (push_resource.request_url.spec() == resource.request_url.spec()) { |
| 385 return true; | 382 return true; |
| 386 } | 383 } |
| 387 } | 384 } |
| 388 return false; | 385 return false; |
| 389 } | 386 } |
| 390 | 387 |
| 391 } // namespace net | 388 } // namespace net |
| OLD | NEW |