| 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_in_memory_cache.h" | 5 #include "net/tools/quic/quic_in_memory_cache.h" |
| 6 | 6 |
| 7 #include "base/files/file_enumerator.h" | 7 #include "base/files/file_enumerator.h" |
| 8 #include "base/files/file_util.h" | 8 #include "base/files/file_util.h" |
| 9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
| 10 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
| 11 #include "net/tools/balsa/balsa_headers.h" | 11 #include "net/tools/balsa/balsa_headers.h" |
| 12 | 12 |
| 13 using base::FilePath; | 13 using base::FilePath; |
| 14 using base::StringPiece; | 14 using base::StringPiece; |
| 15 using std::string; | 15 using std::string; |
| 16 | 16 |
| 17 namespace net { |
| 18 namespace tools { |
| 19 |
| 17 // Specifies the directory used during QuicInMemoryCache | 20 // Specifies the directory used during QuicInMemoryCache |
| 18 // construction to seed the cache. Cache directory can be | 21 // construction to seed the cache. Cache directory can be |
| 19 // generated using `wget -p --save-headers <url> | 22 // generated using `wget -p --save-headers <url> |
| 20 | 23 string FLAGS_quic_in_memory_cache_dir = ""; |
| 21 namespace net { | |
| 22 namespace tools { | |
| 23 | |
| 24 std::string FLAGS_quic_in_memory_cache_dir = ""; | |
| 25 | 24 |
| 26 namespace { | 25 namespace { |
| 27 | 26 |
| 28 // BalsaVisitor implementation (glue) which caches response bodies. | 27 // BalsaVisitor implementation (glue) which caches response bodies. |
| 29 class CachingBalsaVisitor : public NoOpBalsaVisitor { | 28 class CachingBalsaVisitor : public NoOpBalsaVisitor { |
| 30 public: | 29 public: |
| 31 CachingBalsaVisitor() : done_framing_(false) {} | 30 CachingBalsaVisitor() : done_framing_(false) {} |
| 32 void ProcessBodyData(const char* input, size_t size) override { | 31 void ProcessBodyData(const char* input, size_t size) override { |
| 33 AppendToBody(input, size); | 32 AppendToBody(input, size); |
| 34 } | 33 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 52 }; | 51 }; |
| 53 | 52 |
| 54 } // namespace | 53 } // namespace |
| 55 | 54 |
| 56 // static | 55 // static |
| 57 QuicInMemoryCache* QuicInMemoryCache::GetInstance() { | 56 QuicInMemoryCache* QuicInMemoryCache::GetInstance() { |
| 58 return Singleton<QuicInMemoryCache>::get(); | 57 return Singleton<QuicInMemoryCache>::get(); |
| 59 } | 58 } |
| 60 | 59 |
| 61 const QuicInMemoryCache::Response* QuicInMemoryCache::GetResponse( | 60 const QuicInMemoryCache::Response* QuicInMemoryCache::GetResponse( |
| 62 const BalsaHeaders& request_headers) const { | 61 StringPiece host, |
| 63 ResponseMap::const_iterator it = responses_.find(GetKey(request_headers)); | 62 StringPiece path) const { |
| 63 ResponseMap::const_iterator it = responses_.find(GetKey(host, path)); |
| 64 if (it == responses_.end()) { | 64 if (it == responses_.end()) { |
| 65 return nullptr; | 65 return nullptr; |
| 66 } | 66 } |
| 67 return it->second; | 67 return it->second; |
| 68 } | 68 } |
| 69 | 69 |
| 70 void QuicInMemoryCache::AddSimpleResponse(StringPiece method, | 70 void QuicInMemoryCache::AddSimpleResponse(StringPiece host, |
| 71 StringPiece path, | 71 StringPiece path, |
| 72 StringPiece version, | 72 int response_code, |
| 73 StringPiece response_code, | |
| 74 StringPiece response_detail, | 73 StringPiece response_detail, |
| 75 StringPiece body) { | 74 StringPiece body) { |
| 76 BalsaHeaders request_headers, response_headers; | 75 BalsaHeaders response_headers; |
| 77 request_headers.SetRequestFirstlineFromStringPieces(method, | 76 response_headers.SetRequestFirstlineFromStringPieces( |
| 78 path, | 77 "HTTP/1.1", base::IntToString(response_code), response_detail); |
| 79 version); | |
| 80 response_headers.SetRequestFirstlineFromStringPieces(version, | |
| 81 response_code, | |
| 82 response_detail); | |
| 83 response_headers.AppendHeader("content-length", | 78 response_headers.AppendHeader("content-length", |
| 84 base::IntToString(body.length())); | 79 base::IntToString(body.length())); |
| 85 | 80 |
| 86 AddResponse(request_headers, response_headers, body); | 81 AddResponse(host, path, response_headers, body); |
| 87 } | 82 } |
| 88 | 83 |
| 89 void QuicInMemoryCache::AddResponse(const BalsaHeaders& request_headers, | 84 void QuicInMemoryCache::AddResponse(StringPiece host, |
| 85 StringPiece path, |
| 90 const BalsaHeaders& response_headers, | 86 const BalsaHeaders& response_headers, |
| 91 StringPiece response_body) { | 87 StringPiece response_body) { |
| 92 VLOG(1) << "Adding response for: " << GetKey(request_headers); | 88 AddResponseImpl(host, path, REGULAR_RESPONSE, response_headers, |
| 93 if (ContainsKey(responses_, GetKey(request_headers))) { | 89 response_body); |
| 94 LOG(DFATAL) << "Response for given request already exists!"; | |
| 95 return; | |
| 96 } | |
| 97 Response* new_response = new Response(); | |
| 98 new_response->set_headers(response_headers); | |
| 99 new_response->set_body(response_body); | |
| 100 responses_[GetKey(request_headers)] = new_response; | |
| 101 } | 90 } |
| 102 | 91 |
| 103 void QuicInMemoryCache::AddSpecialResponse(StringPiece method, | 92 void QuicInMemoryCache::AddSpecialResponse(StringPiece host, |
| 104 StringPiece path, | 93 StringPiece path, |
| 105 StringPiece version, | |
| 106 SpecialResponseType response_type) { | 94 SpecialResponseType response_type) { |
| 107 BalsaHeaders request_headers, response_headers; | 95 AddResponseImpl(host, path, response_type, BalsaHeaders(), ""); |
| 108 request_headers.SetRequestFirstlineFromStringPieces(method, | |
| 109 path, | |
| 110 version); | |
| 111 AddResponse(request_headers, response_headers, ""); | |
| 112 responses_[GetKey(request_headers)]->response_type_ = response_type; | |
| 113 } | 96 } |
| 114 | 97 |
| 115 QuicInMemoryCache::QuicInMemoryCache() { | 98 QuicInMemoryCache::QuicInMemoryCache() { |
| 116 Initialize(); | 99 Initialize(); |
| 117 } | 100 } |
| 118 | 101 |
| 119 void QuicInMemoryCache::ResetForTests() { | 102 void QuicInMemoryCache::ResetForTests() { |
| 120 STLDeleteValues(&responses_); | 103 STLDeleteValues(&responses_); |
| 121 Initialize(); | 104 Initialize(); |
| 122 } | 105 } |
| 123 | 106 |
| 124 void QuicInMemoryCache::Initialize() { | 107 void QuicInMemoryCache::Initialize() { |
| 125 // If there's no defined cache dir, we have no initialization to do. | 108 // If there's no defined cache dir, we have no initialization to do. |
| 126 if (FLAGS_quic_in_memory_cache_dir.empty()) { | 109 if (FLAGS_quic_in_memory_cache_dir.empty()) { |
| 127 VLOG(1) << "No cache directory found. Skipping initialization."; | 110 VLOG(1) << "No cache directory found. Skipping initialization."; |
| 128 return; | 111 return; |
| 129 } | 112 } |
| 130 VLOG(1) << "Attempting to initialize QuicInMemoryCache from directory: " | 113 VLOG(1) << "Attempting to initialize QuicInMemoryCache from directory: " |
| 131 << FLAGS_quic_in_memory_cache_dir; | 114 << FLAGS_quic_in_memory_cache_dir; |
| 132 | 115 |
| 133 FilePath directory(FLAGS_quic_in_memory_cache_dir); | 116 FilePath directory(FLAGS_quic_in_memory_cache_dir); |
| 134 base::FileEnumerator file_list(directory, | 117 base::FileEnumerator file_list(directory, |
| 135 true, | 118 true, |
| 136 base::FileEnumerator::FILES); | 119 base::FileEnumerator::FILES); |
| 137 | 120 |
| 138 FilePath file = file_list.Next(); | 121 for (FilePath file = file_list.Next(); !file.empty(); |
| 139 while (!file.empty()) { | 122 file = file_list.Next()) { |
| 140 // Need to skip files in .svn directories | 123 // Need to skip files in .svn directories |
| 141 if (file.value().find("/.svn/") != std::string::npos) { | 124 if (file.value().find("/.svn/") != string::npos) { |
| 142 file = file_list.Next(); | |
| 143 continue; | 125 continue; |
| 144 } | 126 } |
| 145 | 127 |
| 146 BalsaHeaders request_headers, response_headers; | 128 BalsaHeaders request_headers, response_headers; |
| 147 | 129 |
| 148 string file_contents; | 130 string file_contents; |
| 149 base::ReadFileToString(file, &file_contents); | 131 base::ReadFileToString(file, &file_contents); |
| 150 | 132 |
| 151 // Frame HTTP. | 133 // Frame HTTP. |
| 152 CachingBalsaVisitor caching_visitor; | 134 CachingBalsaVisitor caching_visitor; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 186 base.remove_prefix(7); | 168 base.remove_prefix(7); |
| 187 } | 169 } |
| 188 } | 170 } |
| 189 int path_start = base.find_first_of('/'); | 171 int path_start = base.find_first_of('/'); |
| 190 DCHECK_LT(0, path_start); | 172 DCHECK_LT(0, path_start); |
| 191 StringPiece host(base.substr(0, path_start)); | 173 StringPiece host(base.substr(0, path_start)); |
| 192 StringPiece path(base.substr(path_start)); | 174 StringPiece path(base.substr(path_start)); |
| 193 if (path[path.length() - 1] == ',') { | 175 if (path[path.length() - 1] == ',') { |
| 194 path.remove_suffix(1); | 176 path.remove_suffix(1); |
| 195 } | 177 } |
| 196 // Set up request headers. Assume method is GET and protocol is HTTP/1.1. | 178 AddResponse(host, path, response_headers, caching_visitor.body()); |
| 197 request_headers.SetRequestFirstlineFromStringPieces("GET", | |
| 198 path, | |
| 199 "HTTP/1.1"); | |
| 200 request_headers.ReplaceOrAppendHeader("host", host); | |
| 201 | |
| 202 VLOG(1) << "Inserting 'http://" << GetKey(request_headers) | |
| 203 << "' into QuicInMemoryCache."; | |
| 204 | |
| 205 AddResponse(request_headers, response_headers, caching_visitor.body()); | |
| 206 | |
| 207 file = file_list.Next(); | |
| 208 } | 179 } |
| 209 } | 180 } |
| 210 | 181 |
| 211 QuicInMemoryCache::~QuicInMemoryCache() { | 182 QuicInMemoryCache::~QuicInMemoryCache() { |
| 212 STLDeleteValues(&responses_); | 183 STLDeleteValues(&responses_); |
| 213 } | 184 } |
| 214 | 185 |
| 215 string QuicInMemoryCache::GetKey(const BalsaHeaders& request_headers) const { | 186 void QuicInMemoryCache::AddResponseImpl( |
| 216 StringPiece uri = request_headers.request_uri(); | 187 StringPiece host, |
| 217 if (uri.size() == 0) { | 188 StringPiece path, |
| 218 return ""; | 189 SpecialResponseType response_type, |
| 190 const BalsaHeaders& response_headers, |
| 191 StringPiece response_body) { |
| 192 string key = GetKey(host, path); |
| 193 VLOG(1) << "Adding response for: " << key; |
| 194 if (ContainsKey(responses_, key)) { |
| 195 LOG(DFATAL) << "Response for '" << key << "' already exists!"; |
| 196 return; |
| 219 } | 197 } |
| 220 StringPiece host; | 198 Response* new_response = new Response(); |
| 221 if (uri[0] == '/') { | 199 new_response->set_response_type(response_type); |
| 222 host = request_headers.GetHeader("host"); | 200 new_response->set_headers(response_headers); |
| 223 } else if (StringPieceUtils::StartsWithIgnoreCase(uri, "https://")) { | 201 new_response->set_body(response_body); |
| 224 uri.remove_prefix(8); | 202 responses_[key] = new_response; |
| 225 } else if (StringPieceUtils::StartsWithIgnoreCase(uri, "http://")) { | 203 } |
| 226 uri.remove_prefix(7); | 204 |
| 227 } | 205 string QuicInMemoryCache::GetKey(StringPiece host, StringPiece path) const { |
| 228 return host.as_string() + uri.as_string(); | 206 return host.as_string() + path.as_string(); |
| 229 } | 207 } |
| 230 | 208 |
| 231 } // namespace tools | 209 } // namespace tools |
| 232 } // namespace net | 210 } // namespace net |
| OLD | NEW |