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