1 // Copyright (c) 2012 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/dump_cache/simple_cache_dumper.h"
6
7 #include "base/at_exit.h"
8 #include "base/command_line.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/message_loop/message_loop_proxy.h"
13 #include "base/threading/thread.h"
14 #include "net/base/cache_type.h"
15 #include "net/base/io_buffer.h"
16 #include "net/base/net_errors.h"
17 #include "net/disk_cache/disk_cache.h"
18 #include "net/tools/dump_cache/cache_dumper.h"
19
20 namespace net {
21
SimpleCacheDumper(base::FilePath input_path,base::FilePath output_path)22 SimpleCacheDumper::SimpleCacheDumper(base::FilePath input_path,
23 base::FilePath output_path)
24 : state_(STATE_NONE),
25 input_path_(input_path),
26 output_path_(output_path),
27 writer_(new DiskDumper(output_path)),
28 cache_thread_(new base::Thread("CacheThead")),
29 iter_(NULL),
30 src_entry_(NULL),
31 dst_entry_(NULL),
32 io_callback_(base::Bind(&SimpleCacheDumper::OnIOComplete,
33 base::Unretained(this))),
34 rv_(0) {
35 }
36
~SimpleCacheDumper()37 SimpleCacheDumper::~SimpleCacheDumper() {
38 }
39
Run()40 int SimpleCacheDumper::Run() {
41 base::MessageLoopForIO main_message_loop;
42
43 LOG(INFO) << "Reading cache from: " << input_path_.value();
44 LOG(INFO) << "Writing cache to: " << output_path_.value();
45
46 if (!cache_thread_->StartWithOptions(
47 base::Thread::Options(base::MessageLoop::TYPE_IO, 0))) {
48 LOG(ERROR) << "Unable to start thread";
49 return ERR_UNEXPECTED;
50 }
51 state_ = STATE_CREATE_CACHE;
52 int rv = DoLoop(OK);
53 if (rv == ERR_IO_PENDING) {
54 main_message_loop.Run();
55 return rv_;
56 }
57 return rv;
58 }
59
DoLoop(int rv)60 int SimpleCacheDumper::DoLoop(int rv) {
61 do {
62 State state = state_;
63 state_ = STATE_NONE;
64 switch (state) {
65 case STATE_CREATE_CACHE:
66 CHECK_EQ(OK, rv);
67 rv = DoCreateCache();
68 break;
69 case STATE_CREATE_CACHE_COMPLETE:
70 rv = DoCreateCacheComplete(rv);
71 break;
72 case STATE_OPEN_ENTRY:
73 CHECK_EQ(OK, rv);
74 rv = DoOpenEntry();
75 break;
76 case STATE_OPEN_ENTRY_COMPLETE:
77 rv = DoOpenEntryComplete(rv);
78 break;
79 case STATE_CREATE_ENTRY:
80 CHECK_EQ(OK, rv);
81 rv = DoCreateEntry();
82 break;
83 case STATE_CREATE_ENTRY_COMPLETE:
84 rv = DoCreateEntryComplete(rv);
85 break;
86 case STATE_READ_HEADERS:
87 CHECK_EQ(OK, rv);
88 rv = DoReadHeaders();
89 break;
90 case STATE_READ_HEADERS_COMPLETE:
91 rv = DoReadHeadersComplete(rv);
92 break;
93 case STATE_WRITE_HEADERS:
94 CHECK_EQ(OK, rv);
95 rv = DoWriteHeaders();
96 break;
97 case STATE_WRITE_HEADERS_COMPLETE:
98 rv = DoWriteHeadersComplete(rv);
99 break;
100 case STATE_READ_BODY:
101 CHECK_EQ(OK, rv);
102 rv = DoReadBody();
103 break;
104 case STATE_READ_BODY_COMPLETE:
105 rv = DoReadBodyComplete(rv);
106 break;
107 case STATE_WRITE_BODY:
108 CHECK_EQ(OK, rv);
109 rv = DoWriteBody();
110 break;
111 case STATE_WRITE_BODY_COMPLETE:
112 rv = DoWriteBodyComplete(rv);
113 break;
114 default:
115 NOTREACHED() << "state_: " << state_;
116 break;
117 }
118 } while (state_ != STATE_NONE && rv != ERR_IO_PENDING);
119 return rv;
120 }
121
DoCreateCache()122 int SimpleCacheDumper::DoCreateCache() {
123 DCHECK(!cache_);
124 state_ = STATE_CREATE_CACHE_COMPLETE;
125 return disk_cache::CreateCacheBackend(
126 DISK_CACHE,
127 CACHE_BACKEND_DEFAULT,
128 input_path_,
129 0,
130 false,
131 cache_thread_->message_loop_proxy().get(),
132 NULL,
133 &cache_,
134 io_callback_);
135 }
136
DoCreateCacheComplete(int rv)137 int SimpleCacheDumper::DoCreateCacheComplete(int rv) {
138 if (rv < 0)
139 return rv;
140
141 reinterpret_cast<disk_cache::BackendImpl*>(cache_.get())->SetUpgradeMode();
142 reinterpret_cast<disk_cache::BackendImpl*>(cache_.get())->SetFlags(
143 disk_cache::kNoRandom);
144
145 state_ = STATE_OPEN_ENTRY;
146 return OK;
147 }
148
DoOpenEntry()149 int SimpleCacheDumper::DoOpenEntry() {
150 DCHECK(!dst_entry_);
151 DCHECK(!src_entry_);
152 state_ = STATE_OPEN_ENTRY_COMPLETE;
153 return cache_->OpenNextEntry(&iter_, &src_entry_, io_callback_);
154 }
155
DoOpenEntryComplete(int rv)156 int SimpleCacheDumper::DoOpenEntryComplete(int rv) {
157 // ERR_FAILED indicates iteration finished.
158 if (rv == ERR_FAILED) {
159 cache_->EndEnumeration(&iter_);
160 return OK;
161 }
162
163 if (rv < 0)
164 return rv;
165
166 state_ = STATE_CREATE_ENTRY;
167 return OK;
168 }
169
DoCreateEntry()170 int SimpleCacheDumper::DoCreateEntry() {
171 DCHECK(!dst_entry_);
172 state_ = STATE_CREATE_ENTRY_COMPLETE;
173
174 return writer_->CreateEntry(src_entry_->GetKey(), &dst_entry_,
175 io_callback_);
176 }
177
DoCreateEntryComplete(int rv)178 int SimpleCacheDumper::DoCreateEntryComplete(int rv) {
179 if (rv < 0)
180 return rv;
181
182 state_ = STATE_READ_HEADERS;
183 return OK;
184 }
185
DoReadHeaders()186 int SimpleCacheDumper::DoReadHeaders() {
187 state_ = STATE_READ_HEADERS_COMPLETE;
188 int32 size = src_entry_->GetDataSize(0);
189 buf_ = new IOBufferWithSize(size);
190 return src_entry_->ReadData(0, 0, buf_.get(), size, io_callback_);
191 }
192
DoReadHeadersComplete(int rv)193 int SimpleCacheDumper::DoReadHeadersComplete(int rv) {
194 if (rv < 0)
195 return rv;
196
197 state_ = STATE_WRITE_HEADERS;
198 return OK;
199 }
200
DoWriteHeaders()201 int SimpleCacheDumper::DoWriteHeaders() {
202 int rv = writer_->WriteEntry(
203 dst_entry_, 0, 0, buf_.get(), buf_->size(), io_callback_);
204 if (rv == 0)
205 return ERR_FAILED;
206
207 state_ = STATE_WRITE_HEADERS_COMPLETE;
208 return OK;
209 }
210
DoWriteHeadersComplete(int rv)211 int SimpleCacheDumper::DoWriteHeadersComplete(int rv) {
212 if (rv < 0)
213 return rv;
214
215 state_ = STATE_READ_BODY;
216 return OK;
217 }
218
DoReadBody()219 int SimpleCacheDumper::DoReadBody() {
220 state_ = STATE_READ_BODY_COMPLETE;
221 int32 size = src_entry_->GetDataSize(1);
222 // If the body is empty, we can neither read nor write it, so
223 // just move to the next.
224 if (size <= 0) {
225 state_ = STATE_WRITE_BODY_COMPLETE;
226 return OK;
227 }
228 buf_ = new IOBufferWithSize(size);
229 return src_entry_->ReadData(1, 0, buf_.get(), size, io_callback_);
230 }
231
DoReadBodyComplete(int rv)232 int SimpleCacheDumper::DoReadBodyComplete(int rv) {
233 if (rv < 0)
234 return rv;
235
236 state_ = STATE_WRITE_BODY;
237 return OK;
238 }
239
DoWriteBody()240 int SimpleCacheDumper::DoWriteBody() {
241 int rv = writer_->WriteEntry(
242 dst_entry_, 1, 0, buf_.get(), buf_->size(), io_callback_);
243 if (rv == 0)
244 return ERR_FAILED;
245
246 state_ = STATE_WRITE_BODY_COMPLETE;
247 return OK;
248 }
249
DoWriteBodyComplete(int rv)250 int SimpleCacheDumper::DoWriteBodyComplete(int rv) {
251 if (rv < 0)
252 return rv;
253
254 src_entry_->Close();
255 writer_->CloseEntry(dst_entry_, base::Time::Now(), base::Time::Now());
256 src_entry_ = NULL;
257 dst_entry_ = NULL;
258
259 state_ = STATE_OPEN_ENTRY;
260 return OK;
261 }
262
OnIOComplete(int rv)263 void SimpleCacheDumper::OnIOComplete(int rv) {
264 rv = DoLoop(rv);
265
266 if (rv != ERR_IO_PENDING) {
267 rv_ = rv;
268 cache_.reset();
269 base::MessageLoop::current()->Quit();
270 }
271 }
272
273 } // namespace net
274