Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(320)

Side by Side Diff: webkit/appcache/appcache_response.cc

Issue 269062: AppCacheResponse storage implementation (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(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 "webkit/appcache/appcache_response.h"
6
7 #include "base/logging.h"
8 #include "base/message_loop.h"
9 #include "base/pickle.h"
10 #include "base/string_util.h"
11 #include "net/base/net_errors.h"
12 #include "net/base/io_buffer.h"
13 #include "net/disk_cache/disk_cache.h"
14 #include "webkit/appcache/appcache_service.h"
15
16 using disk_cache::Entry;
17
18 namespace appcache {
19
20 namespace {
21
22 // Disk cache entry data indices.
23 enum {
24 kResponseInfoIndex,
25 kResponseContentIndex
26 };
27
28 // Disk cache entry keys.
29 std::string response_key(int64 response_id) {
30 return Int64ToString(response_id);
31 }
32
33 // An IOBuffer that wraps a pickle's data. Ownership of the
34 // pickle is transfered to the WrappedPickleIOBuffer object.
35 class WrappedPickleIOBuffer : public net::WrappedIOBuffer {
36 public:
37 explicit WrappedPickleIOBuffer(const Pickle* pickle) :
38 net::WrappedIOBuffer(reinterpret_cast<const char*>(pickle->data())),
39 pickle_(pickle) {
40 DCHECK(pickle->data());
41 }
42
43 private:
44 scoped_ptr<const Pickle> pickle_;
45 };
46
47 } // anon namespace
48
49
50 // AppCacheResponseInfo ----------------------------------------------
51
52 AppCacheResponseInfo::AppCacheResponseInfo(
53 AppCacheService* service, int64 response_id,
54 net::HttpResponseInfo* http_info)
55 : response_id_(response_id), http_response_info_(http_info),
56 service_(service) {
57 DCHECK(http_info);
58 DCHECK(response_id != kNoResponseId);
59 service_->storage()->working_set()->AddResponseInfo(this);
60 }
61
62 AppCacheResponseInfo::~AppCacheResponseInfo() {
63 service_->storage()->working_set()->RemoveResponseInfo(this);
64 }
65
66
67 // AppCacheResponseIO ----------------------------------------------
68
69 AppCacheResponseIO::AppCacheResponseIO(
70 int64 response_id, disk_cache::Backend* disk_cache)
71 : response_id_(response_id), disk_cache_(disk_cache),
72 entry_(NULL), user_callback_(NULL),
73 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
74 ALLOW_THIS_IN_INITIALIZER_LIST(raw_callback_(
75 new net::CancelableCompletionCallback<AppCacheResponseIO>(
76 this, &AppCacheResponseIO::OnRawIOComplete))) {
77 }
78
79 AppCacheResponseIO::~AppCacheResponseIO() {
80 raw_callback_->Cancel();
81 if (entry_)
82 entry_->Close();
83 }
84
85 void AppCacheResponseIO::ScheduleIOCompletionCallback(int result) {
86 MessageLoop::current()->PostTask(FROM_HERE,
87 method_factory_.NewRunnableMethod(
88 &AppCacheResponseIO::OnIOComplete, result));
89 }
90
91 void AppCacheResponseIO::InvokeUserCompletionCallback(int result) {
92 // Clear the user callback and buffers prior to invoking the callback
93 // so the caller can schedule additional operations in the callback.
94 buffer_ = NULL;
95 info_buffer_ = NULL;
96 net::CompletionCallback* temp_user_callback = user_callback_;
97 user_callback_ = NULL;
98 temp_user_callback->Run(result);
99 }
100
101 void AppCacheResponseIO::ReadRaw(int index, int offset,
102 net::IOBuffer* buf, int buf_len) {
103 DCHECK(entry_);
104 raw_callback_->AddRef(); // Balanced in OnRawIOComplete.
105 int rv = entry_->ReadData(index, offset, buf, buf_len, raw_callback_);
106 if (rv != net::ERR_IO_PENDING) {
107 raw_callback_->Release();
108 ScheduleIOCompletionCallback(rv);
109 }
110 }
111
112 void AppCacheResponseIO::WriteRaw(int index, int offset,
113 net::IOBuffer* buf, int buf_len) {
114 DCHECK(entry_);
115 const bool kTruncate = true;
116 raw_callback_->AddRef(); // Balanced in OnRawIOComplete.
117 int rv = entry_->WriteData(index, offset, buf, buf_len, raw_callback_,
118 kTruncate);
119 if (rv != net::ERR_IO_PENDING) {
120 raw_callback_->Release();
121 ScheduleIOCompletionCallback(rv);
122 }
123 }
124
125 void AppCacheResponseIO::OnRawIOComplete(int result) {
126 raw_callback_->Release(); // Balance the AddRefs
127 OnIOComplete(result);
128 }
129
130
131 // AppCacheResponseReader ----------------------------------------------
132
133 void AppCacheResponseReader::ReadInfo(HttpResponseInfoIOBuffer* info_buf,
134 net::CompletionCallback* callback) {
135 DCHECK(callback && !IsReadPending());
136 DCHECK(info_buf && !info_buf->http_info.get());
137 DCHECK(!buffer_.get() && !info_buffer_.get());
138
139 user_callback_ = callback; // cleared on completion
140
141 if (!OpenEntryIfNeeded()) {
142 ScheduleIOCompletionCallback(net::ERR_CACHE_MISS);
143 return;
144 }
145
146 int size = entry_->GetDataSize(kResponseInfoIndex);
147 info_buffer_ = info_buf;
148 buffer_ = new net::IOBuffer(size);
149 ReadRaw(kResponseInfoIndex, 0, buffer_.get(), size);
150 }
151
152 void AppCacheResponseReader::ReadData(net::IOBuffer* buf, int buf_len,
153 net::CompletionCallback* callback) {
154 DCHECK(callback && !IsReadPending());
155 DCHECK(buf && (buf_len >= 0));
156 DCHECK(!buffer_.get() && !info_buffer_.get());
157
158 user_callback_ = callback; // cleared on completion
159
160 if (!OpenEntryIfNeeded()) {
161 ScheduleIOCompletionCallback(net::ERR_CACHE_MISS);
162 return;
163 }
164
165 buffer_ = buf;
166 if (read_position_ + buf_len > range_length_) {
167 // TODO(michaeln): What about integer overflows?
168 DCHECK(range_length_ >= read_position_);
169 buf_len = range_length_ - read_position_;
170 }
171 ReadRaw(kResponseContentIndex, range_offset_ + read_position_,
172 buf, buf_len);
173 }
174
175 void AppCacheResponseReader::SetReadRange(int offset, int length) {
176 DCHECK(!IsReadPending() && !read_position_);
177 range_offset_ = offset;
178 range_length_ = length;
179 }
180
181 void AppCacheResponseReader::OnIOComplete(int result) {
182 if (result >= 0) {
183 if (info_buffer_.get()) {
184 // Allocate and deserialize the http info structure.
185 Pickle pickle(buffer_->data(), result);
186 bool response_truncated = false;
187 info_buffer_->http_info.reset(new net::HttpResponseInfo);
188 info_buffer_->http_info->InitFromPickle(pickle, &response_truncated);
189 DCHECK(!response_truncated);
190 } else {
191 read_position_ += result;
192 }
193 }
194 InvokeUserCompletionCallback(result);
195 }
196
197 bool AppCacheResponseReader::OpenEntryIfNeeded() {
198 if (!entry_)
199 disk_cache_->OpenEntry(response_key(response_id_), &entry_);
200 return entry_ ? true : false;
201 }
202
203
204 // AppCacheResponseWriter ----------------------------------------------
205
206 void AppCacheResponseWriter::WriteInfo(HttpResponseInfoIOBuffer* info_buf,
207 net::CompletionCallback* callback) {
208 DCHECK(callback && !IsWritePending());
209 DCHECK(info_buf && info_buf->http_info.get());
210 DCHECK(!buffer_.get() && !info_buffer_.get());
211
212 user_callback_ = callback; // cleared on completion
213
214 if (!CreateEntryIfNeeded()) {
215 ScheduleIOCompletionCallback(net::ERR_FAILED);
216 return;
217 }
218
219 const bool kSkipTransientHeaders = true;
220 const bool kTruncated = false;
221 Pickle* pickle = new Pickle;
222 info_buf->http_info->Persist(pickle, kSkipTransientHeaders, kTruncated);
223 write_amount_ = static_cast<int>(pickle->size());
224 buffer_ = new WrappedPickleIOBuffer(pickle); // takes ownership of pickle
225 WriteRaw(kResponseInfoIndex, 0, buffer_, write_amount_);
226 }
227
228 void AppCacheResponseWriter::WriteData(net::IOBuffer* buf, int buf_len,
229 net::CompletionCallback* callback) {
230 DCHECK(callback && !IsWritePending());
231 DCHECK(buf && (buf_len >= 0));
232 DCHECK(!buffer_.get() && !info_buffer_.get());
233
234 user_callback_ = callback; // cleared on completion
235
236 if (!CreateEntryIfNeeded()) {
237 ScheduleIOCompletionCallback(net::ERR_FAILED);
238 return;
239 }
240
241 buffer_ = buf;
242 write_amount_ = buf_len;
243 WriteRaw(kResponseContentIndex, write_position_, buf, buf_len);
244 }
245
246 void AppCacheResponseWriter::OnIOComplete(int result) {
247 if (result >= 0) {
248 DCHECK(write_amount_ == result);
249 if (!info_buffer_.get())
250 write_position_ += result;
251 }
252 InvokeUserCompletionCallback(result);
253 }
254
255 bool AppCacheResponseWriter::CreateEntryIfNeeded() {
256 if (!entry_)
257 disk_cache_->CreateEntry(response_key(response_id_), &entry_);
258 return entry_ ? true : false;
259 }
260
261 } // namespace appcache
262
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698