OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 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/glue/media/buffered_resource_loader.h" |
| 6 |
| 7 #include "base/format_macros.h" |
| 8 #include "base/string_util.h" |
| 9 #include "net/base/net_errors.h" |
| 10 #include "net/http/http_util.h" |
| 11 #include "third_party/WebKit/WebKit/chromium/public/WebKit.h" |
| 12 #include "third_party/WebKit/WebKit/chromium/public/WebKitClient.h" |
| 13 #include "third_party/WebKit/WebKit/chromium/public/WebString.h" |
| 14 #include "third_party/WebKit/WebKit/chromium/public/WebURLError.h" |
| 15 #include "webkit/glue/multipart_response_delegate.h" |
| 16 #include "webkit/glue/webkit_glue.h" |
| 17 |
| 18 using WebKit::WebFrame; |
| 19 using WebKit::WebString; |
| 20 using WebKit::WebURLError; |
| 21 using WebKit::WebURLLoader; |
| 22 using WebKit::WebURLRequest; |
| 23 using WebKit::WebURLResponse; |
| 24 using webkit_glue::MultipartResponseDelegate; |
| 25 |
| 26 namespace webkit_glue { |
| 27 |
| 28 BufferedResourceLoader::BufferedResourceLoader( |
| 29 const GURL& url, |
| 30 int64 first_byte_position, |
| 31 int64 last_byte_position) |
| 32 : buffer_(new media::SeekableBuffer(net::kBackwardCapcity, net::kForwardCapa
city)), |
| 33 deferred_(false), |
| 34 defer_allowed_(true), |
| 35 completed_(false), |
| 36 range_requested_(false), |
| 37 partial_response_(false), |
| 38 url_(url), |
| 39 first_byte_position_(first_byte_position), |
| 40 last_byte_position_(last_byte_position), |
| 41 start_callback_(NULL), |
| 42 offset_(0), |
| 43 content_length_(net::kPositionNotSpecified), |
| 44 instance_size_(net::kPositionNotSpecified), |
| 45 read_callback_(NULL), |
| 46 read_position_(0), |
| 47 read_size_(0), |
| 48 read_buffer_(NULL), |
| 49 first_offset_(0), |
| 50 last_offset_(0), |
| 51 keep_test_loader_(false) { |
| 52 } |
| 53 |
| 54 BufferedResourceLoader::~BufferedResourceLoader() { |
| 55 if (!completed_ && url_loader_.get()) |
| 56 url_loader_->cancel(); |
| 57 } |
| 58 |
| 59 void BufferedResourceLoader::Start(net::CompletionCallback* start_callback, |
| 60 NetworkEventCallback* event_callback, |
| 61 WebFrame* frame) { |
| 62 // Make sure we have not started. |
| 63 DCHECK(!start_callback_.get()); |
| 64 DCHECK(!event_callback_.get()); |
| 65 DCHECK(start_callback); |
| 66 DCHECK(event_callback); |
| 67 CHECK(frame); |
| 68 |
| 69 start_callback_.reset(start_callback); |
| 70 event_callback_.reset(event_callback); |
| 71 |
| 72 if (first_byte_position_ != net::kPositionNotSpecified) { |
| 73 range_requested_ = true; |
| 74 // TODO(hclam): server may not support range request so |offset_| may not |
| 75 // equal to |first_byte_position_|. |
| 76 offset_ = first_byte_position_; |
| 77 } |
| 78 |
| 79 // Increment the reference count right before we start the request. This |
| 80 // reference will be release when this request has ended. |
| 81 AddRef(); |
| 82 |
| 83 // Prepare the request. |
| 84 WebURLRequest request(url_); |
| 85 request.setHTTPHeaderField(WebString::fromUTF8("Range"), |
| 86 WebString::fromUTF8(GenerateHeaders( |
| 87 first_byte_position_, |
| 88 last_byte_position_))); |
| 89 frame->setReferrerForRequest(request, WebKit::WebURL()); |
| 90 |
| 91 // This flag is for unittests as we don't want to reset |url_loader| |
| 92 if (!keep_test_loader_) |
| 93 url_loader_.reset(frame->createAssociatedURLLoader()); |
| 94 |
| 95 // Start the resource loading. |
| 96 url_loader_->loadAsynchronously(request, this); |
| 97 } |
| 98 |
| 99 void BufferedResourceLoader::Stop() { |
| 100 // Reset callbacks. |
| 101 start_callback_.reset(); |
| 102 event_callback_.reset(); |
| 103 read_callback_.reset(); |
| 104 |
| 105 // Use the internal buffer to signal that we have been stopped. |
| 106 // TODO(hclam): Not so pretty to do this. |
| 107 if (!buffer_.get()) |
| 108 return; |
| 109 |
| 110 // Destroy internal buffer. |
| 111 buffer_.reset(); |
| 112 |
| 113 if (url_loader_.get()) { |
| 114 if (deferred_) |
| 115 url_loader_->setDefersLoading(false); |
| 116 deferred_ = false; |
| 117 |
| 118 if (!completed_) { |
| 119 url_loader_->cancel(); |
| 120 completed_ = true; |
| 121 } |
| 122 } |
| 123 } |
| 124 |
| 125 void BufferedResourceLoader::Read(int64 position, |
| 126 int read_size, |
| 127 uint8* buffer, |
| 128 net::CompletionCallback* read_callback) { |
| 129 DCHECK(!read_callback_.get()); |
| 130 DCHECK(buffer_.get()); |
| 131 DCHECK(read_callback); |
| 132 DCHECK(buffer); |
| 133 |
| 134 // Save the parameter of reading. |
| 135 read_callback_.reset(read_callback); |
| 136 read_position_ = position; |
| 137 read_size_ = read_size; |
| 138 read_buffer_ = buffer; |
| 139 |
| 140 // If read position is beyond the instance size, we cannot read there. |
| 141 if (instance_size_ != net::kPositionNotSpecified && |
| 142 instance_size_ <= read_position_) { |
| 143 DoneRead(0); |
| 144 return; |
| 145 } |
| 146 |
| 147 // Make sure |offset_| and |read_position_| does not differ by a large |
| 148 // amount. |
| 149 if (read_position_ > offset_ + kint32max || |
| 150 read_position_ < offset_ + kint32min) { |
| 151 DoneRead(net::ERR_CACHE_MISS); |
| 152 return; |
| 153 } |
| 154 |
| 155 // Prepare the parameters. |
| 156 first_offset_ = static_cast<int>(read_position_ - offset_); |
| 157 last_offset_ = first_offset_ + read_size_; |
| 158 |
| 159 // If we can serve the request now, do the actual read. |
| 160 if (CanFulfillRead()) { |
| 161 ReadInternal(); |
| 162 DisableDeferIfNeeded(); |
| 163 return; |
| 164 } |
| 165 |
| 166 // If we expected the read request to be fulfilled later, returns |
| 167 // immediately and let more data to flow in. |
| 168 if (WillFulfillRead()) |
| 169 return; |
| 170 |
| 171 // Make a callback to report failure. |
| 172 DoneRead(net::ERR_CACHE_MISS); |
| 173 } |
| 174 |
| 175 int64 BufferedResourceLoader::GetBufferedFirstBytePosition() { |
| 176 if (buffer_.get()) |
| 177 return offset_ - static_cast<int>(buffer_->backward_bytes()); |
| 178 return net::kPositionNotSpecified; |
| 179 } |
| 180 |
| 181 int64 BufferedResourceLoader::GetBufferedLastBytePosition() { |
| 182 if (buffer_.get()) |
| 183 return offset_ + static_cast<int>(buffer_->forward_bytes()) - 1; |
| 184 return net::kPositionNotSpecified; |
| 185 } |
| 186 |
| 187 void BufferedResourceLoader::SetAllowDefer(bool is_allowed) { |
| 188 defer_allowed_ = is_allowed; |
| 189 DisableDeferIfNeeded(); |
| 190 } |
| 191 |
| 192 void BufferedResourceLoader::SetURLLoaderForTest(WebURLLoader* mock_loader) { |
| 193 url_loader_.reset(mock_loader); |
| 194 keep_test_loader_ = true; |
| 195 } |
| 196 |
| 197 // WebKit::WebURLLoaderClient implementations. |
| 198 void BufferedResourceLoader::willSendRequest( |
| 199 WebURLLoader* loader, |
| 200 WebURLRequest& newRequest, |
| 201 const WebURLResponse& redirectResponse) { |
| 202 |
| 203 // The load may have been stopped and |start_callback| is destroyed. |
| 204 // In this case we shouldn't do anything. |
| 205 if (!start_callback_.get()) { |
| 206 // Set the url in the request to an invalid value (empty url). |
| 207 newRequest.setURL(WebKit::WebURL()); |
| 208 return; |
| 209 } |
| 210 |
| 211 if (!IsProtocolSupportedForMedia(newRequest.url())) { |
| 212 // Set the url in the request to an invalid value (empty url). |
| 213 newRequest.setURL(WebKit::WebURL()); |
| 214 DoneStart(net::ERR_ADDRESS_INVALID); |
| 215 Stop(); |
| 216 return; |
| 217 } |
| 218 |
| 219 url_ = newRequest.url(); |
| 220 } |
| 221 |
| 222 void BufferedResourceLoader::didSendData( |
| 223 WebURLLoader* loader, |
| 224 unsigned long long bytes_sent, |
| 225 unsigned long long total_bytes_to_be_sent) { |
| 226 NOTIMPLEMENTED(); |
| 227 } |
| 228 |
| 229 void BufferedResourceLoader::didReceiveResponse( |
| 230 WebURLLoader* loader, |
| 231 const WebURLResponse& response) { |
| 232 |
| 233 // The loader may have been stopped and |start_callback| is destroyed. |
| 234 // In this case we shouldn't do anything. |
| 235 if (!start_callback_.get()) |
| 236 return; |
| 237 |
| 238 // We make a strong assumption that when we reach here we have either |
| 239 // received a response from HTTP/HTTPS protocol or the request was |
| 240 // successful (in particular range request). So we only verify the partial |
| 241 // response for HTTP and HTTPS protocol. |
| 242 if (net::HttpUtil::IsHttpProtocol(url_)) { |
| 243 int error = net::OK; |
| 244 |
| 245 if (response.httpStatusCode() == net::kHttpPartialContent) |
| 246 partial_response_ = true; |
| 247 |
| 248 if (range_requested_ && partial_response_) { |
| 249 // If we have verified the partial response and it is correct, we will |
| 250 // return net::OK. |
| 251 if (!VerifyPartialResponse(response)) |
| 252 error = net::ERR_INVALID_RESPONSE; |
| 253 } else if (response.httpStatusCode() != net::kHttpOK) { |
| 254 // We didn't request a range but server didn't reply with "200 OK". |
| 255 error = net::ERR_FAILED; |
| 256 } |
| 257 |
| 258 if (error != net::OK) { |
| 259 DoneStart(error); |
| 260 Stop(); |
| 261 return; |
| 262 } |
| 263 } else { |
| 264 // For any protocol other than HTTP and HTTPS, assume range request is |
| 265 // always fulfilled. |
| 266 partial_response_ = range_requested_; |
| 267 } |
| 268 |
| 269 // Expected content length can be -1, in that case |content_length_| is |
| 270 // not specified and this is a streaming response. |
| 271 content_length_ = response.expectedContentLength(); |
| 272 |
| 273 // If we have not requested a range, then the size of the instance is equal |
| 274 // to the content length. |
| 275 if (!partial_response_) |
| 276 instance_size_ = content_length_; |
| 277 |
| 278 // Calls with a successful response. |
| 279 DoneStart(net::OK); |
| 280 } |
| 281 |
| 282 void BufferedResourceLoader::didReceiveData( |
| 283 WebURLLoader* loader, |
| 284 const char* data, |
| 285 int data_length) { |
| 286 DCHECK(!completed_); |
| 287 DCHECK_GT(data_length, 0); |
| 288 |
| 289 // If this loader has been stopped, |buffer_| would be destroyed. |
| 290 // In this case we shouldn't do anything. |
| 291 if (!buffer_.get()) |
| 292 return; |
| 293 |
| 294 // Writes more data to |buffer_|. |
| 295 buffer_->Append(reinterpret_cast<const uint8*>(data), data_length); |
| 296 |
| 297 // If there is an active read request, try to fulfill the request. |
| 298 if (HasPendingRead() && CanFulfillRead()) { |
| 299 ReadInternal(); |
| 300 } else if (!defer_allowed_) { |
| 301 // If we're not allowed to defer, slide the buffer window forward instead |
| 302 // of deferring. |
| 303 if (buffer_->forward_bytes() > buffer_->forward_capacity()) { |
| 304 size_t excess = buffer_->forward_bytes() - buffer_->forward_capacity(); |
| 305 bool success = buffer_->Seek(excess); |
| 306 DCHECK(success); |
| 307 offset_ += first_offset_ + excess; |
| 308 } |
| 309 } |
| 310 |
| 311 // At last see if the buffer is full and we need to defer the downloading. |
| 312 EnableDeferIfNeeded(); |
| 313 |
| 314 // Notify that we have received some data. |
| 315 NotifyNetworkEvent(); |
| 316 } |
| 317 |
| 318 void BufferedResourceLoader::didDownloadData( |
| 319 WebKit::WebURLLoader* loader, |
| 320 int dataLength) { |
| 321 NOTIMPLEMENTED(); |
| 322 } |
| 323 |
| 324 void BufferedResourceLoader::didReceiveCachedMetadata( |
| 325 WebURLLoader* loader, |
| 326 const char* data, |
| 327 int data_length) { |
| 328 NOTIMPLEMENTED(); |
| 329 } |
| 330 |
| 331 void BufferedResourceLoader::didFinishLoading( |
| 332 WebURLLoader* loader, |
| 333 double finishTime) { |
| 334 DCHECK(!completed_); |
| 335 completed_ = true; |
| 336 |
| 337 // If there is a start callback, calls it. |
| 338 if (start_callback_.get()) { |
| 339 DoneStart(net::OK); |
| 340 } |
| 341 |
| 342 // If there is a pending read but the request has ended, returns with what |
| 343 // we have. |
| 344 if (HasPendingRead()) { |
| 345 // Make sure we have a valid buffer before we satisfy a read request. |
| 346 DCHECK(buffer_.get()); |
| 347 |
| 348 // Try to fulfill with what is in the buffer. |
| 349 if (CanFulfillRead()) |
| 350 ReadInternal(); |
| 351 else |
| 352 DoneRead(net::ERR_CACHE_MISS); |
| 353 } |
| 354 |
| 355 // There must not be any outstanding read request. |
| 356 DCHECK(!HasPendingRead()); |
| 357 |
| 358 // Notify that network response is completed. |
| 359 NotifyNetworkEvent(); |
| 360 |
| 361 url_loader_.reset(); |
| 362 Release(); |
| 363 } |
| 364 |
| 365 void BufferedResourceLoader::didFail( |
| 366 WebURLLoader* loader, |
| 367 const WebURLError& error) { |
| 368 DCHECK(!completed_); |
| 369 completed_ = true; |
| 370 |
| 371 // If there is a start callback, calls it. |
| 372 if (start_callback_.get()) { |
| 373 DoneStart(error.reason); |
| 374 } |
| 375 |
| 376 // If there is a pending read but the request failed, return with the |
| 377 // reason for the error. |
| 378 if (HasPendingRead()) { |
| 379 DoneRead(error.reason); |
| 380 } |
| 381 |
| 382 // Notify that network response is completed. |
| 383 NotifyNetworkEvent(); |
| 384 |
| 385 url_loader_.reset(); |
| 386 Release(); |
| 387 } |
| 388 |
| 389 void BufferedResourceLoader::EnableDeferIfNeeded() { |
| 390 if (!defer_allowed_) |
| 391 return; |
| 392 |
| 393 if (!deferred_ && |
| 394 buffer_->forward_bytes() >= buffer_->forward_capacity()) { |
| 395 deferred_ = true; |
| 396 |
| 397 if (url_loader_.get()) |
| 398 url_loader_->setDefersLoading(true); |
| 399 |
| 400 NotifyNetworkEvent(); |
| 401 } |
| 402 } |
| 403 |
| 404 void BufferedResourceLoader::DisableDeferIfNeeded() { |
| 405 if (deferred_ && |
| 406 (!defer_allowed_ || |
| 407 buffer_->forward_bytes() < buffer_->forward_capacity() / 2)) { |
| 408 deferred_ = false; |
| 409 |
| 410 if (url_loader_.get()) |
| 411 url_loader_->setDefersLoading(false); |
| 412 |
| 413 NotifyNetworkEvent(); |
| 414 } |
| 415 } |
| 416 |
| 417 bool BufferedResourceLoader::CanFulfillRead() { |
| 418 // If we are reading too far in the backward direction. |
| 419 if (first_offset_ < 0 && |
| 420 first_offset_ + static_cast<int>(buffer_->backward_bytes()) < 0) |
| 421 return false; |
| 422 |
| 423 // If the start offset is too far ahead. |
| 424 if (first_offset_ >= static_cast<int>(buffer_->forward_bytes())) |
| 425 return false; |
| 426 |
| 427 // At the point, we verified that first byte requested is within the buffer. |
| 428 // If the request has completed, then just returns with what we have now. |
| 429 if (completed_) |
| 430 return true; |
| 431 |
| 432 // If the resource request is still active, make sure the whole requested |
| 433 // range is covered. |
| 434 if (last_offset_ > static_cast<int>(buffer_->forward_bytes())) |
| 435 return false; |
| 436 |
| 437 return true; |
| 438 } |
| 439 |
| 440 bool BufferedResourceLoader::WillFulfillRead() { |
| 441 // Reading too far in the backward direction. |
| 442 if (first_offset_ < 0 && |
| 443 first_offset_ + static_cast<int>(buffer_->backward_bytes()) < 0) |
| 444 return false; |
| 445 |
| 446 // Try to read too far ahead. |
| 447 if (last_offset_ > net::kForwardWaitThreshold) |
| 448 return false; |
| 449 |
| 450 // The resource request has completed, there's no way we can fulfill the |
| 451 // read request. |
| 452 if (completed_) |
| 453 return false; |
| 454 |
| 455 return true; |
| 456 } |
| 457 |
| 458 void BufferedResourceLoader::ReadInternal() { |
| 459 // Seek to the first byte requested. |
| 460 bool ret = buffer_->Seek(first_offset_); |
| 461 DCHECK(ret); |
| 462 |
| 463 // Then do the read. |
| 464 int read = static_cast<int>(buffer_->Read(read_buffer_, read_size_)); |
| 465 offset_ += first_offset_ + read; |
| 466 |
| 467 // And report with what we have read. |
| 468 DoneRead(read); |
| 469 } |
| 470 |
| 471 bool BufferedResourceLoader::VerifyPartialResponse( |
| 472 const WebURLResponse& response) { |
| 473 int first_byte_position, last_byte_position, instance_size; |
| 474 |
| 475 if (!MultipartResponseDelegate::ReadContentRanges(response, |
| 476 &first_byte_position, |
| 477 &last_byte_position, |
| 478 &instance_size)) { |
| 479 return false; |
| 480 } |
| 481 |
| 482 if (instance_size != net::kPositionNotSpecified) { |
| 483 instance_size_ = instance_size; |
| 484 } |
| 485 |
| 486 if (first_byte_position_ != net::kPositionNotSpecified && |
| 487 first_byte_position_ != first_byte_position) { |
| 488 return false; |
| 489 } |
| 490 |
| 491 // TODO(hclam): I should also check |last_byte_position|, but since |
| 492 // we will never make such a request that it is ok to leave it unimplemented. |
| 493 return true; |
| 494 } |
| 495 |
| 496 std::string BufferedResourceLoader::GenerateHeaders( |
| 497 int64 first_byte_position, |
| 498 int64 last_byte_position) { |
| 499 // Construct the value for the range header. |
| 500 std::string header; |
| 501 if (first_byte_position > net::kPositionNotSpecified && |
| 502 last_byte_position > net::kPositionNotSpecified) { |
| 503 if (first_byte_position <= last_byte_position) { |
| 504 header = base::StringPrintf("bytes=%" PRId64 "-%" PRId64, |
| 505 first_byte_position, |
| 506 last_byte_position); |
| 507 } |
| 508 } else if (first_byte_position > net::kPositionNotSpecified) { |
| 509 header = base::StringPrintf("bytes=%" PRId64 "-", |
| 510 first_byte_position); |
| 511 } else if (last_byte_position > net::kPositionNotSpecified) { |
| 512 NOTIMPLEMENTED() << "Suffix range not implemented"; |
| 513 } |
| 514 return header; |
| 515 } |
| 516 |
| 517 void BufferedResourceLoader::DoneRead(int error) { |
| 518 read_callback_->RunWithParams(Tuple1<int>(error)); |
| 519 read_callback_.reset(); |
| 520 read_position_ = 0; |
| 521 read_size_ = 0; |
| 522 read_buffer_ = NULL; |
| 523 first_offset_ = 0; |
| 524 last_offset_ = 0; |
| 525 } |
| 526 |
| 527 void BufferedResourceLoader::DoneStart(int error) { |
| 528 start_callback_->RunWithParams(Tuple1<int>(error)); |
| 529 start_callback_.reset(); |
| 530 } |
| 531 |
| 532 void BufferedResourceLoader::NotifyNetworkEvent() { |
| 533 if (event_callback_.get()) |
| 534 event_callback_->Run(); |
| 535 } |
| 536 |
| 537 } // namespace webkit_glue |
OLD | NEW |