| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2009 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/tools/flip_server/mem_cache.h" | |
| 6 | |
| 7 #include <dirent.h> | |
| 8 #include <errno.h> | |
| 9 #include <fcntl.h> | |
| 10 #include <stdio.h> | |
| 11 #include <sys/stat.h> | |
| 12 #include <sys/types.h> | |
| 13 #include <unistd.h> | |
| 14 | |
| 15 #include <deque> | |
| 16 #include <map> | |
| 17 #include <string> | |
| 18 | |
| 19 #include "base/strings/string_util.h" | |
| 20 #include "net/tools/balsa/balsa_frame.h" | |
| 21 #include "net/tools/balsa/balsa_headers.h" | |
| 22 #include "net/tools/dump_cache/url_to_filename_encoder.h" | |
| 23 #include "net/tools/dump_cache/url_utilities.h" | |
| 24 | |
| 25 namespace { | |
| 26 // The directory where cache locates); | |
| 27 const char FLAGS_cache_base_dir[] = "."; | |
| 28 } // namespace | |
| 29 | |
| 30 namespace net { | |
| 31 | |
| 32 void StoreBodyAndHeadersVisitor::ProcessBodyData(const char* input, | |
| 33 size_t size) { | |
| 34 body.append(input, size); | |
| 35 } | |
| 36 | |
| 37 void StoreBodyAndHeadersVisitor::HandleHeaderError(BalsaFrame* framer) { | |
| 38 HandleError(); | |
| 39 } | |
| 40 | |
| 41 void StoreBodyAndHeadersVisitor::HandleHeaderWarning(BalsaFrame* framer) { | |
| 42 HandleError(); | |
| 43 } | |
| 44 | |
| 45 void StoreBodyAndHeadersVisitor::HandleChunkingError(BalsaFrame* framer) { | |
| 46 HandleError(); | |
| 47 } | |
| 48 | |
| 49 void StoreBodyAndHeadersVisitor::HandleBodyError(BalsaFrame* framer) { | |
| 50 HandleError(); | |
| 51 } | |
| 52 | |
| 53 FileData::FileData(const BalsaHeaders* headers, | |
| 54 const std::string& filename, | |
| 55 const std::string& body) | |
| 56 : filename_(filename), body_(body) { | |
| 57 if (headers) { | |
| 58 headers_.reset(new BalsaHeaders); | |
| 59 headers_->CopyFrom(*headers); | |
| 60 } | |
| 61 } | |
| 62 | |
| 63 FileData::FileData() {} | |
| 64 | |
| 65 FileData::~FileData() {} | |
| 66 | |
| 67 MemoryCache::MemoryCache() : cwd_(FLAGS_cache_base_dir) {} | |
| 68 | |
| 69 MemoryCache::~MemoryCache() { ClearFiles(); } | |
| 70 | |
| 71 void MemoryCache::CloneFrom(const MemoryCache& mc) { | |
| 72 DCHECK_NE(this, &mc); | |
| 73 ClearFiles(); | |
| 74 files_ = mc.files_; | |
| 75 cwd_ = mc.cwd_; | |
| 76 } | |
| 77 | |
| 78 void MemoryCache::AddFiles() { | |
| 79 std::deque<std::string> paths; | |
| 80 paths.push_back(cwd_ + "/GET_"); | |
| 81 DIR* current_dir = NULL; | |
| 82 while (!paths.empty()) { | |
| 83 while (current_dir == NULL && !paths.empty()) { | |
| 84 std::string current_dir_name = paths.front(); | |
| 85 VLOG(1) << "Attempting to open dir: \"" << current_dir_name << "\""; | |
| 86 current_dir = opendir(current_dir_name.c_str()); | |
| 87 paths.pop_front(); | |
| 88 | |
| 89 if (current_dir == NULL) { | |
| 90 perror("Unable to open directory. "); | |
| 91 current_dir_name.clear(); | |
| 92 continue; | |
| 93 } | |
| 94 | |
| 95 if (current_dir) { | |
| 96 VLOG(1) << "Succeeded opening"; | |
| 97 for (struct dirent* dir_data = readdir(current_dir); dir_data != NULL; | |
| 98 dir_data = readdir(current_dir)) { | |
| 99 std::string current_entry_name = | |
| 100 current_dir_name + "/" + dir_data->d_name; | |
| 101 if (dir_data->d_type == DT_REG) { | |
| 102 VLOG(1) << "Found file: " << current_entry_name; | |
| 103 ReadAndStoreFileContents(current_entry_name.c_str()); | |
| 104 } else if (dir_data->d_type == DT_DIR) { | |
| 105 VLOG(1) << "Found subdir: " << current_entry_name; | |
| 106 if (std::string(dir_data->d_name) != "." && | |
| 107 std::string(dir_data->d_name) != "..") { | |
| 108 VLOG(1) << "Adding to search path: " << current_entry_name; | |
| 109 paths.push_front(current_entry_name); | |
| 110 } | |
| 111 } | |
| 112 } | |
| 113 VLOG(1) << "Oops, no data left. Closing dir."; | |
| 114 closedir(current_dir); | |
| 115 current_dir = NULL; | |
| 116 } | |
| 117 } | |
| 118 } | |
| 119 } | |
| 120 | |
| 121 void MemoryCache::ReadToString(const char* filename, std::string* output) { | |
| 122 output->clear(); | |
| 123 int fd = open(filename, 0, "r"); | |
| 124 if (fd == -1) | |
| 125 return; | |
| 126 char buffer[4096]; | |
| 127 ssize_t read_status = read(fd, buffer, sizeof(buffer)); | |
| 128 while (read_status > 0) { | |
| 129 output->append(buffer, static_cast<size_t>(read_status)); | |
| 130 do { | |
| 131 read_status = read(fd, buffer, sizeof(buffer)); | |
| 132 } while (read_status <= 0 && errno == EINTR); | |
| 133 } | |
| 134 close(fd); | |
| 135 } | |
| 136 | |
| 137 void MemoryCache::ReadAndStoreFileContents(const char* filename) { | |
| 138 StoreBodyAndHeadersVisitor visitor; | |
| 139 BalsaFrame framer; | |
| 140 framer.set_balsa_visitor(&visitor); | |
| 141 framer.set_balsa_headers(&(visitor.headers)); | |
| 142 std::string filename_contents; | |
| 143 ReadToString(filename, &filename_contents); | |
| 144 | |
| 145 // Ugly hack to make everything look like 1.1. | |
| 146 if (filename_contents.find("HTTP/1.0") == 0) | |
| 147 filename_contents[7] = '1'; | |
| 148 | |
| 149 size_t pos = 0; | |
| 150 size_t old_pos = 0; | |
| 151 while (true) { | |
| 152 old_pos = pos; | |
| 153 pos += framer.ProcessInput(filename_contents.data() + pos, | |
| 154 filename_contents.size() - pos); | |
| 155 if (framer.Error() || pos == old_pos) { | |
| 156 LOG(ERROR) << "Unable to make forward progress, or error" | |
| 157 " framing file: " << filename; | |
| 158 if (framer.Error()) { | |
| 159 LOG(INFO) << "********************************************ERROR!"; | |
| 160 return; | |
| 161 } | |
| 162 return; | |
| 163 } | |
| 164 if (framer.MessageFullyRead()) { | |
| 165 // If no Content-Length or Transfer-Encoding was captured in the | |
| 166 // file, then the rest of the data is the body. Many of the captures | |
| 167 // from within Chrome don't have content-lengths. | |
| 168 if (!visitor.body.length()) | |
| 169 visitor.body = filename_contents.substr(pos); | |
| 170 break; | |
| 171 } | |
| 172 } | |
| 173 visitor.headers.RemoveAllOfHeader("content-length"); | |
| 174 visitor.headers.RemoveAllOfHeader("transfer-encoding"); | |
| 175 visitor.headers.RemoveAllOfHeader("connection"); | |
| 176 visitor.headers.AppendHeader("transfer-encoding", "chunked"); | |
| 177 visitor.headers.AppendHeader("connection", "keep-alive"); | |
| 178 | |
| 179 // Experiment with changing headers for forcing use of cached | |
| 180 // versions of content. | |
| 181 // TODO(mbelshe) REMOVE ME | |
| 182 #if 0 | |
| 183 // TODO(mbelshe) append current date. | |
| 184 visitor.headers.RemoveAllOfHeader("date"); | |
| 185 if (visitor.headers.HasHeader("expires")) { | |
| 186 visitor.headers.RemoveAllOfHeader("expires"); | |
| 187 visitor.headers.AppendHeader("expires", | |
| 188 "Fri, 30 Aug, 2019 12:00:00 GMT"); | |
| 189 } | |
| 190 #endif | |
| 191 DCHECK_GE(std::string(filename).size(), cwd_.size() + 1); | |
| 192 DCHECK_EQ(std::string(filename).substr(0, cwd_.size()), cwd_); | |
| 193 DCHECK_EQ(filename[cwd_.size()], '/'); | |
| 194 std::string filename_stripped = std::string(filename).substr(cwd_.size() + 1); | |
| 195 LOG(INFO) << "Adding file (" << visitor.body.length() | |
| 196 << " bytes): " << filename_stripped; | |
| 197 size_t slash_pos = filename_stripped.find('/'); | |
| 198 if (slash_pos == std::string::npos) { | |
| 199 slash_pos = filename_stripped.size(); | |
| 200 } | |
| 201 InsertFile( | |
| 202 &visitor.headers, filename_stripped.substr(0, slash_pos), visitor.body); | |
| 203 } | |
| 204 | |
| 205 FileData* MemoryCache::GetFileData(const std::string& filename) { | |
| 206 Files::iterator fi = files_.end(); | |
| 207 if (EndsWith(filename, ".html", true)) { | |
| 208 fi = files_.find(filename.substr(0, filename.size() - 5) + ".http"); | |
| 209 } | |
| 210 if (fi == files_.end()) | |
| 211 fi = files_.find(filename); | |
| 212 | |
| 213 if (fi == files_.end()) { | |
| 214 return NULL; | |
| 215 } | |
| 216 return fi->second; | |
| 217 } | |
| 218 | |
| 219 bool MemoryCache::AssignFileData(const std::string& filename, | |
| 220 MemCacheIter* mci) { | |
| 221 mci->file_data = GetFileData(filename); | |
| 222 if (mci->file_data == NULL) { | |
| 223 LOG(ERROR) << "Could not find file data for " << filename; | |
| 224 return false; | |
| 225 } | |
| 226 return true; | |
| 227 } | |
| 228 | |
| 229 void MemoryCache::InsertFile(const BalsaHeaders* headers, | |
| 230 const std::string& filename, | |
| 231 const std::string& body) { | |
| 232 InsertFile(new FileData(headers, filename, body)); | |
| 233 } | |
| 234 | |
| 235 void MemoryCache::InsertFile(FileData* file_data) { | |
| 236 Files::iterator it = files_.find(file_data->filename()); | |
| 237 if (it != files_.end()) { | |
| 238 delete it->second; | |
| 239 it->second = file_data; | |
| 240 } else { | |
| 241 files_.insert(std::make_pair(file_data->filename(), file_data)); | |
| 242 } | |
| 243 } | |
| 244 | |
| 245 void MemoryCache::ClearFiles() { | |
| 246 for (Files::const_iterator i = files_.begin(); i != files_.end(); ++i) { | |
| 247 delete i->second; | |
| 248 } | |
| 249 files_.clear(); | |
| 250 } | |
| 251 | |
| 252 } // namespace net | |
| OLD | NEW |