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>
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
= ".";
28 void StoreBodyAndHeadersVisitor::ProcessBodyData(const char *input
,
30 body
.append(input
, size
);
33 void StoreBodyAndHeadersVisitor::HandleHeaderError(BalsaFrame
* framer
) {
37 void StoreBodyAndHeadersVisitor::HandleHeaderWarning(BalsaFrame
* framer
) {
41 void StoreBodyAndHeadersVisitor::HandleChunkingError(BalsaFrame
* framer
) {
45 void StoreBodyAndHeadersVisitor::HandleBodyError(BalsaFrame
* framer
) {
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();
73 Files::iterator out_i
=
74 files_
.insert(make_pair(i
->first
, FileData())).first
;
75 out_i
->second
.CopyFrom(i
->second
);
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());
92 if (current_dir
== NULL
) {
93 perror("Unable to open directory. ");
94 current_dir_name
.clear();
99 VLOG(1) << "Succeeded opening";
100 for (struct dirent
* dir_data
= readdir(current_dir
);
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
);
125 void MemoryCache::ReadToString(const char* filename
, std::string
* output
) {
127 int fd
= open(filename
, 0, "r");
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
));
135 read_status
= read(fd
, buffer
, sizeof(buffer
));
136 } while (read_status
<= 0 && errno
== EINTR
);
141 void MemoryCache::ReadAndStoreFileContents(const char* filename
) {
142 StoreBodyAndHeadersVisitor visitor
;
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';
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!";
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
);
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
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");
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()) {
220 return &(fi
->second
);
223 bool MemoryCache::AssignFileData(const std::string
& filename
,
225 mci
->file_data
= GetFileData(filename
);
226 if (mci
->file_data
== NULL
) {
227 LOG(ERROR
) << "Could not find file data for " << filename
;