Home | History | Annotate | Download | only in flip_server
      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 
     27 void StoreBodyAndHeadersVisitor::ProcessBodyData(const char *input,
     28                                                  size_t size) {
     29   body.append(input, size);
     30 }
     31 
     32 void StoreBodyAndHeadersVisitor::HandleHeaderError(BalsaFrame* framer) {
     33   HandleError();
     34 }
     35 
     36 void StoreBodyAndHeadersVisitor::HandleHeaderWarning(BalsaFrame* framer) {
     37   HandleError();
     38 }
     39 
     40 void StoreBodyAndHeadersVisitor::HandleChunkingError(BalsaFrame* framer) {
     41   HandleError();
     42 }
     43 
     44 void StoreBodyAndHeadersVisitor::HandleBodyError(BalsaFrame* framer) {
     45   HandleError();
     46 }
     47 
     48 FileData::FileData(BalsaHeaders* h, const std::string& b)
     49     : headers(h), body(b) {
     50 }
     51 
     52 FileData::FileData() {}
     53 
     54 FileData::~FileData() {}
     55 
     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 
     64 MemoryCache::MemoryCache() {}
     65 
     66 MemoryCache::~MemoryCache() {}
     67 
     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 
     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 
    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 
    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 
    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 
    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