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