• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ProcessBodyData(const char * input,size_t size)32 void StoreBodyAndHeadersVisitor::ProcessBodyData(const char* input,
33                                                  size_t size) {
34   body.append(input, size);
35 }
36 
HandleHeaderError(BalsaFrame * framer)37 void StoreBodyAndHeadersVisitor::HandleHeaderError(BalsaFrame* framer) {
38   HandleError();
39 }
40 
HandleHeaderWarning(BalsaFrame * framer)41 void StoreBodyAndHeadersVisitor::HandleHeaderWarning(BalsaFrame* framer) {
42   HandleError();
43 }
44 
HandleChunkingError(BalsaFrame * framer)45 void StoreBodyAndHeadersVisitor::HandleChunkingError(BalsaFrame* framer) {
46   HandleError();
47 }
48 
HandleBodyError(BalsaFrame * framer)49 void StoreBodyAndHeadersVisitor::HandleBodyError(BalsaFrame* framer) {
50   HandleError();
51 }
52 
FileData(const BalsaHeaders * headers,const std::string & filename,const std::string & body)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 
FileData()63 FileData::FileData() {}
64 
~FileData()65 FileData::~FileData() {}
66 
MemoryCache()67 MemoryCache::MemoryCache() : cwd_(FLAGS_cache_base_dir) {}
68 
~MemoryCache()69 MemoryCache::~MemoryCache() { ClearFiles(); }
70 
CloneFrom(const MemoryCache & mc)71 void MemoryCache::CloneFrom(const MemoryCache& mc) {
72   DCHECK_NE(this, &mc);
73   ClearFiles();
74   files_ = mc.files_;
75   cwd_ = mc.cwd_;
76 }
77 
AddFiles()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 
ReadToString(const char * filename,std::string * output)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 
ReadAndStoreFileContents(const char * filename)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 
GetFileData(const std::string & filename)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 
AssignFileData(const std::string & filename,MemCacheIter * mci)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 
InsertFile(const BalsaHeaders * headers,const std::string & filename,const std::string & body)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 
InsertFile(FileData * file_data)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 
ClearFiles()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
253