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"
12 #include <sys/types.h>
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"
26 // The directory where cache locates);
27 const char FLAGS_cache_base_dir
[] = ".";
32 void StoreBodyAndHeadersVisitor::ProcessBodyData(const char* input
,
34 body
.append(input
, size
);
37 void StoreBodyAndHeadersVisitor::HandleHeaderError(BalsaFrame
* framer
) {
41 void StoreBodyAndHeadersVisitor::HandleHeaderWarning(BalsaFrame
* framer
) {
45 void StoreBodyAndHeadersVisitor::HandleChunkingError(BalsaFrame
* framer
) {
49 void StoreBodyAndHeadersVisitor::HandleBodyError(BalsaFrame
* framer
) {
53 FileData::FileData(const BalsaHeaders
* headers
,
54 const std::string
& filename
,
55 const std::string
& body
)
56 : filename_(filename
), body_(body
) {
58 headers_
.reset(new BalsaHeaders
);
59 headers_
->CopyFrom(*headers
);
63 FileData::FileData() {}
65 FileData::~FileData() {}
67 MemoryCache::MemoryCache() : cwd_(FLAGS_cache_base_dir
) {}
69 MemoryCache::~MemoryCache() { ClearFiles(); }
71 void MemoryCache::CloneFrom(const MemoryCache
& mc
) {
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());
89 if (current_dir
== NULL
) {
90 perror("Unable to open directory. ");
91 current_dir_name
.clear();
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
);
113 VLOG(1) << "Oops, no data left. Closing dir.";
114 closedir(current_dir
);
121 void MemoryCache::ReadToString(const char* filename
, std::string
* output
) {
123 int fd
= open(filename
, 0, "r");
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
));
131 read_status
= read(fd
, buffer
, sizeof(buffer
));
132 } while (read_status
<= 0 && errno
== EINTR
);
137 void MemoryCache::ReadAndStoreFileContents(const char* filename
) {
138 StoreBodyAndHeadersVisitor visitor
;
140 framer
.set_balsa_visitor(&visitor
);
141 framer
.set_balsa_headers(&(visitor
.headers
));
142 std::string filename_contents
;
143 ReadToString(filename
, &filename_contents
);
145 // Ugly hack to make everything look like 1.1.
146 if (filename_contents
.find("HTTP/1.0") == 0)
147 filename_contents
[7] = '1';
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!";
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
);
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");
179 // Experiment with changing headers for forcing use of cached
180 // versions of content.
181 // TODO(mbelshe) REMOVE ME
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");
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();
202 &visitor
.headers
, filename_stripped
.substr(0, slash_pos
), visitor
.body
);
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");
210 if (fi
== files_
.end())
211 fi
= files_
.find(filename
);
213 if (fi
== files_
.end()) {
219 bool MemoryCache::AssignFileData(const std::string
& filename
,
221 mci
->file_data
= GetFileData(filename
);
222 if (mci
->file_data
== NULL
) {
223 LOG(ERROR
) << "Could not find file data for " << filename
;
229 void MemoryCache::InsertFile(const BalsaHeaders
* headers
,
230 const std::string
& filename
,
231 const std::string
& body
) {
232 InsertFile(new FileData(headers
, filename
, body
));
235 void MemoryCache::InsertFile(FileData
* file_data
) {
236 Files::iterator it
= files_
.find(file_data
->filename());
237 if (it
!= files_
.end()) {
239 it
->second
= file_data
;
241 files_
.insert(std::make_pair(file_data
->filename(), file_data
));
245 void MemoryCache::ClearFiles() {
246 for (Files::const_iterator i
= files_
.begin(); i
!= files_
.end(); ++i
) {