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