OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "webkit/browser/appcache/appcache_url_request_job.h" | 5 #include "webkit/browser/appcache/appcache_url_request_job.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
12 #include "base/compiler_specific.h" | 12 #include "base/compiler_specific.h" |
13 #include "base/message_loop/message_loop.h" | 13 #include "base/message_loop/message_loop.h" |
14 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
| 15 #include "base/strings/utf_string_conversions.h" |
15 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
16 #include "net/base/io_buffer.h" | 17 #include "net/base/io_buffer.h" |
17 #include "net/base/net_errors.h" | 18 #include "net/base/net_errors.h" |
18 #include "net/base/net_log.h" | 19 #include "net/base/net_log.h" |
19 #include "net/http/http_request_headers.h" | 20 #include "net/http/http_request_headers.h" |
20 #include "net/http/http_response_headers.h" | 21 #include "net/http/http_response_headers.h" |
21 #include "net/http/http_util.h" | 22 #include "net/http/http_util.h" |
22 #include "net/url_request/url_request.h" | 23 #include "net/url_request/url_request.h" |
23 #include "net/url_request/url_request_status.h" | 24 #include "net/url_request/url_request_status.h" |
24 #include "webkit/browser/appcache/appcache.h" | 25 #include "webkit/browser/appcache/appcache.h" |
25 #include "webkit/browser/appcache/appcache_group.h" | 26 #include "webkit/browser/appcache/appcache_group.h" |
26 #include "webkit/browser/appcache/appcache_histograms.h" | 27 #include "webkit/browser/appcache/appcache_histograms.h" |
27 #include "webkit/browser/appcache/appcache_host.h" | 28 #include "webkit/browser/appcache/appcache_host.h" |
28 #include "webkit/browser/appcache/appcache_service.h" | 29 #include "webkit/browser/appcache/appcache_service.h" |
| 30 #include "webkit/browser/blob/blob_reader.h" |
| 31 #include "webkit/browser/blob/blob_storage_controller.h" |
29 | 32 |
30 namespace appcache { | 33 namespace appcache { |
31 | 34 |
| 35 namespace { |
| 36 |
| 37 // Helper to make structs for synthesized responses |
| 38 net::HttpResponseInfo* MakeHttpResponseInfo(const std::string& raw_headers) { |
| 39 net::HttpResponseInfo* info = new net::HttpResponseInfo; |
| 40 info->request_time = base::Time::Now(); |
| 41 info->response_time = base::Time::Now(); |
| 42 info->was_cached = false; |
| 43 info->headers = new net::HttpResponseHeaders(raw_headers); |
| 44 std::string headers; |
| 45 info->headers->GetNormalizedHeaders(&headers); |
| 46 return info; |
| 47 } |
| 48 |
| 49 } |
| 50 |
32 AppCacheURLRequestJob::AppCacheURLRequestJob( | 51 AppCacheURLRequestJob::AppCacheURLRequestJob( |
33 net::URLRequest* request, | 52 net::URLRequest* request, |
34 net::NetworkDelegate* network_delegate, | 53 net::NetworkDelegate* network_delegate, |
35 AppCacheStorage* storage, | 54 AppCacheStorage* storage, |
36 AppCacheHost* host) | 55 AppCacheHost* host) |
37 : net::URLRequestJob(request, network_delegate), | 56 : net::URLRequestJob(request, network_delegate), |
38 host_(host), | 57 host_(host), |
39 storage_(storage), | 58 storage_(storage), |
40 has_been_started_(false), has_been_killed_(false), | 59 has_been_started_(false), has_been_killed_(false), |
41 delivery_type_(AWAITING_DELIVERY_ORDERS), | 60 delivery_type_(AWAITING_DELIVERY_ORDERS), |
42 group_id_(0), cache_id_(kNoCacheId), is_fallback_(false), | 61 group_id_(0), cache_id_(kNoCacheId), is_fallback_(false), |
43 cache_entry_not_found_(false), | 62 cache_entry_not_found_(false), |
44 weak_factory_(this) { | 63 weak_factory_(this), |
| 64 is_main_resource_load_(false) { |
45 DCHECK(storage_); | 65 DCHECK(storage_); |
46 } | 66 } |
47 | 67 |
48 void AppCacheURLRequestJob::DeliverAppCachedResponse( | 68 void AppCacheURLRequestJob::DeliverAppCachedResponse( |
49 const GURL& manifest_url, int64 group_id, int64 cache_id, | 69 const GURL& manifest_url, int64 group_id, int64 cache_id, |
50 const AppCacheEntry& entry, bool is_fallback) { | 70 const AppCacheEntry& entry, bool is_fallback) { |
51 DCHECK(!has_delivery_orders()); | 71 DCHECK(!has_delivery_orders()); |
52 DCHECK(entry.has_response_id()); | 72 DCHECK(entry.has_response_id()); |
53 delivery_type_ = APPCACHED_DELIVERY; | 73 delivery_type_ = APPCACHED_DELIVERY; |
54 manifest_url_ = manifest_url; | 74 manifest_url_ = manifest_url; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
118 AppCacheHistograms::AddAppCacheJobStartDelaySample( | 138 AppCacheHistograms::AddAppCacheJobStartDelaySample( |
119 base::TimeTicks::Now() - start_time_tick_); | 139 base::TimeTicks::Now() - start_time_tick_); |
120 request()->net_log().AddEvent( | 140 request()->net_log().AddEvent( |
121 is_fallback_ ? | 141 is_fallback_ ? |
122 net::NetLog::TYPE_APPCACHE_DELIVERING_FALLBACK_RESPONSE : | 142 net::NetLog::TYPE_APPCACHE_DELIVERING_FALLBACK_RESPONSE : |
123 net::NetLog::TYPE_APPCACHE_DELIVERING_CACHED_RESPONSE); | 143 net::NetLog::TYPE_APPCACHE_DELIVERING_CACHED_RESPONSE); |
124 storage_->LoadResponseInfo( | 144 storage_->LoadResponseInfo( |
125 manifest_url_, group_id_, entry_.response_id(), this); | 145 manifest_url_, group_id_, entry_.response_id(), this); |
126 break; | 146 break; |
127 | 147 |
| 148 case SYNTHESIZED_DELIVERY: |
| 149 DCHECK(info_); |
| 150 NotifyHeadersComplete(); |
| 151 break; |
| 152 |
128 default: | 153 default: |
129 NOTREACHED(); | 154 NOTREACHED(); |
130 break; | 155 break; |
131 } | 156 } |
132 } | 157 } |
133 | 158 |
134 void AppCacheURLRequestJob::BeginExecutableHandlerDelivery() { | 159 void AppCacheURLRequestJob::BeginExecutableHandlerDelivery() { |
135 DCHECK(CommandLine::ForCurrentProcess()-> | 160 DCHECK(CommandLine::ForCurrentProcess()-> |
136 HasSwitch(kEnableExecutableHandlers)); | 161 HasSwitch(kEnableExecutableHandlers)); |
137 if (!storage_->service()->handler_factory()) { | 162 if (!storage_->service()->executable_handler_factory()) { |
138 BeginErrorDelivery("missing handler factory"); | 163 BeginErrorDelivery("missing handler factory"); |
139 return; | 164 return; |
140 } | 165 } |
141 | 166 |
| 167 if (is_range_request()) { |
| 168 BeginErrorDelivery("sorry, no support for range requests yet"); |
| 169 return; |
| 170 } |
| 171 |
142 request()->net_log().AddEvent( | 172 request()->net_log().AddEvent( |
143 net::NetLog::TYPE_APPCACHE_DELIVERING_EXECUTABLE_RESPONSE); | 173 net::NetLog::TYPE_APPCACHE_DELIVERING_EXECUTABLE_RESPONSE); |
144 | 174 |
145 // We defer job delivery until the executable handler is spun up and | 175 // We defer job delivery until the executable handler is spun up and |
146 // provides a response. The sequence goes like this... | 176 // provides a response. The sequence goes like this... |
147 // | 177 // |
148 // 1. First we load the cache. | 178 // 1. First we load the cache. |
149 // 2. Then if the handler is not spun up, we load the script resource which | 179 // 2. Then if the handler is not spun up, we load the script resource which |
150 // is needed to spin it up. | 180 // is needed to spin it up. |
151 // 3. Then we ask then we ask the handler to compute a response. | 181 // 3. Then we ask then we ask the handler to compute a response. |
152 // 4. Finally we deilver that response to the caller. | 182 // 4. Finally we deilver that response to the caller. |
153 storage_->LoadCache(cache_id_, this); | 183 storage_->LoadCache(cache_id_, this); |
154 } | 184 } |
155 | 185 |
156 void AppCacheURLRequestJob::OnCacheLoaded(AppCache* cache, int64 cache_id) { | 186 void AppCacheURLRequestJob::OnCacheLoaded(AppCache* cache, int64 cache_id) { |
157 DCHECK_EQ(cache_id_, cache_id); | 187 DCHECK_EQ(cache_id_, cache_id); |
158 DCHECK(!has_been_killed()); | 188 DCHECK(!has_been_killed()); |
159 | 189 |
160 if (!cache) { | 190 if (!cache) { |
161 BeginErrorDelivery("cache load failed"); | 191 BeginErrorDelivery("cache load failed"); |
162 return; | 192 return; |
163 } | 193 } |
164 | 194 |
165 // Keep references to ensure they don't go out of scope until job completion. | 195 // Keep references to ensure they don't go out of scope until job completion. |
166 cache_ = cache; | 196 cache_ = cache; |
167 group_ = cache->owning_group(); | 197 group_ = cache->owning_group(); |
168 | 198 |
| 199 // Detect odd ball cases where we want to return the resource instead of |
| 200 // executing the script. If it's an exact match for the resource, just return
it. |
| 201 if (cache_->GetEntry(request()->url())) { |
| 202 entry_.clear_types(AppCacheEntry::EXECUTABLE); |
| 203 delivery_type_ = APPCACHED_DELIVERY; |
| 204 BeginDelivery(); |
| 205 return; |
| 206 } |
169 // If the handler is spun up, ask it to compute a response. | 207 // If the handler is spun up, ask it to compute a response. |
170 AppCacheExecutableHandler* handler = | 208 AppCacheExecutableHandler* handler = |
171 cache->GetExecutableHandler(entry_.response_id()); | 209 cache->GetExecutableHandler(entry_.response_id()); |
172 if (handler) { | 210 if (handler) { |
173 InvokeExecutableHandler(handler); | 211 InvokeExecutableHandler(handler); |
174 return; | 212 return; |
175 } | 213 } |
176 | 214 |
177 // Handler is not spun up yet, load the script resource to do that. | 215 // Handler is not spun up yet, load the script resource to do that. |
178 // NOTE: This is not ideal since multiple jobs may be doing this, | 216 // NOTE: This is not ideal since multiple jobs may be doing this, |
(...skipping 16 matching lines...) Expand all Loading... |
195 } | 233 } |
196 | 234 |
197 void AppCacheURLRequestJob::OnExecutableSourceLoaded(int result) { | 235 void AppCacheURLRequestJob::OnExecutableSourceLoaded(int result) { |
198 DCHECK(!has_been_killed()); | 236 DCHECK(!has_been_killed()); |
199 handler_source_reader_.reset(); | 237 handler_source_reader_.reset(); |
200 if (result < 0) { | 238 if (result < 0) { |
201 BeginErrorDelivery("script source load failed"); | 239 BeginErrorDelivery("script source load failed"); |
202 return; | 240 return; |
203 } | 241 } |
204 | 242 |
205 handler_source_buffer_->SetCapacity(result); // Free up some memory. | 243 std::string raw_handler_source(handler_source_buffer_->data(), result); |
| 244 handler_source_buffer_ = NULL; // Free up some memory. |
206 | 245 |
207 AppCacheExecutableHandler* handler = cache_->GetOrCreateExecutableHandler( | 246 AppCacheExecutableHandler* handler = cache_->GetOrCreateExecutableHandler( |
208 entry_.response_id(), handler_source_buffer_.get()); | 247 entry_.response_id(), raw_handler_source); |
209 handler_source_buffer_ = NULL; // not needed anymore | |
210 if (handler) { | 248 if (handler) { |
211 InvokeExecutableHandler(handler); | 249 InvokeExecutableHandler(handler); |
212 return; | 250 return; |
213 } | 251 } |
214 | 252 |
215 BeginErrorDelivery("factory failed to produce a handler"); | 253 BeginErrorDelivery("factory failed to produce a handler"); |
216 } | 254 } |
217 | 255 |
218 void AppCacheURLRequestJob::InvokeExecutableHandler( | 256 void AppCacheURLRequestJob::InvokeExecutableHandler( |
219 AppCacheExecutableHandler* handler) { | 257 AppCacheExecutableHandler* handler) { |
| 258 net::URLRequest* req = request(); |
| 259 |
| 260 AppCacheExecutableHandler::Request request; |
| 261 request.url = req->url(); |
| 262 request.is_main_resource_load = is_main_resource_load_; |
| 263 request.method = req->method(); |
| 264 request.referrer = req->referrer(); |
| 265 net::HttpRequestHeaders headers; |
| 266 req->GetFullRequestHeaders(&headers); |
| 267 net::HttpRequestHeaders::Iterator iter(headers); |
| 268 while (iter.GetNext()) |
| 269 request.headers.insert(make_pair(iter.name(), iter.value())); |
| 270 |
220 handler->HandleRequest( | 271 handler->HandleRequest( |
221 request(), | 272 request, |
222 base::Bind(&AppCacheURLRequestJob::OnExecutableResponseCallback, | 273 base::Bind(&AppCacheURLRequestJob::OnExecutableResponseCallback, |
223 weak_factory_.GetWeakPtr())); | 274 weak_factory_.GetWeakPtr())); |
224 } | 275 } |
225 | 276 |
226 void AppCacheURLRequestJob::OnExecutableResponseCallback( | 277 void AppCacheURLRequestJob::OnExecutableResponseCallback( |
227 const AppCacheExecutableHandler::Response& response) { | 278 const AppCacheExecutableHandler::Response& response) { |
228 DCHECK(!has_been_killed()); | 279 DCHECK(!has_been_killed()); |
229 if (response.use_network) { | 280 |
| 281 // Support for .respondWithNetwork(id) |
| 282 if (response.use_default) { |
230 delivery_type_ = NETWORK_DELIVERY; | 283 delivery_type_ = NETWORK_DELIVERY; |
231 storage_ = NULL; | 284 storage_ = NULL; |
232 BeginDelivery(); | 285 BeginDelivery(); |
233 return; | 286 return; |
234 } | 287 } |
235 | 288 |
236 if (!response.cached_resource_url.is_empty()) { | 289 // Support for .respondWith(blob) and .redirectTo(locataion); |
237 AppCacheEntry* entry_ptr = cache_->GetEntry(response.cached_resource_url); | 290 if (response.status_code) { |
238 if (entry_ptr && !entry_ptr->IsExecutable()) { | 291 // TODO(michaeln): synthesize a response with the response_code and |
239 entry_ = *entry_ptr; | 292 // the blob as the body. |
240 BeginDelivery(); | 293 webkit_blob::BlobStorageController* blob_storage = |
241 return; | 294 storage_->service()->executable_handler_factory()->GetBlobStorageControl
ler(); |
| 295 fileapi::FileSystemContext* filesystem_context = |
| 296 storage_->service()->executable_handler_factory()->GetFileSystemContext(
); |
| 297 |
| 298 scoped_refptr<webkit_blob::BlobData> blob_data; |
| 299 if (!response.blob_id.empty()) |
| 300 blob_data = blob_storage->GetBlobDataFromUrl(GURL(response.blob_id)); |
| 301 |
| 302 std::string raw_headers = base::StringPrintf( |
| 303 "HTTP/1.0 %d %S", response.status_code, UTF16ToWide(response.status_text
).data()); |
| 304 raw_headers.append(1, '\0'); |
| 305 |
| 306 // TODO(alecflett): content_type is totally messy because blob has |
| 307 // a content type, as does the response body itself. Further, the |
| 308 // response header may have additional information on it like |
| 309 // 'text/html; charset=utf-8' - this code drastically simplifies |
| 310 // by simply using the blob if they don't match. |
| 311 string16 content_type; |
| 312 for (std::map<string16, string16>::const_iterator iter = response.headers.be
gin(); |
| 313 iter != response.headers.end(); |
| 314 ++iter) { |
| 315 if (LowerCaseEqualsASCII(iter->first, "content-type")) |
| 316 content_type = iter->second; |
| 317 else { |
| 318 raw_headers.append(base::StringPrintf("%s: %s", UTF16ToUTF8(iter->first)
.data(), UTF16ToUTF8(iter->second).data())); |
| 319 raw_headers.append(1, '\0'); |
| 320 } |
242 } | 321 } |
243 } | 322 if (blob_data) { |
| 323 if (content_type.empty()) |
| 324 content_type = UTF8ToUTF16(blob_data->content_type()); |
| 325 if (!EqualsASCII(content_type, blob_data->content_type())) |
| 326 LOG(WARNING) << "Blob and header content types don't match, using " << |
| 327 content_type << ". (blob is " << blob_data->content_type() << " but
header is " << content_type << ")"; |
| 328 raw_headers.append(base::StringPrintf( |
| 329 "Content-Type: %s", UTF16ToUTF8(content_type).data())); |
244 | 330 |
245 if (!response.redirect_url.is_empty()) { | 331 raw_headers.append(1, '\0'); |
246 // TODO(michaeln): playback a redirect | 332 // TODO: content-length header too |
247 // response_headers_(new HttpResponseHeaders(response_headers)), | 333 blob_reader_.reset(new webkit_blob::BlobReader( |
248 // fallthru for now to deliver an error | 334 blob_data.get(), filesystem_context)); |
| 335 } |
| 336 raw_headers.append(2, '\0'); |
| 337 info_ = new AppCacheResponseInfo( |
| 338 manifest_url_, MakeHttpResponseInfo(raw_headers), 0); |
| 339 BeginSynthesizedDelivery(); |
| 340 return; |
249 } | 341 } |
250 | 342 |
251 // Otherwise, return an error. | 343 // Otherwise, return an error. |
252 BeginErrorDelivery("handler returned an invalid response"); | 344 BeginErrorDelivery("handler returned an invalid response"); |
253 } | 345 } |
254 | 346 |
255 void AppCacheURLRequestJob::BeginErrorDelivery(const char* message) { | 347 void AppCacheURLRequestJob::BeginErrorDelivery(const char* message) { |
256 if (host_) | 348 if (host_) |
257 host_->frontend()->OnLogMessage(host_->host_id(), LOG_ERROR, message); | 349 host_->frontend()->OnLogMessage(host_->host_id(), LOG_ERROR, message); |
258 delivery_type_ = ERROR_DELIVERY; | 350 delivery_type_ = ERROR_DELIVERY; |
259 storage_ = NULL; | 351 storage_ = NULL; |
260 BeginDelivery(); | 352 BeginDelivery(); |
261 } | 353 } |
262 | 354 |
| 355 void AppCacheURLRequestJob::BeginSynthesizedDelivery() { |
| 356 delivery_type_ = SYNTHESIZED_DELIVERY; |
| 357 storage_ = NULL; |
| 358 BeginDelivery(); |
| 359 } |
| 360 |
263 AppCacheURLRequestJob::~AppCacheURLRequestJob() { | 361 AppCacheURLRequestJob::~AppCacheURLRequestJob() { |
264 if (storage_) | 362 if (storage_) |
265 storage_->CancelDelegateCallbacks(this); | 363 storage_->CancelDelegateCallbacks(this); |
266 } | 364 } |
267 | 365 |
268 void AppCacheURLRequestJob::OnResponseInfoLoaded( | 366 void AppCacheURLRequestJob::OnResponseInfoLoaded( |
269 AppCacheResponseInfo* response_info, int64 response_id) { | 367 AppCacheResponseInfo* response_info, int64 response_id) { |
270 DCHECK(is_delivering_appcache_response()); | 368 DCHECK(is_delivering_appcache_response()); |
271 scoped_refptr<AppCacheURLRequestJob> protect(this); | 369 scoped_refptr<AppCacheURLRequestJob> protect(this); |
272 if (response_info) { | 370 if (response_info) { |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
374 net::URLRequestJob::Kill(); | 472 net::URLRequestJob::Kill(); |
375 weak_factory_.InvalidateWeakPtrs(); | 473 weak_factory_.InvalidateWeakPtrs(); |
376 } | 474 } |
377 } | 475 } |
378 | 476 |
379 net::LoadState AppCacheURLRequestJob::GetLoadState() const { | 477 net::LoadState AppCacheURLRequestJob::GetLoadState() const { |
380 if (!has_been_started()) | 478 if (!has_been_started()) |
381 return net::LOAD_STATE_IDLE; | 479 return net::LOAD_STATE_IDLE; |
382 if (!has_delivery_orders()) | 480 if (!has_delivery_orders()) |
383 return net::LOAD_STATE_WAITING_FOR_APPCACHE; | 481 return net::LOAD_STATE_WAITING_FOR_APPCACHE; |
384 if (delivery_type_ != APPCACHED_DELIVERY) | 482 if (delivery_type_ != APPCACHED_DELIVERY && |
| 483 delivery_type_ != SYNTHESIZED_DELIVERY) |
385 return net::LOAD_STATE_IDLE; | 484 return net::LOAD_STATE_IDLE; |
386 if (!info_.get()) | 485 if (!info_.get()) |
387 return net::LOAD_STATE_WAITING_FOR_APPCACHE; | 486 return net::LOAD_STATE_WAITING_FOR_APPCACHE; |
388 if (reader_.get() && reader_->IsReadPending()) | 487 if (reader_.get() && reader_->IsReadPending()) |
389 return net::LOAD_STATE_READING_RESPONSE; | 488 return net::LOAD_STATE_READING_RESPONSE; |
390 return net::LOAD_STATE_IDLE; | 489 return net::LOAD_STATE_IDLE; |
391 } | 490 } |
392 | 491 |
393 bool AppCacheURLRequestJob::GetMimeType(std::string* mime_type) const { | 492 bool AppCacheURLRequestJob::GetMimeType(std::string* mime_type) const { |
394 if (!http_info()) | 493 if (!http_info()) |
(...skipping 14 matching lines...) Expand all Loading... |
409 } | 508 } |
410 | 509 |
411 int AppCacheURLRequestJob::GetResponseCode() const { | 510 int AppCacheURLRequestJob::GetResponseCode() const { |
412 if (!http_info()) | 511 if (!http_info()) |
413 return -1; | 512 return -1; |
414 return http_info()->headers->response_code(); | 513 return http_info()->headers->response_code(); |
415 } | 514 } |
416 | 515 |
417 bool AppCacheURLRequestJob::ReadRawData(net::IOBuffer* buf, int buf_size, | 516 bool AppCacheURLRequestJob::ReadRawData(net::IOBuffer* buf, int buf_size, |
418 int *bytes_read) { | 517 int *bytes_read) { |
419 DCHECK(is_delivering_appcache_response()); | 518 DCHECK(is_delivering_appcache_response() || |
| 519 is_delivering_synthesized_response()); |
420 DCHECK_NE(buf_size, 0); | 520 DCHECK_NE(buf_size, 0); |
421 DCHECK(bytes_read); | 521 DCHECK(bytes_read); |
| 522 |
| 523 // Branch to return a 'blob' response provided by an exe handler. |
| 524 if (blob_reader_) |
| 525 return ReadRawBlobData(buf, buf_size, bytes_read); |
| 526 |
| 527 if (!reader_) { |
| 528 // No raw data to read, an empty response body. |
| 529 *bytes_read = 0; |
| 530 return true; |
| 531 } |
| 532 |
422 DCHECK(!reader_->IsReadPending()); | 533 DCHECK(!reader_->IsReadPending()); |
423 reader_->ReadData( | 534 reader_->ReadData( |
424 buf, buf_size, base::Bind(&AppCacheURLRequestJob::OnReadComplete, | 535 buf, buf_size, base::Bind(&AppCacheURLRequestJob::OnReadComplete, |
425 base::Unretained(this))); | 536 base::Unretained(this))); |
426 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); | 537 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); |
427 return false; | 538 return false; |
428 } | 539 } |
429 | 540 |
| 541 bool AppCacheURLRequestJob::ReadRawBlobData(net::IOBuffer* buf, int buf_size, |
| 542 int *bytes_read) { |
| 543 DCHECK(is_delivering_synthesized_response()); |
| 544 DCHECK_NE(buf_size, 0); |
| 545 DCHECK(bytes_read); |
| 546 |
| 547 int rv = blob_reader_->Read( |
| 548 buf, buf_size, base::Bind(&AppCacheURLRequestJob::OnReadBlobDataComplete, |
| 549 base::Unretained(this))); |
| 550 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); |
| 551 if (rv != net::ERR_IO_PENDING) { |
| 552 base::MessageLoop::current()->PostTask( |
| 553 FROM_HERE, base::Bind(&AppCacheURLRequestJob::OnReadBlobDataComplete, |
| 554 weak_factory_.GetWeakPtr(), rv)); |
| 555 } |
| 556 return false; |
| 557 } |
| 558 |
| 559 void AppCacheURLRequestJob::OnReadBlobDataComplete(int result) { |
| 560 DCHECK(is_delivering_synthesized_response()); |
| 561 if (result == 0) |
| 562 NotifyDone(net::URLRequestStatus()); |
| 563 else if (result < 0) |
| 564 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); |
| 565 else |
| 566 SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status |
| 567 NotifyReadComplete(result); |
| 568 } |
| 569 |
| 570 |
430 void AppCacheURLRequestJob::SetExtraRequestHeaders( | 571 void AppCacheURLRequestJob::SetExtraRequestHeaders( |
431 const net::HttpRequestHeaders& headers) { | 572 const net::HttpRequestHeaders& headers) { |
432 std::string value; | 573 std::string value; |
433 std::vector<net::HttpByteRange> ranges; | 574 std::vector<net::HttpByteRange> ranges; |
434 if (!headers.GetHeader(net::HttpRequestHeaders::kRange, &value) || | 575 if (!headers.GetHeader(net::HttpRequestHeaders::kRange, &value) || |
435 !net::HttpUtil::ParseRangeHeader(value, &ranges)) { | 576 !net::HttpUtil::ParseRangeHeader(value, &ranges)) { |
436 return; | 577 return; |
437 } | 578 } |
438 | 579 |
439 // If multiple ranges are requested, we play dumb and | 580 // If multiple ranges are requested, we play dumb and |
440 // return the entire response with 200 OK. | 581 // return the entire response with 200 OK. |
441 if (ranges.size() == 1U) | 582 if (ranges.size() == 1U) |
442 range_requested_ = ranges[0]; | 583 range_requested_ = ranges[0]; |
443 } | 584 } |
444 | 585 |
445 } // namespace appcache | 586 } // namespace appcache |
OLD | NEW |