diff options
author | annacc@chromium.org <annacc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-16 18:49:52 +0000 |
---|---|---|
committer | annacc@chromium.org <annacc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-16 18:49:52 +0000 |
commit | 32ba25f8130e85dc5189b06490156c1df4f0cee8 (patch) | |
tree | e2427dbc87efb9289315dff1cb416c8f823aac7a /webkit/glue | |
parent | 1cf1e69b1ea029d5d99a9b25d9e505cb56170630 (diff) | |
download | chromium_src-32ba25f8130e85dc5189b06490156c1df4f0cee8.zip chromium_src-32ba25f8130e85dc5189b06490156c1df4f0cee8.tar.gz chromium_src-32ba25f8130e85dc5189b06490156c1df4f0cee8.tar.bz2 |
Separate BufferedDataSource and BufferedResourceLoader into two files.
It's time to finally separate the huge monster files buffered_data_source.[h/cc] into two.
ericroman: There are some variables and short methods that both BufferedDataSource and BufferedResourceLoader rely on and that I have moved to src/net/http/http_util.h. Could you please verify that this is an ok place to put them?
Also, appcache issues have been resolved (and approved by michaeln) so I've removed those comments.
BUG=None.
TEST=Compiles.
Review URL: http://codereview.chromium.org/5756004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@69429 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue')
-rw-r--r-- | webkit/glue/media/buffered_data_source.cc | 617 | ||||
-rw-r--r-- | webkit/glue/media/buffered_data_source.h | 237 | ||||
-rw-r--r-- | webkit/glue/media/buffered_data_source_unittest.cc | 477 | ||||
-rw-r--r-- | webkit/glue/media/buffered_resource_loader.cc | 575 | ||||
-rw-r--r-- | webkit/glue/media/buffered_resource_loader.h | 247 | ||||
-rw-r--r-- | webkit/glue/media/buffered_resource_loader_unittest.cc | 486 | ||||
-rw-r--r-- | webkit/glue/media/media_resource_loader_bridge_factory.cc | 82 | ||||
-rw-r--r-- | webkit/glue/media/media_resource_loader_bridge_factory.h | 76 | ||||
-rw-r--r-- | webkit/glue/media/media_resource_loader_bridge_factory_unittest.cc | 44 | ||||
-rw-r--r-- | webkit/glue/media/mock_media_resource_loader_bridge_factory.h | 36 | ||||
-rw-r--r-- | webkit/glue/media/simple_data_source.cc | 16 | ||||
-rw-r--r-- | webkit/glue/webkit_glue.gypi | 4 | ||||
-rw-r--r-- | webkit/glue/webmediaplayer_impl.cc | 1 |
13 files changed, 1344 insertions, 1554 deletions
diff --git a/webkit/glue/media/buffered_data_source.cc b/webkit/glue/media/buffered_data_source.cc index ec7a3a0..c1aed27 100644 --- a/webkit/glue/media/buffered_data_source.cc +++ b/webkit/glue/media/buffered_data_source.cc @@ -2,61 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/callback.h" -#include "base/compiler_specific.h" -#include "base/format_macros.h" -#include "base/message_loop.h" -#include "base/process_util.h" -#include "base/stl_util-inl.h" -#include "base/string_number_conversions.h" -#include "base/string_util.h" +#include "webkit/glue/media/buffered_data_source.h" + #include "media/base/filter_host.h" -#include "media/base/media_format.h" -#include "net/base/load_flags.h" #include "net/base/net_errors.h" -#include "third_party/WebKit/WebKit/chromium/public/WebKit.h" -#include "third_party/WebKit/WebKit/chromium/public/WebKitClient.h" -#include "third_party/WebKit/WebKit/chromium/public/WebString.h" -#include "third_party/WebKit/WebKit/chromium/public/WebURLError.h" -#include "webkit/glue/media/buffered_data_source.h" -#include "webkit/glue/multipart_response_delegate.h" #include "webkit/glue/webkit_glue.h" -#include "webkit/glue/webmediaplayer_impl.h" using WebKit::WebFrame; -using WebKit::WebString; -using WebKit::WebURLError; -using WebKit::WebURLLoader; -using WebKit::WebURLRequest; -using WebKit::WebURLResponse; -using webkit_glue::MultipartResponseDelegate; namespace { -const char kHttpScheme[] = "http"; -const char kHttpsScheme[] = "https"; -const char kDataScheme[] = "data"; -const int64 kPositionNotSpecified = -1; -const int kHttpOK = 200; -const int kHttpPartialContent = 206; - -// Define the number of bytes in a megabyte. -const size_t kMegabyte = 1024 * 1024; - -// Backward capacity of the buffer, by default 2MB. -const size_t kBackwardCapcity = 2 * kMegabyte; - -// Forward capacity of the buffer, by default 10MB. -const size_t kForwardCapacity = 10 * kMegabyte; - -// The threshold of bytes that we should wait until the data arrives in the -// future instead of restarting a new connection. This number is defined in the -// number of bytes, we should determine this value from typical connection speed -// and amount of time for a suitable wait. Now I just make a guess for this -// number to be 2MB. -// TODO(hclam): determine a better value for this. -const int kForwardWaitThreshold = 2 * kMegabyte; - // Defines how long we should wait for more data before we declare a connection // timeout and start a new request. // TODO(hclam): Set it to 5s, calibrate this value later. @@ -72,556 +27,10 @@ const int kReadTrials = 3; // of FFmpeg. const int kInitialReadBufferSize = 32768; -// Returns true if |url| operates on HTTP protocol. -bool IsHttpProtocol(const GURL& url) { - return url.SchemeIs(kHttpScheme) || url.SchemeIs(kHttpsScheme); -} - -bool IsDataProtocol(const GURL& url) { - return url.SchemeIs(kDataScheme); -} - -} // namespace +} // namespace namespace webkit_glue { -///////////////////////////////////////////////////////////////////////////// -// BufferedResourceLoader -BufferedResourceLoader::BufferedResourceLoader( - const GURL& url, - int64 first_byte_position, - int64 last_byte_position) - : buffer_(new media::SeekableBuffer(kBackwardCapcity, kForwardCapacity)), - deferred_(false), - defer_allowed_(true), - completed_(false), - range_requested_(false), - partial_response_(false), - url_(url), - first_byte_position_(first_byte_position), - last_byte_position_(last_byte_position), - start_callback_(NULL), - offset_(0), - content_length_(kPositionNotSpecified), - instance_size_(kPositionNotSpecified), - read_callback_(NULL), - read_position_(0), - read_size_(0), - read_buffer_(NULL), - first_offset_(0), - last_offset_(0), - keep_test_loader_(false) { -} - -BufferedResourceLoader::~BufferedResourceLoader() { - if (!completed_ && url_loader_.get()) - url_loader_->cancel(); -} - -void BufferedResourceLoader::Start(net::CompletionCallback* start_callback, - NetworkEventCallback* event_callback, - WebFrame* frame) { - // Make sure we have not started. - DCHECK(!start_callback_.get()); - DCHECK(!event_callback_.get()); - DCHECK(start_callback); - DCHECK(event_callback); - CHECK(frame); - - start_callback_.reset(start_callback); - event_callback_.reset(event_callback); - - if (first_byte_position_ != kPositionNotSpecified) { - range_requested_ = true; - // TODO(hclam): server may not support range request so |offset_| may not - // equal to |first_byte_position_|. - offset_ = first_byte_position_; - } - - // Increment the reference count right before we start the request. This - // reference will be release when this request has ended. - AddRef(); - - // Prepare the request. - WebURLRequest request(url_); - request.setTargetType(WebURLRequest::TargetIsMedia); - request.setHTTPHeaderField(WebString::fromUTF8("Range"), - WebString::fromUTF8(GenerateHeaders( - first_byte_position_, - last_byte_position_))); - frame->setReferrerForRequest(request, WebKit::WebURL()); - - // This flag is for unittests as we don't want to reset |url_loader| - if (!keep_test_loader_) - url_loader_.reset(frame->createAssociatedURLLoader()); - - // Start the resource loading. - url_loader_->loadAsynchronously(request, this); -} - -void BufferedResourceLoader::Stop() { - // Reset callbacks. - start_callback_.reset(); - event_callback_.reset(); - read_callback_.reset(); - - // Use the internal buffer to signal that we have been stopped. - // TODO(hclam): Not so pretty to do this. - if (!buffer_.get()) - return; - - // Destroy internal buffer. - buffer_.reset(); - - if (url_loader_.get()) { - if (deferred_) - url_loader_->setDefersLoading(false); - deferred_ = false; - - if (!completed_) { - url_loader_->cancel(); - completed_ = true; - } - } -} - -void BufferedResourceLoader::Read(int64 position, - int read_size, - uint8* buffer, - net::CompletionCallback* read_callback) { - DCHECK(!read_callback_.get()); - DCHECK(buffer_.get()); - DCHECK(read_callback); - DCHECK(buffer); - - // Save the parameter of reading. - read_callback_.reset(read_callback); - read_position_ = position; - read_size_ = read_size; - read_buffer_ = buffer; - - // If read position is beyond the instance size, we cannot read there. - if (instance_size_ != kPositionNotSpecified && - instance_size_ <= read_position_) { - DoneRead(0); - return; - } - - // Make sure |offset_| and |read_position_| does not differ by a large - // amount. - if (read_position_ > offset_ + kint32max || - read_position_ < offset_ + kint32min) { - DoneRead(net::ERR_CACHE_MISS); - return; - } - - // Prepare the parameters. - first_offset_ = static_cast<int>(read_position_ - offset_); - last_offset_ = first_offset_ + read_size_; - - // If we can serve the request now, do the actual read. - if (CanFulfillRead()) { - ReadInternal(); - DisableDeferIfNeeded(); - return; - } - - // If we expected the read request to be fulfilled later, returns - // immediately and let more data to flow in. - if (WillFulfillRead()) - return; - - // Make a callback to report failure. - DoneRead(net::ERR_CACHE_MISS); -} - -int64 BufferedResourceLoader::GetBufferedFirstBytePosition() { - if (buffer_.get()) - return offset_ - static_cast<int>(buffer_->backward_bytes()); - return kPositionNotSpecified; -} - -int64 BufferedResourceLoader::GetBufferedLastBytePosition() { - if (buffer_.get()) - return offset_ + static_cast<int>(buffer_->forward_bytes()) - 1; - return kPositionNotSpecified; -} - -void BufferedResourceLoader::SetAllowDefer(bool is_allowed) { - defer_allowed_ = is_allowed; - DisableDeferIfNeeded(); -} - -int64 BufferedResourceLoader::content_length() { - return content_length_; -} - -int64 BufferedResourceLoader::instance_size() { - return instance_size_; -} - -bool BufferedResourceLoader::partial_response() { - return partial_response_; -} - -bool BufferedResourceLoader::network_activity() { - return !completed_ && !deferred_; -} - -const GURL& BufferedResourceLoader::url() { - return url_; -} - -void BufferedResourceLoader::SetURLLoaderForTest(WebURLLoader* mock_loader) { - url_loader_.reset(mock_loader); - keep_test_loader_ = true; -} - -///////////////////////////////////////////////////////////////////////////// -// BufferedResourceLoader, WebKit::WebURLLoaderClient implementations. -void BufferedResourceLoader::willSendRequest( - WebURLLoader* loader, - WebURLRequest& newRequest, - const WebURLResponse& redirectResponse) { - - // The load may have been stopped and |start_callback| is destroyed. - // In this case we shouldn't do anything. - if (!start_callback_.get()) { - // Set the url in the request to an invalid value (empty url). - newRequest.setURL(WebKit::WebURL()); - return; - } - - if (!IsProtocolSupportedForMedia(newRequest.url())) { - // Set the url in the request to an invalid value (empty url). - newRequest.setURL(WebKit::WebURL()); - DoneStart(net::ERR_ADDRESS_INVALID); - Stop(); - return; - } - - url_ = newRequest.url(); -} - -void BufferedResourceLoader::didSendData( - WebURLLoader* loader, - unsigned long long bytes_sent, - unsigned long long total_bytes_to_be_sent) { - NOTIMPLEMENTED(); -} - -void BufferedResourceLoader::didReceiveResponse( - WebURLLoader* loader, - const WebURLResponse& response) { - - // The loader may have been stopped and |start_callback| is destroyed. - // In this case we shouldn't do anything. - if (!start_callback_.get()) - return; - - // We make a strong assumption that when we reach here we have either - // received a response from HTTP/HTTPS protocol or the request was - // successful (in particular range request). So we only verify the partial - // response for HTTP and HTTPS protocol. - if (IsHttpProtocol(url_)) { - int error = net::OK; - - if (response.httpStatusCode() == kHttpPartialContent) - partial_response_ = true; - - if (range_requested_ && partial_response_) { - // If we have verified the partial response and it is correct, we will - // return net::OK. - if (!VerifyPartialResponse(response)) - error = net::ERR_INVALID_RESPONSE; - } else if (response.httpStatusCode() != kHttpOK) { - // We didn't request a range but server didn't reply with "200 OK". - error = net::ERR_FAILED; - } - - if (error != net::OK) { - DoneStart(error); - Stop(); - return; - } - } else { - // For any protocol other than HTTP and HTTPS, assume range request is - // always fulfilled. - partial_response_ = range_requested_; - } - - // Expected content length can be -1, in that case |content_length_| is - // not specified and this is a streaming response. - content_length_ = response.expectedContentLength(); - - // If we have not requested a range, then the size of the instance is equal - // to the content length. - if (!partial_response_) - instance_size_ = content_length_; - - // Calls with a successful response. - DoneStart(net::OK); -} - -void BufferedResourceLoader::didReceiveData( - WebURLLoader* loader, - const char* data, - int data_length) { - DCHECK(!completed_); - DCHECK_GT(data_length, 0); - - // If this loader has been stopped, |buffer_| would be destroyed. - // In this case we shouldn't do anything. - if (!buffer_.get()) - return; - - // Writes more data to |buffer_|. - buffer_->Append(reinterpret_cast<const uint8*>(data), data_length); - - // If there is an active read request, try to fulfill the request. - if (HasPendingRead() && CanFulfillRead()) { - ReadInternal(); - } else if (!defer_allowed_) { - // If we're not allowed to defer, slide the buffer window forward instead - // of deferring. - if (buffer_->forward_bytes() > buffer_->forward_capacity()) { - size_t excess = buffer_->forward_bytes() - buffer_->forward_capacity(); - bool success = buffer_->Seek(excess); - DCHECK(success); - offset_ += first_offset_ + excess; - } - } - - // At last see if the buffer is full and we need to defer the downloading. - EnableDeferIfNeeded(); - - // Notify that we have received some data. - NotifyNetworkEvent(); -} - -void BufferedResourceLoader::didDownloadData( - WebKit::WebURLLoader* loader, - int dataLength) { - NOTIMPLEMENTED(); -} - -void BufferedResourceLoader::didReceiveCachedMetadata( - WebURLLoader* loader, - const char* data, - int data_length) { - NOTIMPLEMENTED(); -} - -void BufferedResourceLoader::didFinishLoading( - WebURLLoader* loader, - double finishTime) { - DCHECK(!completed_); - completed_ = true; - - // If there is a start callback, calls it. - if (start_callback_.get()) { - DoneStart(net::OK); - } - - // If there is a pending read but the request has ended, returns with what - // we have. - if (HasPendingRead()) { - // Make sure we have a valid buffer before we satisfy a read request. - DCHECK(buffer_.get()); - - // Try to fulfill with what is in the buffer. - if (CanFulfillRead()) - ReadInternal(); - else - DoneRead(net::ERR_CACHE_MISS); - } - - // There must not be any outstanding read request. - DCHECK(!HasPendingRead()); - - // Notify that network response is completed. - NotifyNetworkEvent(); - - url_loader_.reset(); - Release(); -} - -void BufferedResourceLoader::didFail( - WebURLLoader* loader, - const WebURLError& error) { - DCHECK(!completed_); - completed_ = true; - - // If there is a start callback, calls it. - if (start_callback_.get()) { - DoneStart(error.reason); - } - - // If there is a pending read but the request failed, return with the - // reason for the error. - if (HasPendingRead()) { - DoneRead(error.reason); - } - - // Notify that network response is completed. - NotifyNetworkEvent(); - - url_loader_.reset(); - Release(); -} - -///////////////////////////////////////////////////////////////////////////// -// BufferedResourceLoader, private -void BufferedResourceLoader::EnableDeferIfNeeded() { - if (!defer_allowed_) - return; - - if (!deferred_ && - buffer_->forward_bytes() >= buffer_->forward_capacity()) { - deferred_ = true; - - if (url_loader_.get()) - url_loader_->setDefersLoading(true); - - NotifyNetworkEvent(); - } -} - -void BufferedResourceLoader::DisableDeferIfNeeded() { - if (deferred_ && - (!defer_allowed_ || - buffer_->forward_bytes() < buffer_->forward_capacity() / 2)) { - deferred_ = false; - - if (url_loader_.get()) - url_loader_->setDefersLoading(false); - - NotifyNetworkEvent(); - } -} - -bool BufferedResourceLoader::CanFulfillRead() { - // If we are reading too far in the backward direction. - if (first_offset_ < 0 && - first_offset_ + static_cast<int>(buffer_->backward_bytes()) < 0) - return false; - - // If the start offset is too far ahead. - if (first_offset_ >= static_cast<int>(buffer_->forward_bytes())) - return false; - - // At the point, we verified that first byte requested is within the buffer. - // If the request has completed, then just returns with what we have now. - if (completed_) - return true; - - // If the resource request is still active, make sure the whole requested - // range is covered. - if (last_offset_ > static_cast<int>(buffer_->forward_bytes())) - return false; - - return true; -} - -bool BufferedResourceLoader::WillFulfillRead() { - // Reading too far in the backward direction. - if (first_offset_ < 0 && - first_offset_ + static_cast<int>(buffer_->backward_bytes()) < 0) - return false; - - // Try to read too far ahead. - if (last_offset_ > kForwardWaitThreshold) - return false; - - // The resource request has completed, there's no way we can fulfill the - // read request. - if (completed_) - return false; - - return true; -} - -void BufferedResourceLoader::ReadInternal() { - // Seek to the first byte requested. - bool ret = buffer_->Seek(first_offset_); - DCHECK(ret); - - // Then do the read. - int read = static_cast<int>(buffer_->Read(read_buffer_, read_size_)); - offset_ += first_offset_ + read; - - // And report with what we have read. - DoneRead(read); -} - -bool BufferedResourceLoader::VerifyPartialResponse( - const WebURLResponse& response) { - int first_byte_position, last_byte_position, instance_size; - - if (!MultipartResponseDelegate::ReadContentRanges(response, - &first_byte_position, - &last_byte_position, - &instance_size)) { - return false; - } - - if (instance_size != kPositionNotSpecified) { - instance_size_ = instance_size; - } - - if (first_byte_position_ != kPositionNotSpecified && - first_byte_position_ != first_byte_position) { - return false; - } - - // TODO(hclam): I should also check |last_byte_position|, but since - // we will never make such a request that it is ok to leave it unimplemented. - return true; -} - -std::string BufferedResourceLoader::GenerateHeaders( - int64 first_byte_position, - int64 last_byte_position) { - // Construct the value for the range header. - std::string header; - if (first_byte_position > kPositionNotSpecified && - last_byte_position > kPositionNotSpecified) { - if (first_byte_position <= last_byte_position) { - header = base::StringPrintf("bytes=%" PRId64 "-%" PRId64, - first_byte_position, - last_byte_position); - } - } else if (first_byte_position > kPositionNotSpecified) { - header = base::StringPrintf("bytes=%" PRId64 "-", - first_byte_position); - } else if (last_byte_position > kPositionNotSpecified) { - NOTIMPLEMENTED() << "Suffix range not implemented"; - } - return header; -} - -void BufferedResourceLoader::DoneRead(int error) { - read_callback_->RunWithParams(Tuple1<int>(error)); - read_callback_.reset(); - read_position_ = 0; - read_size_ = 0; - read_buffer_ = NULL; - first_offset_ = 0; - last_offset_ = 0; -} - -void BufferedResourceLoader::DoneStart(int error) { - start_callback_->RunWithParams(Tuple1<int>(error)); - start_callback_.reset(); -} - -void BufferedResourceLoader::NotifyNetworkEvent() { - if (event_callback_.get()) - event_callback_->Run(); -} - -///////////////////////////////////////////////////////////////////////////// -// BufferedDataSource BufferedDataSource::BufferedDataSource( MessageLoop* render_loop, WebFrame* frame) @@ -701,7 +110,7 @@ bool BufferedDataSource::IsUrlSupported(const std::string& url) { GURL gurl(url); // This data source doesn't support data:// protocol so reject it. - return IsProtocolSupportedForMedia(gurl) && !IsDataProtocol(gurl); + return IsProtocolSupportedForMedia(gurl) && !gurl.SchemeIs(kDataScheme); } void BufferedDataSource::Stop(media::FilterCallback* callback) { @@ -781,7 +190,7 @@ void BufferedDataSource::InitializeTask() { this, &BufferedDataSource::WatchDogTask); - if (IsHttpProtocol(url_)) { + if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) { // Fetch only first 1024 bytes as this usually covers the header portion // of a media file that gives enough information about the codecs, etc. // This also serve as a probe to determine server capability to serve @@ -796,7 +205,8 @@ void BufferedDataSource::InitializeTask() { // For all other protocols, assume they support range request. We fetch // the full range of the resource to obtain the instance size because // we won't be served HTTP headers. - loader_ = CreateResourceLoader(-1, -1); + loader_ = CreateResourceLoader(kPositionNotSpecified, + kPositionNotSpecified); loader_->Start( NewCallback(this, &BufferedDataSource::NonHttpInitialStartCallback), NewCallback(this, &BufferedDataSource::NetworkEventCallback), @@ -859,7 +269,7 @@ void BufferedDataSource::RestartLoadingTask() { if (!read_callback_.get()) return; - loader_ = CreateResourceLoader(read_position_, -1); + loader_ = CreateResourceLoader(read_position_, kPositionNotSpecified); loader_->SetAllowDefer(!media_is_paused_); loader_->Start( NewCallback(this, &BufferedDataSource::PartialReadStartCallback), @@ -892,7 +302,7 @@ void BufferedDataSource::WatchDogTask() { // Stops the current loader and creates a new resource loader and // retry the request. loader_->Stop(); - loader_ = CreateResourceLoader(read_position_, -1); + loader_ = CreateResourceLoader(read_position_, kPositionNotSpecified); loader_->SetAllowDefer(!media_is_paused_); loader_->Start( NewCallback(this, &BufferedDataSource::PartialReadStartCallback), @@ -992,7 +402,8 @@ void BufferedDataSource::HttpInitialStartCallback(int error) { // Assuming that the Range header was causing the problem. Retry without // the Range header. using_range_request_ = false; - loader_ = CreateResourceLoader(-1, -1); + loader_ = CreateResourceLoader(kPositionNotSpecified, + kPositionNotSpecified); loader_->Start( NewCallback(this, &BufferedDataSource::HttpInitialStartCallback), NewCallback(this, &BufferedDataSource::NetworkEventCallback), @@ -1150,10 +561,10 @@ void BufferedDataSource::NetworkEventCallback() { return; bool network_activity = loader_->network_activity(); - int64 buffered_last_byte_position = loader_->GetBufferedLastBytePosition(); + int64 buffered_position = loader_->GetBufferedPosition(); // If we get an unspecified value, return immediately. - if (buffered_last_byte_position == kPositionNotSpecified) + if (buffered_position == kPositionNotSpecified) return; // We need to prevent calling to filter host and running the callback if @@ -1172,7 +583,7 @@ void BufferedDataSource::NetworkEventCallback() { network_activity_ = network_activity; host()->SetNetworkActivity(network_activity); } - host()->SetBufferedBytes(buffered_last_byte_position + 1); + host()->SetBufferedBytes(buffered_position + 1); } } // namespace webkit_glue diff --git a/webkit/glue/media/buffered_data_source.h b/webkit/glue/media/buffered_data_source.h index 6ea6f1c..1c4e3fa 100644 --- a/webkit/glue/media/buffered_data_source.h +++ b/webkit/glue/media/buffered_data_source.h @@ -10,245 +10,10 @@ #include "base/callback.h" #include "base/lock.h" #include "base/scoped_ptr.h" -#include "base/timer.h" -#include "base/condition_variable.h" -#include "googleurl/src/gurl.h" -#include "media/base/filters.h" -#include "media/base/media_format.h" -#include "media/base/pipeline.h" -#include "media/base/seekable_buffer.h" -#include "net/base/completion_callback.h" -#include "net/base/file_stream.h" -#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" -#include "third_party/WebKit/WebKit/chromium/public/WebURLLoader.h" -#include "third_party/WebKit/WebKit/chromium/public/WebURLLoaderClient.h" -#include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h" -#include "webkit/glue/media/web_data_source.h" -#include "webkit/glue/webmediaplayer_impl.h" - -namespace WebKit { -class WebURLResponse; -} +#include "webkit/glue/media/buffered_resource_loader.h" namespace webkit_glue { -///////////////////////////////////////////////////////////////////////////// -// BufferedResourceLoader -// This class works inside demuxer thread and render thread. It contains a -// WebURLLoader and does the actual resource loading. This object does -// buffering internally, it defers the resource loading if buffer is full -// and un-defers the resource loading if it is under buffered. -class BufferedResourceLoader : - public base::RefCountedThreadSafe<BufferedResourceLoader>, - public WebKit::WebURLLoaderClient { - public: - typedef Callback0::Type NetworkEventCallback; - - // |url| - URL for the resource to be loaded. - // |first_byte_position| - First byte to start loading from, -1 for not - // specified. - // |last_byte_position| - Last byte to be loaded, -1 for not specified. - BufferedResourceLoader(const GURL& url, - int64 first_byte_position, - int64 last_byte_position); - - // Start the resource loading with the specified URL and range. - // This method operates in asynchronous mode. Once there's a response from the - // server, success or fail |callback| is called with the result. - // |callback| is called with the following values: - // - net::OK - // The request has started successfully. - // - net::ERR_FAILED - // The request has failed because of an error with the network. - // - net::ERR_INVALID_RESPONSE - // An invalid response is received from the server. - // - (Anything else) - // An error code that indicates the request has failed. - // |event_callback| is called when the response is completed, data is - // received, the request is suspended or resumed. - virtual void Start(net::CompletionCallback* callback, - NetworkEventCallback* event_callback, - WebKit::WebFrame* frame); - - // Stop this loader, cancels and request and release internal buffer. - virtual void Stop(); - - // Reads the specified |read_size| from |position| into |buffer| and when - // the operation is done invoke |callback| with number of bytes read or an - // error code. - // |callback| is called with the following values: - // - (Anything greater than or equal 0) - // Read was successful with the indicated number of bytes read. - // - net::ERR_FAILED - // The read has failed because of an error with the network. - // - net::ERR_CACHE_MISS - // The read was made too far away from the current buffered position. - virtual void Read(int64 position, int read_size, - uint8* buffer, net::CompletionCallback* callback); - - // Returns the position of the first byte buffered. Returns -1 if such value - // is not available. - virtual int64 GetBufferedFirstBytePosition(); - - // Returns the position of the last byte buffered. Returns -1 if such value - // is not available. - virtual int64 GetBufferedLastBytePosition(); - - // Sets whether deferring data is allowed or disallowed. - virtual void SetAllowDefer(bool is_allowed); - - // Gets the content length in bytes of the instance after this loader has been - // started. If this value is -1, then content length is unknown. - virtual int64 content_length(); - - // Gets the original size of the file requested. If this value is -1, then - // the size is unknown. - virtual int64 instance_size(); - - // Returns true if the response for this loader is a partial response. - // It means a 206 response in HTTP/HTTPS protocol. - virtual bool partial_response(); - - // Returns true if network is currently active. - virtual bool network_activity(); - - // Returns resulting URL. - virtual const GURL& url(); - - // Used to inject a mock used for unittests. - virtual void SetURLLoaderForTest(WebKit::WebURLLoader* mock_loader); - - ///////////////////////////////////////////////////////////////////////////// - // WebKit::WebURLLoaderClient implementations. - virtual void willSendRequest( - WebKit::WebURLLoader* loader, - WebKit::WebURLRequest& newRequest, - const WebKit::WebURLResponse& redirectResponse); - virtual void didSendData( - WebKit::WebURLLoader* loader, - unsigned long long bytesSent, - unsigned long long totalBytesToBeSent); - virtual void didReceiveResponse( - WebKit::WebURLLoader* loader, - const WebKit::WebURLResponse& response); - virtual void didDownloadData( - WebKit::WebURLLoader* loader, - int dataLength); - virtual void didReceiveData( - WebKit::WebURLLoader* loader, - const char* data, - int dataLength); - virtual void didReceiveCachedMetadata( - WebKit::WebURLLoader* loader, - const char* data, int dataLength); - virtual void didFinishLoading( - WebKit::WebURLLoader* loader, - double finishTime); - virtual void didFail( - WebKit::WebURLLoader* loader, - const WebKit::WebURLError&); - - protected: - friend class base::RefCountedThreadSafe<BufferedResourceLoader>; - - virtual ~BufferedResourceLoader(); - - private: - friend class BufferedResourceLoaderTest; - - // Defer the resource loading if the buffer is full. - void EnableDeferIfNeeded(); - - // Disable defer loading if we are under-buffered. - void DisableDeferIfNeeded(); - - // Returns true if the current read request can be fulfilled by what is in - // the buffer. - bool CanFulfillRead(); - - // Returns true if the current read request will be fulfilled in the future. - bool WillFulfillRead(); - - // Method that does the actual read and calls the |read_callbac_|, assuming - // the request range is in |buffer_|. - void ReadInternal(); - - // If we have made a range request, verify the response from the server. - bool VerifyPartialResponse(const WebKit::WebURLResponse& response); - - // Returns the value for a range request header using parameters - // |first_byte_position| and |last_byte_position|. Negative numbers other - // than -1 are not allowed for |first_byte_position| and |last_byte_position|. - // |first_byte_position| should always be less than or equal to - // |last_byte_position| if they are both not -1. - // Empty string is returned on invalid parameters. - std::string GenerateHeaders(int64 first_byte_position, - int64 last_byte_position); - - // Done with read. Invokes the read callback and reset parameters for the - // read request. - void DoneRead(int error); - - // Done with start. Invokes the start callback and reset it. - void DoneStart(int error); - - // Calls |event_callback_| in terms of a network event. - void NotifyNetworkEvent(); - - bool HasPendingRead() { return read_callback_.get() != NULL; } - - // A sliding window of buffer. - scoped_ptr<media::SeekableBuffer> buffer_; - - // True if resource loading was deferred. - bool deferred_; - - // True if resource loader is allowed to defer, false otherwise. - bool defer_allowed_; - - // True if resource loading has completed. - bool completed_; - - // True if a range request was made. - bool range_requested_; - - // True if response data received is a partial range. - bool partial_response_; - - // Does the work of loading and sends data back to this client. - scoped_ptr<WebKit::WebURLLoader> url_loader_; - - GURL url_; - int64 first_byte_position_; - int64 last_byte_position_; - - // Callback method that listens to network events. - scoped_ptr<NetworkEventCallback> event_callback_; - - // Members used during request start. - scoped_ptr<net::CompletionCallback> start_callback_; - int64 offset_; - int64 content_length_; - int64 instance_size_; - - // Members used during a read operation. They should be reset after each - // read has completed or failed. - scoped_ptr<net::CompletionCallback> read_callback_; - int64 read_position_; - int read_size_; - uint8* read_buffer_; - - // Offsets of the requested first byte and last byte in |buffer_|. They are - // written by VerifyRead(). - int first_offset_; - int last_offset_; - - // Used to ensure mocks for unittests are used instead of reset in Start(). - bool keep_test_loader_; - - DISALLOW_COPY_AND_ASSIGN(BufferedResourceLoader); -}; - class BufferedDataSource : public WebDataSource { public: BufferedDataSource(MessageLoop* render_loop, diff --git a/webkit/glue/media/buffered_data_source_unittest.cc b/webkit/glue/media/buffered_data_source_unittest.cc index 5fad3a4..1e1bb1a 100644 --- a/webkit/glue/media/buffered_data_source_unittest.cc +++ b/webkit/glue/media/buffered_data_source_unittest.cc @@ -4,26 +4,14 @@ #include <algorithm> -#include "base/callback.h" -#include "base/format_macros.h" -#include "base/message_loop.h" -#include "base/string_util.h" -#include "base/stringprintf.h" -#include "media/base/filters.h" +#include "base/test/test_timeouts.h" #include "media/base/mock_filter_host.h" #include "media/base/mock_filters.h" #include "net/base/net_errors.h" -#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" -#include "third_party/WebKit/WebKit/chromium/public/WebFrameClient.h" -#include "third_party/WebKit/WebKit/chromium/public/WebString.h" #include "third_party/WebKit/WebKit/chromium/public/WebURLError.h" -#include "third_party/WebKit/WebKit/chromium/public/WebURLLoader.h" -#include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h" #include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.h" -#include "third_party/WebKit/WebKit/chromium/public/WebView.h" #include "webkit/glue/media/buffered_data_source.h" #include "webkit/glue/mock_webframe.h" -#include "webkit/glue/mock_weburlloader_impl.h" using ::testing::_; using ::testing::Assign; @@ -41,22 +29,11 @@ using ::testing::StrictMock; using ::testing::NiceMock; using ::testing::WithArgs; -using WebKit::WebURLError; -using WebKit::WebFrame; -using WebKit::WebFrameClient; -using WebKit::WebString; -using WebKit::WebURLLoader; -using WebKit::WebURLRequest; -using WebKit::WebURLResponse; -using WebKit::WebView; - namespace { const char* kHttpUrl = "http://test"; const char* kFileUrl = "file://test"; const int kDataSize = 1024; -const int kHttpOK = 200; -const int kHttpPartialContent = 206; enum NetworkState { NONE, @@ -68,433 +45,28 @@ enum NetworkState { namespace webkit_glue { -// Submit a request completed event to the resource loader due to request -// being canceled. Pretending the event is from external. -ACTION_P(RequestCanceled, loader) { - WebURLError error; - error.reason = net::ERR_ABORTED; - error.domain = WebString::fromUTF8(net::kErrorDomain); - loader->didFail(NULL, error); -} - -class BufferedResourceLoaderTest : public testing::Test { +// A mock BufferedDataSource to inject mock BufferedResourceLoader through +// CreateResourceLoader() method. +class MockBufferedDataSource : public BufferedDataSource { public: - BufferedResourceLoaderTest() { - url_loader_ = new NiceMock<MockWebURLLoader>(); - - for (int i = 0; i < kDataSize; ++i) - data_[i] = i; - } - - virtual ~BufferedResourceLoaderTest() { - ignore_result(frame_.release()); - } - - void Initialize(const char* url, int first_position, int last_position) { - gurl_ = GURL(url); - first_position_ = first_position; - last_position_ = last_position; - - frame_.reset(new NiceMock<MockWebFrame>()); - - loader_ = new BufferedResourceLoader(gurl_, - first_position_, last_position_); - loader_->SetURLLoaderForTest(url_loader_); - } - - void SetLoaderBuffer(size_t forward_capacity, size_t backward_capacity) { - loader_->buffer_.reset( - new media::SeekableBuffer(backward_capacity, forward_capacity)); - } - - void Start() { - InSequence s; - EXPECT_CALL(*url_loader_, loadAsynchronously(_, loader_.get())); - loader_->Start( - NewCallback(this, &BufferedResourceLoaderTest::StartCallback), - NewCallback(this, &BufferedResourceLoaderTest::NetworkCallback), - frame_.get()); - } - - void FullResponse(int64 instance_size) { - EXPECT_CALL(*this, StartCallback(net::OK)); - - WebURLResponse response(gurl_); - response.setHTTPHeaderField(WebString::fromUTF8("Content-Length"), - WebString::fromUTF8(base::StringPrintf("%" - PRId64, instance_size))); - response.setExpectedContentLength(instance_size); - response.setHTTPStatusCode(kHttpOK); - loader_->didReceiveResponse(url_loader_, response); - EXPECT_EQ(instance_size, loader_->content_length()); - EXPECT_EQ(instance_size, loader_->instance_size()); - EXPECT_FALSE(loader_->partial_response()); - } - - void PartialResponse(int64 first_position, int64 last_position, - int64 instance_size) { - EXPECT_CALL(*this, StartCallback(net::OK)); - int64 content_length = last_position - first_position + 1; - - WebURLResponse response(gurl_); - response.setHTTPHeaderField(WebString::fromUTF8("Content-Range"), - WebString::fromUTF8(base::StringPrintf("bytes " - "%" PRId64 "-%" PRId64 "/%" PRId64, - first_position, - last_position, - instance_size))); - response.setExpectedContentLength(content_length); - response.setHTTPStatusCode(kHttpPartialContent); - loader_->didReceiveResponse(url_loader_, response); - EXPECT_EQ(content_length, loader_->content_length()); - EXPECT_EQ(instance_size, loader_->instance_size()); - EXPECT_TRUE(loader_->partial_response()); - } - - void StopWhenLoad() { - InSequence s; - EXPECT_CALL(*url_loader_, cancel()) - .WillOnce(RequestCanceled(loader_)); - loader_->Stop(); - } - - // Helper method to write to |loader_| from |data_|. - void WriteLoader(int position, int size) { - EXPECT_CALL(*this, NetworkCallback()) - .RetiresOnSaturation(); - loader_->didReceiveData(url_loader_, - reinterpret_cast<char*>(data_ + position), size); - } - - // Helper method to read from |loader_|. - void ReadLoader(int64 position, int size, uint8* buffer) { - loader_->Read(position, size, buffer, - NewCallback(this, &BufferedResourceLoaderTest::ReadCallback)); - } - - // Verifis that data in buffer[0...size] is equal to data_[pos...pos+size]. - void VerifyBuffer(uint8* buffer, int pos, int size) { - EXPECT_EQ(0, memcmp(buffer, data_ + pos, size)); - } - - // Helper method to disallow deferring in |loader_|. - void DisallowLoaderDefer() { - if (loader_->deferred_) { - EXPECT_CALL(*url_loader_, setDefersLoading(false)); - EXPECT_CALL(*this, NetworkCallback()); - } - loader_->SetAllowDefer(false); + MockBufferedDataSource( + MessageLoop* message_loop, WebFrame* frame) + : BufferedDataSource(message_loop, frame) { } - // Helper method to allow deferring in |loader_|. - void AllowLoaderDefer() { - loader_->SetAllowDefer(true); + virtual base::TimeDelta GetTimeoutMilliseconds() { + return base::TimeDelta::FromMilliseconds( + TestTimeouts::tiny_timeout_ms()); } - MOCK_METHOD1(StartCallback, void(int error)); - MOCK_METHOD1(ReadCallback, void(int error)); - MOCK_METHOD0(NetworkCallback, void()); - - protected: - GURL gurl_; - int64 first_position_; - int64 last_position_; - - scoped_refptr<BufferedResourceLoader> loader_; - NiceMock<MockWebURLLoader>* url_loader_; - scoped_ptr<NiceMock<MockWebFrame> > frame_; - - uint8 data_[kDataSize]; + MOCK_METHOD2(CreateResourceLoader, + BufferedResourceLoader*(int64 first_position, + int64 last_position)); private: - DISALLOW_COPY_AND_ASSIGN(BufferedResourceLoaderTest); + DISALLOW_COPY_AND_ASSIGN(MockBufferedDataSource); }; -TEST_F(BufferedResourceLoaderTest, StartStop) { - Initialize(kHttpUrl, -1, -1); - Start(); - StopWhenLoad(); -} - -// Tests that a bad HTTP response is recived, e.g. file not found. -TEST_F(BufferedResourceLoaderTest, BadHttpResponse) { - Initialize(kHttpUrl, -1, -1); - Start(); - - EXPECT_CALL(*this, StartCallback(net::ERR_FAILED)); - EXPECT_CALL(*url_loader_, cancel()) - .WillOnce(RequestCanceled(loader_)); - - WebURLResponse response(gurl_); - response.setHTTPStatusCode(404); - response.setHTTPStatusText("Not Found\n"); - loader_->didReceiveResponse(url_loader_, response); -} - -// Tests that partial content is requested but not fulfilled. -TEST_F(BufferedResourceLoaderTest, NotPartialResponse) { - Initialize(kHttpUrl, 100, -1); - Start(); - FullResponse(1024); - StopWhenLoad(); -} - -// Tests that a 200 response is received. -TEST_F(BufferedResourceLoaderTest, FullResponse) { - Initialize(kHttpUrl, -1, -1); - Start(); - FullResponse(1024); - StopWhenLoad(); -} - -// Tests that a partial content response is received. -TEST_F(BufferedResourceLoaderTest, PartialResponse) { - Initialize(kHttpUrl, 100, 200); - Start(); - PartialResponse(100, 200, 1024); - StopWhenLoad(); -} - -// Tests that an invalid partial response is received. -TEST_F(BufferedResourceLoaderTest, InvalidPartialResponse) { - Initialize(kHttpUrl, 0, 10); - Start(); - - EXPECT_CALL(*this, StartCallback(net::ERR_INVALID_RESPONSE)); - EXPECT_CALL(*url_loader_, cancel()) - .WillOnce(RequestCanceled(loader_)); - - WebURLResponse response(gurl_); - response.setHTTPHeaderField(WebString::fromUTF8("Content-Range"), - WebString::fromUTF8(base::StringPrintf("bytes " - "%d-%d/%d", 1, 10, 1024))); - response.setExpectedContentLength(10); - response.setHTTPStatusCode(kHttpPartialContent); - loader_->didReceiveResponse(url_loader_, response); -} - -// Tests the logic of sliding window for data buffering and reading. -TEST_F(BufferedResourceLoaderTest, BufferAndRead) { - Initialize(kHttpUrl, 10, 29); - Start(); - PartialResponse(10, 29, 30); - - uint8 buffer[10]; - InSequence s; - - // Writes 10 bytes and read them back. - WriteLoader(10, 10); - EXPECT_CALL(*this, ReadCallback(10)); - ReadLoader(10, 10, buffer); - VerifyBuffer(buffer, 10, 10); - - // Writes 10 bytes and read 2 times. - WriteLoader(20, 10); - EXPECT_CALL(*this, ReadCallback(5)); - ReadLoader(20, 5, buffer); - VerifyBuffer(buffer, 20, 5); - EXPECT_CALL(*this, ReadCallback(5)); - ReadLoader(25, 5, buffer); - VerifyBuffer(buffer, 25, 5); - - // Read backward within buffer. - EXPECT_CALL(*this, ReadCallback(10)); - ReadLoader(10, 10, buffer); - VerifyBuffer(buffer, 10, 10); - - // Read backward outside buffer. - EXPECT_CALL(*this, ReadCallback(net::ERR_CACHE_MISS)); - ReadLoader(9, 10, buffer); - - // Response has completed. - EXPECT_CALL(*this, NetworkCallback()); - loader_->didFinishLoading(url_loader_, 0); - - // Try to read 10 from position 25 will just return with 5 bytes. - EXPECT_CALL(*this, ReadCallback(5)); - ReadLoader(25, 10, buffer); - VerifyBuffer(buffer, 25, 5); - - // Try to read outside buffered range after request has completed. - EXPECT_CALL(*this, ReadCallback(net::ERR_CACHE_MISS)); - ReadLoader(5, 10, buffer); - - // Try to read beyond the instance size. - EXPECT_CALL(*this, ReadCallback(0)); - ReadLoader(30, 10, buffer); -} - -TEST_F(BufferedResourceLoaderTest, ReadOutsideBuffer) { - Initialize(kHttpUrl, 10, 0x00FFFFFF); - Start(); - PartialResponse(10, 0x00FFFFFF, 0x01000000); - - uint8 buffer[10]; - InSequence s; - - // Read very far aheard will get a cache miss. - EXPECT_CALL(*this, ReadCallback(net::ERR_CACHE_MISS)); - ReadLoader(0x00FFFFFF, 1, buffer); - - // The following call will not call ReadCallback() because it is waiting for - // data to arrive. - ReadLoader(10, 10, buffer); - - // Writing to loader will fulfill the read request. - EXPECT_CALL(*this, ReadCallback(10)); - WriteLoader(10, 20); - VerifyBuffer(buffer, 10, 10); - - // The following call cannot be fulfilled now. - ReadLoader(25, 10, buffer); - - EXPECT_CALL(*this, ReadCallback(5)); - EXPECT_CALL(*this, NetworkCallback()); - loader_->didFinishLoading(url_loader_, 0); -} - -TEST_F(BufferedResourceLoaderTest, RequestFailedWhenRead) { - Initialize(kHttpUrl, 10, 29); - Start(); - PartialResponse(10, 29, 30); - - uint8 buffer[10]; - InSequence s; - - ReadLoader(10, 10, buffer); - EXPECT_CALL(*this, ReadCallback(net::ERR_FAILED)); - EXPECT_CALL(*this, NetworkCallback()); - WebURLError error; - error.reason = net::ERR_FAILED; - loader_->didFail(url_loader_, error); -} - -// Tests the logic of caching data to disk when media is paused. -TEST_F(BufferedResourceLoaderTest, AllowDefer_NoDataReceived) { - Initialize(kHttpUrl, 10, 99); - SetLoaderBuffer(10, 20); - Start(); - PartialResponse(10, 99, 100); - - // Start in undeferred state, then disallow defer, then allow defer - // without receiving data in between. - DisallowLoaderDefer(); - AllowLoaderDefer(); - StopWhenLoad(); -} - -TEST_F(BufferedResourceLoaderTest, AllowDefer_ReadSameWindow) { - Initialize(kHttpUrl, 10, 99); - SetLoaderBuffer(10, 20); - Start(); - PartialResponse(10, 99, 100); - - uint8 buffer[10]; - - // Start in undeferred state, disallow defer, receive data but don't shift - // buffer window, then allow defer and read. - DisallowLoaderDefer(); - WriteLoader(10, 10); - AllowLoaderDefer(); - - EXPECT_CALL(*this, ReadCallback(10)); - ReadLoader(10, 10, buffer); - VerifyBuffer(buffer, 10, 10); - StopWhenLoad(); -} - -TEST_F(BufferedResourceLoaderTest, AllowDefer_ReadPastWindow) { - Initialize(kHttpUrl, 10, 99); - SetLoaderBuffer(10, 20); - Start(); - PartialResponse(10, 99, 100); - - uint8 buffer[10]; - - // Not deferred, disallow defer, received data and shift buffer window, - // allow defer, then read in area outside of buffer window. - DisallowLoaderDefer(); - WriteLoader(10, 10); - WriteLoader(20, 50); - AllowLoaderDefer(); - - EXPECT_CALL(*this, ReadCallback(net::ERR_CACHE_MISS)); - ReadLoader(10, 10, buffer); - StopWhenLoad(); -} - -TEST_F(BufferedResourceLoaderTest, AllowDefer_DeferredNoDataReceived) { - Initialize(kHttpUrl, 10, 99); - SetLoaderBuffer(10, 20); - Start(); - PartialResponse(10, 99, 100); - - uint8 buffer[10]; - - // Start in deferred state, then disallow defer, receive no data, and - // allow defer and read. - EXPECT_CALL(*url_loader_, setDefersLoading(true)); - EXPECT_CALL(*this, NetworkCallback()); - WriteLoader(10, 40); - - DisallowLoaderDefer(); - AllowLoaderDefer(); - - EXPECT_CALL(*this, ReadCallback(10)); - ReadLoader(20, 10, buffer); - VerifyBuffer(buffer, 20, 10); - StopWhenLoad(); -} - -TEST_F(BufferedResourceLoaderTest, AllowDefer_DeferredReadSameWindow) { - Initialize(kHttpUrl, 10, 99); - SetLoaderBuffer(10, 20); - Start(); - PartialResponse(10, 99, 100); - - uint8 buffer[10]; - - // Start in deferred state, disallow defer, receive data and shift buffer - // window, allow defer, and read in a place that's still in the window. - EXPECT_CALL(*url_loader_, setDefersLoading(true)); - EXPECT_CALL(*this, NetworkCallback()); - WriteLoader(10, 30); - - DisallowLoaderDefer(); - WriteLoader(40, 5); - AllowLoaderDefer(); - - EXPECT_CALL(*this, ReadCallback(10)); - ReadLoader(20, 10, buffer); - VerifyBuffer(buffer, 20, 10); - StopWhenLoad(); -} - -TEST_F(BufferedResourceLoaderTest, AllowDefer_DeferredReadPastWindow) { - Initialize(kHttpUrl, 10, 99); - SetLoaderBuffer(10, 20); - Start(); - PartialResponse(10, 99, 100); - - uint8 buffer[10]; - - // Start in deferred state, disallow defer, receive data and shift buffer - // window, allow defer, and read outside of the buffer window. - EXPECT_CALL(*url_loader_, setDefersLoading(true)); - EXPECT_CALL(*this, NetworkCallback()); - WriteLoader(10, 40); - - DisallowLoaderDefer(); - WriteLoader(50, 20); - WriteLoader(70, 40); - AllowLoaderDefer(); - - EXPECT_CALL(*this, ReadCallback(net::ERR_CACHE_MISS)); - ReadLoader(20, 5, buffer); - StopWhenLoad(); -} -// TODO(hclam): add unit test for defer loading. - class MockBufferedResourceLoader : public BufferedResourceLoader { public: MockBufferedResourceLoader() : BufferedResourceLoader(GURL(), 0, 0) { @@ -520,27 +92,6 @@ class MockBufferedResourceLoader : public BufferedResourceLoader { DISALLOW_COPY_AND_ASSIGN(MockBufferedResourceLoader); }; -// A mock BufferedDataSource to inject mock BufferedResourceLoader through -// CreateResourceLoader() method. -class MockBufferedDataSource : public BufferedDataSource { - public: - MockBufferedDataSource( - MessageLoop* message_loop, WebFrame* frame) - : BufferedDataSource(message_loop, frame) { - } - - virtual base::TimeDelta GetTimeoutMilliseconds() { - // It is 100 ms because we don't want the test to run too long. - return base::TimeDelta::FromMilliseconds(100); - } - - MOCK_METHOD2(CreateResourceLoader, BufferedResourceLoader*( - int64 first_position, int64 last_position)); - - private: - DISALLOW_COPY_AND_ASSIGN(MockBufferedDataSource); -}; - class BufferedDataSourceTest : public testing::Test { public: BufferedDataSourceTest() { diff --git a/webkit/glue/media/buffered_resource_loader.cc b/webkit/glue/media/buffered_resource_loader.cc new file mode 100644 index 0000000..8045d07 --- /dev/null +++ b/webkit/glue/media/buffered_resource_loader.cc @@ -0,0 +1,575 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "webkit/glue/media/buffered_resource_loader.h" + +#include "base/format_macros.h" +#include "base/string_util.h" +#include "net/base/net_errors.h" +#include "third_party/WebKit/WebKit/chromium/public/WebKit.h" +#include "third_party/WebKit/WebKit/chromium/public/WebKitClient.h" +#include "third_party/WebKit/WebKit/chromium/public/WebString.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLError.h" +#include "webkit/glue/multipart_response_delegate.h" +#include "webkit/glue/webkit_glue.h" + +using WebKit::WebFrame; +using WebKit::WebString; +using WebKit::WebURLError; +using WebKit::WebURLLoader; +using WebKit::WebURLRequest; +using WebKit::WebURLResponse; +using webkit_glue::MultipartResponseDelegate; + +namespace { + +const int kHttpOK = 200; +const int kHttpPartialContent = 206; + +// Define the number of bytes in a megabyte. +const size_t kMegabyte = 1024 * 1024; + +// Backward capacity of the buffer, by default 2MB. +const size_t kBackwardCapcity = 2 * kMegabyte; + +// Forward capacity of the buffer, by default 10MB. +const size_t kForwardCapacity = 10 * kMegabyte; + +// The threshold of bytes that we should wait until the data arrives in the +// future instead of restarting a new connection. This number is defined in the +// number of bytes, we should determine this value from typical connection speed +// and amount of time for a suitable wait. Now I just make a guess for this +// number to be 2MB. +// TODO(hclam): determine a better value for this. +const int kForwardWaitThreshold = 2 * kMegabyte; + +} // namespace + +namespace webkit_glue { + +BufferedResourceLoader::BufferedResourceLoader( + const GURL& url, + int64 first_byte_position, + int64 last_byte_position) + : buffer_(new media::SeekableBuffer(kBackwardCapcity, kForwardCapacity)), + deferred_(false), + defer_allowed_(true), + completed_(false), + range_requested_(false), + partial_response_(false), + url_(url), + first_byte_position_(first_byte_position), + last_byte_position_(last_byte_position), + start_callback_(NULL), + offset_(0), + content_length_(kPositionNotSpecified), + instance_size_(kPositionNotSpecified), + read_callback_(NULL), + read_position_(0), + read_size_(0), + read_buffer_(NULL), + first_offset_(0), + last_offset_(0), + keep_test_loader_(false) { +} + +BufferedResourceLoader::~BufferedResourceLoader() { + if (!completed_ && url_loader_.get()) + url_loader_->cancel(); +} + +void BufferedResourceLoader::Start(net::CompletionCallback* start_callback, + NetworkEventCallback* event_callback, + WebFrame* frame) { + // Make sure we have not started. + DCHECK(!start_callback_.get()); + DCHECK(!event_callback_.get()); + DCHECK(start_callback); + DCHECK(event_callback); + CHECK(frame); + + start_callback_.reset(start_callback); + event_callback_.reset(event_callback); + + if (first_byte_position_ != kPositionNotSpecified) { + range_requested_ = true; + // TODO(hclam): server may not support range request so |offset_| may not + // equal to |first_byte_position_|. + offset_ = first_byte_position_; + } + + // Increment the reference count right before we start the request. This + // reference will be release when this request has ended. + AddRef(); + + // Prepare the request. + WebURLRequest request(url_); + request.setTargetType(WebURLRequest::TargetIsMedia); + request.setHTTPHeaderField(WebString::fromUTF8("Range"), + WebString::fromUTF8(GenerateHeaders( + first_byte_position_, + last_byte_position_))); + frame->setReferrerForRequest(request, WebKit::WebURL()); + + // This flag is for unittests as we don't want to reset |url_loader| + if (!keep_test_loader_) + url_loader_.reset(frame->createAssociatedURLLoader()); + + // Start the resource loading. + url_loader_->loadAsynchronously(request, this); +} + +void BufferedResourceLoader::Stop() { + // Reset callbacks. + start_callback_.reset(); + event_callback_.reset(); + read_callback_.reset(); + + // Use the internal buffer to signal that we have been stopped. + // TODO(hclam): Not so pretty to do this. + if (!buffer_.get()) + return; + + // Destroy internal buffer. + buffer_.reset(); + + if (url_loader_.get()) { + if (deferred_) + url_loader_->setDefersLoading(false); + deferred_ = false; + + if (!completed_) { + url_loader_->cancel(); + completed_ = true; + } + } +} + +void BufferedResourceLoader::Read(int64 position, + int read_size, + uint8* buffer, + net::CompletionCallback* read_callback) { + DCHECK(!read_callback_.get()); + DCHECK(buffer_.get()); + DCHECK(read_callback); + DCHECK(buffer); + + // Save the parameter of reading. + read_callback_.reset(read_callback); + read_position_ = position; + read_size_ = read_size; + read_buffer_ = buffer; + + // If read position is beyond the instance size, we cannot read there. + if (instance_size_ != kPositionNotSpecified && + instance_size_ <= read_position_) { + DoneRead(0); + return; + } + + // Make sure |offset_| and |read_position_| does not differ by a large + // amount. + if (read_position_ > offset_ + kint32max || + read_position_ < offset_ + kint32min) { + DoneRead(net::ERR_CACHE_MISS); + return; + } + + // Prepare the parameters. + first_offset_ = static_cast<int>(read_position_ - offset_); + last_offset_ = first_offset_ + read_size_; + + // If we can serve the request now, do the actual read. + if (CanFulfillRead()) { + ReadInternal(); + DisableDeferIfNeeded(); + return; + } + + // If we expected the read request to be fulfilled later, returns + // immediately and let more data to flow in. + if (WillFulfillRead()) + return; + + // Make a callback to report failure. + DoneRead(net::ERR_CACHE_MISS); +} + +int64 BufferedResourceLoader::GetBufferedPosition() { + if (buffer_.get()) + return offset_ + static_cast<int>(buffer_->forward_bytes()) - 1; + return kPositionNotSpecified; +} + +void BufferedResourceLoader::SetAllowDefer(bool is_allowed) { + defer_allowed_ = is_allowed; + DisableDeferIfNeeded(); +} + +int64 BufferedResourceLoader::content_length() { + return content_length_; +} + +int64 BufferedResourceLoader::instance_size() { + return instance_size_; +} + +bool BufferedResourceLoader::partial_response() { + return partial_response_; +} + +bool BufferedResourceLoader::network_activity() { + return !completed_ && !deferred_; +} + +const GURL& BufferedResourceLoader::url() { + return url_; +} + +void BufferedResourceLoader::SetURLLoaderForTest(WebURLLoader* mock_loader) { + url_loader_.reset(mock_loader); + keep_test_loader_ = true; +} + +// WebKit::WebURLLoaderClient implementations. +void BufferedResourceLoader::willSendRequest( + WebURLLoader* loader, + WebURLRequest& newRequest, + const WebURLResponse& redirectResponse) { + + // The load may have been stopped and |start_callback| is destroyed. + // In this case we shouldn't do anything. + if (!start_callback_.get()) { + // Set the url in the request to an invalid value (empty url). + newRequest.setURL(WebKit::WebURL()); + return; + } + + if (!IsProtocolSupportedForMedia(newRequest.url())) { + // Set the url in the request to an invalid value (empty url). + newRequest.setURL(WebKit::WebURL()); + DoneStart(net::ERR_ADDRESS_INVALID); + Stop(); + return; + } + + url_ = newRequest.url(); +} + +void BufferedResourceLoader::didSendData( + WebURLLoader* loader, + unsigned long long bytes_sent, + unsigned long long total_bytes_to_be_sent) { + NOTIMPLEMENTED(); +} + +void BufferedResourceLoader::didReceiveResponse( + WebURLLoader* loader, + const WebURLResponse& response) { + + // The loader may have been stopped and |start_callback| is destroyed. + // In this case we shouldn't do anything. + if (!start_callback_.get()) + return; + + // We make a strong assumption that when we reach here we have either + // received a response from HTTP/HTTPS protocol or the request was + // successful (in particular range request). So we only verify the partial + // response for HTTP and HTTPS protocol. + if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) { + int error = net::OK; + + if (response.httpStatusCode() == kHttpPartialContent) + partial_response_ = true; + + if (range_requested_ && partial_response_) { + // If we have verified the partial response and it is correct, we will + // return net::OK. + if (!VerifyPartialResponse(response)) + error = net::ERR_INVALID_RESPONSE; + } else if (response.httpStatusCode() != kHttpOK) { + // We didn't request a range but server didn't reply with "200 OK". + error = net::ERR_FAILED; + } + + if (error != net::OK) { + DoneStart(error); + Stop(); + return; + } + } else { + // For any protocol other than HTTP and HTTPS, assume range request is + // always fulfilled. + partial_response_ = range_requested_; + } + + // Expected content length can be |kPositionNotSpecified|, in that case + // |content_length_| is not specified and this is a streaming response. + content_length_ = response.expectedContentLength(); + + // If we have not requested a range, then the size of the instance is equal + // to the content length. + if (!partial_response_) + instance_size_ = content_length_; + + // Calls with a successful response. + DoneStart(net::OK); +} + +void BufferedResourceLoader::didReceiveData( + WebURLLoader* loader, + const char* data, + int data_length) { + DCHECK(!completed_); + DCHECK_GT(data_length, 0); + + // If this loader has been stopped, |buffer_| would be destroyed. + // In this case we shouldn't do anything. + if (!buffer_.get()) + return; + + // Writes more data to |buffer_|. + buffer_->Append(reinterpret_cast<const uint8*>(data), data_length); + + // If there is an active read request, try to fulfill the request. + if (HasPendingRead() && CanFulfillRead()) { + ReadInternal(); + } else if (!defer_allowed_) { + // If we're not allowed to defer, slide the buffer window forward instead + // of deferring. + if (buffer_->forward_bytes() > buffer_->forward_capacity()) { + size_t excess = buffer_->forward_bytes() - buffer_->forward_capacity(); + bool success = buffer_->Seek(excess); + DCHECK(success); + offset_ += first_offset_ + excess; + } + } + + // At last see if the buffer is full and we need to defer the downloading. + EnableDeferIfNeeded(); + + // Notify that we have received some data. + NotifyNetworkEvent(); +} + +void BufferedResourceLoader::didDownloadData( + WebKit::WebURLLoader* loader, + int dataLength) { + NOTIMPLEMENTED(); +} + +void BufferedResourceLoader::didReceiveCachedMetadata( + WebURLLoader* loader, + const char* data, + int data_length) { + NOTIMPLEMENTED(); +} + +void BufferedResourceLoader::didFinishLoading( + WebURLLoader* loader, + double finishTime) { + DCHECK(!completed_); + completed_ = true; + + // If there is a start callback, calls it. + if (start_callback_.get()) { + DoneStart(net::OK); + } + + // If there is a pending read but the request has ended, returns with what + // we have. + if (HasPendingRead()) { + // Make sure we have a valid buffer before we satisfy a read request. + DCHECK(buffer_.get()); + + // Try to fulfill with what is in the buffer. + if (CanFulfillRead()) + ReadInternal(); + else + DoneRead(net::ERR_CACHE_MISS); + } + + // There must not be any outstanding read request. + DCHECK(!HasPendingRead()); + + // Notify that network response is completed. + NotifyNetworkEvent(); + + url_loader_.reset(); + Release(); +} + +void BufferedResourceLoader::didFail( + WebURLLoader* loader, + const WebURLError& error) { + DCHECK(!completed_); + completed_ = true; + + // If there is a start callback, calls it. + if (start_callback_.get()) { + DoneStart(error.reason); + } + + // If there is a pending read but the request failed, return with the + // reason for the error. + if (HasPendingRead()) { + DoneRead(error.reason); + } + + // Notify that network response is completed. + NotifyNetworkEvent(); + + url_loader_.reset(); + Release(); +} + +void BufferedResourceLoader::EnableDeferIfNeeded() { + if (!defer_allowed_) + return; + + if (!deferred_ && + buffer_->forward_bytes() >= buffer_->forward_capacity()) { + deferred_ = true; + + if (url_loader_.get()) + url_loader_->setDefersLoading(true); + + NotifyNetworkEvent(); + } +} + +void BufferedResourceLoader::DisableDeferIfNeeded() { + if (deferred_ && + (!defer_allowed_ || + buffer_->forward_bytes() < buffer_->forward_capacity() / 2)) { + deferred_ = false; + + if (url_loader_.get()) + url_loader_->setDefersLoading(false); + + NotifyNetworkEvent(); + } +} + +bool BufferedResourceLoader::CanFulfillRead() { + // If we are reading too far in the backward direction. + if (first_offset_ < 0 && + first_offset_ + static_cast<int>(buffer_->backward_bytes()) < 0) + return false; + + // If the start offset is too far ahead. + if (first_offset_ >= static_cast<int>(buffer_->forward_bytes())) + return false; + + // At the point, we verified that first byte requested is within the buffer. + // If the request has completed, then just returns with what we have now. + if (completed_) + return true; + + // If the resource request is still active, make sure the whole requested + // range is covered. + if (last_offset_ > static_cast<int>(buffer_->forward_bytes())) + return false; + + return true; +} + +bool BufferedResourceLoader::WillFulfillRead() { + // Reading too far in the backward direction. + if (first_offset_ < 0 && + first_offset_ + static_cast<int>(buffer_->backward_bytes()) < 0) + return false; + + // Try to read too far ahead. + if (last_offset_ > kForwardWaitThreshold) + return false; + + // The resource request has completed, there's no way we can fulfill the + // read request. + if (completed_) + return false; + + return true; +} + +void BufferedResourceLoader::ReadInternal() { + // Seek to the first byte requested. + bool ret = buffer_->Seek(first_offset_); + DCHECK(ret); + + // Then do the read. + int read = static_cast<int>(buffer_->Read(read_buffer_, read_size_)); + offset_ += first_offset_ + read; + + // And report with what we have read. + DoneRead(read); +} + +bool BufferedResourceLoader::VerifyPartialResponse( + const WebURLResponse& response) { + int first_byte_position, last_byte_position, instance_size; + + if (!MultipartResponseDelegate::ReadContentRanges(response, + &first_byte_position, + &last_byte_position, + &instance_size)) { + return false; + } + + if (instance_size != kPositionNotSpecified) { + instance_size_ = instance_size; + } + + if (first_byte_position_ != kPositionNotSpecified && + first_byte_position_ != first_byte_position) { + return false; + } + + // TODO(hclam): I should also check |last_byte_position|, but since + // we will never make such a request that it is ok to leave it unimplemented. + return true; +} + +std::string BufferedResourceLoader::GenerateHeaders( + int64 first_byte_position, + int64 last_byte_position) { + // Construct the value for the range header. + std::string header; + if (first_byte_position > kPositionNotSpecified && + last_byte_position > kPositionNotSpecified) { + if (first_byte_position <= last_byte_position) { + header = base::StringPrintf("bytes=%" PRId64 "-%" PRId64, + first_byte_position, + last_byte_position); + } + } else if (first_byte_position > kPositionNotSpecified) { + header = base::StringPrintf("bytes=%" PRId64 "-", + first_byte_position); + } else if (last_byte_position > kPositionNotSpecified) { + NOTIMPLEMENTED() << "Suffix range not implemented"; + } + return header; +} + +void BufferedResourceLoader::DoneRead(int error) { + read_callback_->RunWithParams(Tuple1<int>(error)); + read_callback_.reset(); + read_position_ = 0; + read_size_ = 0; + read_buffer_ = NULL; + first_offset_ = 0; + last_offset_ = 0; +} + +void BufferedResourceLoader::DoneStart(int error) { + start_callback_->RunWithParams(Tuple1<int>(error)); + start_callback_.reset(); +} + +void BufferedResourceLoader::NotifyNetworkEvent() { + if (event_callback_.get()) + event_callback_->Run(); +} + +} // namespace webkit_glue diff --git a/webkit/glue/media/buffered_resource_loader.h b/webkit/glue/media/buffered_resource_loader.h new file mode 100644 index 0000000..8b5939e --- /dev/null +++ b/webkit/glue/media/buffered_resource_loader.h @@ -0,0 +1,247 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBKIT_GLUE_MEDIA_BUFFERED_RESOURCE_LOADER_H_ +#define WEBKIT_GLUE_MEDIA_BUFFERED_RESOURCE_LOADER_H_ + +#include <string> + +#include "base/callback.h" +#include "base/lock.h" +#include "base/scoped_ptr.h" +#include "base/timer.h" +#include "googleurl/src/gurl.h" +#include "media/base/seekable_buffer.h" +#include "net/base/file_stream.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLLoader.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLLoaderClient.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h" +#include "webkit/glue/media/web_data_source.h" +#include "webkit/glue/webmediaplayer_impl.h" + +namespace webkit_glue { + +const int64 kPositionNotSpecified = -1; + +const char kHttpScheme[] = "http"; +const char kHttpsScheme[] = "https"; +const char kDataScheme[] = "data"; + +// This class works inside demuxer thread and render thread. It contains a +// WebURLLoader and does the actual resource loading. This object does +// buffering internally, it defers the resource loading if buffer is full +// and un-defers the resource loading if it is under buffered. +class BufferedResourceLoader : + public base::RefCountedThreadSafe<BufferedResourceLoader>, + public WebKit::WebURLLoaderClient { + public: + typedef Callback0::Type NetworkEventCallback; + + // |url| - URL for the resource to be loaded. + // |first_byte_position| - First byte to start loading from, + // |kPositionNotSpecified| for not specified. + // |last_byte_position| - Last byte to be loaded, + // |kPositionNotSpecified| for not specified. + BufferedResourceLoader(const GURL& url, + int64 first_byte_position, + int64 last_byte_position); + + // Start the resource loading with the specified URL and range. + // This method operates in asynchronous mode. Once there's a response from the + // server, success or fail |callback| is called with the result. + // |callback| is called with the following values: + // - net::OK + // The request has started successfully. + // - net::ERR_FAILED + // The request has failed because of an error with the network. + // - net::ERR_INVALID_RESPONSE + // An invalid response is received from the server. + // - (Anything else) + // An error code that indicates the request has failed. + // |event_callback| is called when the response is completed, data is + // received, the request is suspended or resumed. + virtual void Start(net::CompletionCallback* callback, + NetworkEventCallback* event_callback, + WebKit::WebFrame* frame); + + // Stop this loader, cancels and request and release internal buffer. + virtual void Stop(); + + // Reads the specified |read_size| from |position| into |buffer| and when + // the operation is done invoke |callback| with number of bytes read or an + // error code. + // |callback| is called with the following values: + // - (Anything greater than or equal 0) + // Read was successful with the indicated number of bytes read. + // - net::ERR_FAILED + // The read has failed because of an error with the network. + // - net::ERR_CACHE_MISS + // The read was made too far away from the current buffered position. + virtual void Read(int64 position, int read_size, + uint8* buffer, net::CompletionCallback* callback); + + // Returns the position of the last byte buffered. Returns + // |kPositionNotSpecified| if such value is not available. + virtual int64 GetBufferedPosition(); + + // Sets whether deferring data is allowed or disallowed. + virtual void SetAllowDefer(bool is_allowed); + + // Gets the content length in bytes of the instance after this loader has been + // started. If this value is |kPositionNotSpecified|, then content length is + // unknown. + virtual int64 content_length(); + + // Gets the original size of the file requested. If this value is + // |kPositionNotSpecified|, then the size is unknown. + virtual int64 instance_size(); + + // Returns true if the response for this loader is a partial response. + // It means a 206 response in HTTP/HTTPS protocol. + virtual bool partial_response(); + + // Returns true if network is currently active. + virtual bool network_activity(); + + // Returns resulting URL. + virtual const GURL& url(); + + // Used to inject a mock used for unittests. + virtual void SetURLLoaderForTest(WebKit::WebURLLoader* mock_loader); + + ///////////////////////////////////////////////////////////////////////////// + // WebKit::WebURLLoaderClient implementations. + virtual void willSendRequest( + WebKit::WebURLLoader* loader, + WebKit::WebURLRequest& newRequest, + const WebKit::WebURLResponse& redirectResponse); + virtual void didSendData( + WebKit::WebURLLoader* loader, + unsigned long long bytesSent, + unsigned long long totalBytesToBeSent); + virtual void didReceiveResponse( + WebKit::WebURLLoader* loader, + const WebKit::WebURLResponse& response); + virtual void didDownloadData( + WebKit::WebURLLoader* loader, + int dataLength); + virtual void didReceiveData( + WebKit::WebURLLoader* loader, + const char* data, + int dataLength); + virtual void didReceiveCachedMetadata( + WebKit::WebURLLoader* loader, + const char* data, int dataLength); + virtual void didFinishLoading( + WebKit::WebURLLoader* loader, + double finishTime); + virtual void didFail( + WebKit::WebURLLoader* loader, + const WebKit::WebURLError&); + + protected: + friend class base::RefCountedThreadSafe<BufferedResourceLoader>; + + virtual ~BufferedResourceLoader(); + + private: + friend class BufferedResourceLoaderTest; + + // Defer the resource loading if the buffer is full. + void EnableDeferIfNeeded(); + + // Disable defer loading if we are under-buffered. + void DisableDeferIfNeeded(); + + // Returns true if the current read request can be fulfilled by what is in + // the buffer. + bool CanFulfillRead(); + + // Returns true if the current read request will be fulfilled in the future. + bool WillFulfillRead(); + + // Method that does the actual read and calls the |read_callback_|, assuming + // the request range is in |buffer_|. + void ReadInternal(); + + // If we have made a range request, verify the response from the server. + bool VerifyPartialResponse(const WebKit::WebURLResponse& response); + + // Returns the value for a range request header using parameters + // |first_byte_position| and |last_byte_position|. Negative numbers other + // than |kPositionNotSpecified| are not allowed for |first_byte_position| and + // |last_byte_position|. |first_byte_position| should always be less than or + // equal to |last_byte_position| if they are both not |kPositionNotSpecified|. + // Empty string is returned on invalid parameters. + std::string GenerateHeaders(int64 first_byte_position, + int64 last_byte_position); + + // Done with read. Invokes the read callback and reset parameters for the + // read request. + void DoneRead(int error); + + // Done with start. Invokes the start callback and reset it. + void DoneStart(int error); + + // Calls |event_callback_| in terms of a network event. + void NotifyNetworkEvent(); + + bool HasPendingRead() { return read_callback_.get() != NULL; } + + // A sliding window of buffer. + scoped_ptr<media::SeekableBuffer> buffer_; + + // True if resource loading was deferred. + bool deferred_; + + // True if resource loader is allowed to defer, false otherwise. + bool defer_allowed_; + + // True if resource loading has completed. + bool completed_; + + // True if a range request was made. + bool range_requested_; + + // True if response data received is a partial range. + bool partial_response_; + + // Does the work of loading and sends data back to this client. + scoped_ptr<WebKit::WebURLLoader> url_loader_; + + GURL url_; + int64 first_byte_position_; + int64 last_byte_position_; + + // Callback method that listens to network events. + scoped_ptr<NetworkEventCallback> event_callback_; + + // Members used during request start. + scoped_ptr<net::CompletionCallback> start_callback_; + int64 offset_; + int64 content_length_; + int64 instance_size_; + + // Members used during a read operation. They should be reset after each + // read has completed or failed. + scoped_ptr<net::CompletionCallback> read_callback_; + int64 read_position_; + int read_size_; + uint8* read_buffer_; + + // Offsets of the requested first byte and last byte in |buffer_|. They are + // written by VerifyRead(). + int first_offset_; + int last_offset_; + + // Used to ensure mocks for unittests are used instead of reset in Start(). + bool keep_test_loader_; + + DISALLOW_COPY_AND_ASSIGN(BufferedResourceLoader); +}; + +} // namespace webkit_glue + +#endif // WEBKIT_GLUE_MEDIA_BUFFERED_RESOURCE_LOADER_H_ diff --git a/webkit/glue/media/buffered_resource_loader_unittest.cc b/webkit/glue/media/buffered_resource_loader_unittest.cc new file mode 100644 index 0000000..db9b49e --- /dev/null +++ b/webkit/glue/media/buffered_resource_loader_unittest.cc @@ -0,0 +1,486 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <algorithm> + +#include "base/format_macros.h" +#include "base/stringprintf.h" +#include "net/base/net_errors.h" +#include "net/http/http_util.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFrameClient.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLError.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.h" +#include "third_party/WebKit/WebKit/chromium/public/WebView.h" +#include "webkit/glue/media/buffered_resource_loader.h" +#include "webkit/glue/mock_webframe.h" +#include "webkit/glue/mock_weburlloader_impl.h" + +using ::testing::_; +using ::testing::Assign; +using ::testing::AtLeast; +using ::testing::DeleteArg; +using ::testing::DoAll; +using ::testing::InSequence; +using ::testing::Invoke; +using ::testing::InvokeWithoutArgs; +using ::testing::NotNull; +using ::testing::Return; +using ::testing::ReturnRef; +using ::testing::SetArgumentPointee; +using ::testing::StrictMock; +using ::testing::NiceMock; +using ::testing::WithArgs; + +using WebKit::WebURLError; +using WebKit::WebFrameClient; +using WebKit::WebURLResponse; +using WebKit::WebView; + +namespace { + +const char* kHttpUrl = "http://test"; +const int kDataSize = 1024; +const int kHttpOK = 200; +const int kHttpPartialContent = 206; + +enum NetworkState { + NONE, + LOADED, + LOADING +}; + +} // namespace + +namespace webkit_glue { + +// Submit a request completed event to the resource loader due to request +// being canceled. Pretending the event is from external. +ACTION_P(RequestCanceled, loader) { + WebURLError error; + error.reason = net::ERR_ABORTED; + error.domain = WebString::fromUTF8(net::kErrorDomain); + loader->didFail(NULL, error); +} + +class BufferedResourceLoaderTest : public testing::Test { + public: + BufferedResourceLoaderTest() { + url_loader_ = new NiceMock<MockWebURLLoader>(); + + for (int i = 0; i < kDataSize; ++i) + data_[i] = i; + } + + virtual ~BufferedResourceLoaderTest() { + ignore_result(frame_.release()); + } + + void Initialize(const char* url, int first_position, int last_position) { + gurl_ = GURL(url); + first_position_ = first_position; + last_position_ = last_position; + + frame_.reset(new NiceMock<MockWebFrame>()); + + loader_ = new BufferedResourceLoader(gurl_, + first_position_, last_position_); + loader_->SetURLLoaderForTest(url_loader_); + } + + void SetLoaderBuffer(size_t forward_capacity, size_t backward_capacity) { + loader_->buffer_.reset( + new media::SeekableBuffer(backward_capacity, forward_capacity)); + } + + void Start() { + InSequence s; + EXPECT_CALL(*url_loader_, loadAsynchronously(_, loader_.get())); + loader_->Start( + NewCallback(this, &BufferedResourceLoaderTest::StartCallback), + NewCallback(this, &BufferedResourceLoaderTest::NetworkCallback), + frame_.get()); + } + + void FullResponse(int64 instance_size) { + EXPECT_CALL(*this, StartCallback(net::OK)); + + WebURLResponse response(gurl_); + response.setHTTPHeaderField(WebString::fromUTF8("Content-Length"), + WebString::fromUTF8(base::StringPrintf("%" + PRId64, instance_size))); + response.setExpectedContentLength(instance_size); + response.setHTTPStatusCode(kHttpOK); + loader_->didReceiveResponse(url_loader_, response); + EXPECT_EQ(instance_size, loader_->content_length()); + EXPECT_EQ(instance_size, loader_->instance_size()); + EXPECT_FALSE(loader_->partial_response()); + } + + void PartialResponse(int64 first_position, int64 last_position, + int64 instance_size) { + EXPECT_CALL(*this, StartCallback(net::OK)); + int64 content_length = last_position - first_position + 1; + + WebURLResponse response(gurl_); + response.setHTTPHeaderField(WebString::fromUTF8("Content-Range"), + WebString::fromUTF8(base::StringPrintf("bytes " + "%" PRId64 "-%" PRId64 "/%" PRId64, + first_position, + last_position, + instance_size))); + response.setExpectedContentLength(content_length); + response.setHTTPStatusCode(kHttpPartialContent); + loader_->didReceiveResponse(url_loader_, response); + EXPECT_EQ(content_length, loader_->content_length()); + EXPECT_EQ(instance_size, loader_->instance_size()); + EXPECT_TRUE(loader_->partial_response()); + } + + void StopWhenLoad() { + InSequence s; + EXPECT_CALL(*url_loader_, cancel()) + .WillOnce(RequestCanceled(loader_)); + loader_->Stop(); + } + + // Helper method to write to |loader_| from |data_|. + void WriteLoader(int position, int size) { + EXPECT_CALL(*this, NetworkCallback()) + .RetiresOnSaturation(); + loader_->didReceiveData(url_loader_, + reinterpret_cast<char*>(data_ + position), size); + } + + // Helper method to read from |loader_|. + void ReadLoader(int64 position, int size, uint8* buffer) { + loader_->Read(position, size, buffer, + NewCallback(this, &BufferedResourceLoaderTest::ReadCallback)); + } + + // Verifis that data in buffer[0...size] is equal to data_[pos...pos+size]. + void VerifyBuffer(uint8* buffer, int pos, int size) { + EXPECT_EQ(0, memcmp(buffer, data_ + pos, size)); + } + + // Helper method to disallow deferring in |loader_|. + void DisallowLoaderDefer() { + if (loader_->deferred_) { + EXPECT_CALL(*url_loader_, setDefersLoading(false)); + EXPECT_CALL(*this, NetworkCallback()); + } + loader_->SetAllowDefer(false); + } + + // Helper method to allow deferring in |loader_|. + void AllowLoaderDefer() { + loader_->SetAllowDefer(true); + } + + MOCK_METHOD1(StartCallback, void(int error)); + MOCK_METHOD1(ReadCallback, void(int error)); + MOCK_METHOD0(NetworkCallback, void()); + + protected: + GURL gurl_; + int64 first_position_; + int64 last_position_; + + scoped_refptr<BufferedResourceLoader> loader_; + NiceMock<MockWebURLLoader>* url_loader_; + scoped_ptr<NiceMock<MockWebFrame> > frame_; + + uint8 data_[kDataSize]; + + private: + DISALLOW_COPY_AND_ASSIGN(BufferedResourceLoaderTest); +}; + +TEST_F(BufferedResourceLoaderTest, StartStop) { + Initialize(kHttpUrl, -1, -1); + Start(); + StopWhenLoad(); +} + +// Tests that a bad HTTP response is recived, e.g. file not found. +TEST_F(BufferedResourceLoaderTest, BadHttpResponse) { + Initialize(kHttpUrl, -1, -1); + Start(); + + EXPECT_CALL(*this, StartCallback(net::ERR_FAILED)); + EXPECT_CALL(*url_loader_, cancel()) + .WillOnce(RequestCanceled(loader_)); + + WebURLResponse response(gurl_); + response.setHTTPStatusCode(404); + response.setHTTPStatusText("Not Found\n"); + loader_->didReceiveResponse(url_loader_, response); +} + +// Tests that partial content is requested but not fulfilled. +TEST_F(BufferedResourceLoaderTest, NotPartialResponse) { + Initialize(kHttpUrl, 100, -1); + Start(); + FullResponse(1024); + StopWhenLoad(); +} + +// Tests that a 200 response is received. +TEST_F(BufferedResourceLoaderTest, FullResponse) { + Initialize(kHttpUrl, -1, -1); + Start(); + FullResponse(1024); + StopWhenLoad(); +} + +// Tests that a partial content response is received. +TEST_F(BufferedResourceLoaderTest, PartialResponse) { + Initialize(kHttpUrl, 100, 200); + Start(); + PartialResponse(100, 200, 1024); + StopWhenLoad(); +} + +// Tests that an invalid partial response is received. +TEST_F(BufferedResourceLoaderTest, InvalidPartialResponse) { + Initialize(kHttpUrl, 0, 10); + Start(); + + EXPECT_CALL(*this, StartCallback(net::ERR_INVALID_RESPONSE)); + EXPECT_CALL(*url_loader_, cancel()) + .WillOnce(RequestCanceled(loader_)); + + WebURLResponse response(gurl_); + response.setHTTPHeaderField(WebString::fromUTF8("Content-Range"), + WebString::fromUTF8(base::StringPrintf("bytes " + "%d-%d/%d", 1, 10, 1024))); + response.setExpectedContentLength(10); + response.setHTTPStatusCode(kHttpPartialContent); + loader_->didReceiveResponse(url_loader_, response); +} + +// Tests the logic of sliding window for data buffering and reading. +TEST_F(BufferedResourceLoaderTest, BufferAndRead) { + Initialize(kHttpUrl, 10, 29); + Start(); + PartialResponse(10, 29, 30); + + uint8 buffer[10]; + InSequence s; + + // Writes 10 bytes and read them back. + WriteLoader(10, 10); + EXPECT_CALL(*this, ReadCallback(10)); + ReadLoader(10, 10, buffer); + VerifyBuffer(buffer, 10, 10); + + // Writes 10 bytes and read 2 times. + WriteLoader(20, 10); + EXPECT_CALL(*this, ReadCallback(5)); + ReadLoader(20, 5, buffer); + VerifyBuffer(buffer, 20, 5); + EXPECT_CALL(*this, ReadCallback(5)); + ReadLoader(25, 5, buffer); + VerifyBuffer(buffer, 25, 5); + + // Read backward within buffer. + EXPECT_CALL(*this, ReadCallback(10)); + ReadLoader(10, 10, buffer); + VerifyBuffer(buffer, 10, 10); + + // Read backward outside buffer. + EXPECT_CALL(*this, ReadCallback(net::ERR_CACHE_MISS)); + ReadLoader(9, 10, buffer); + + // Response has completed. + EXPECT_CALL(*this, NetworkCallback()); + loader_->didFinishLoading(url_loader_, 0); + + // Try to read 10 from position 25 will just return with 5 bytes. + EXPECT_CALL(*this, ReadCallback(5)); + ReadLoader(25, 10, buffer); + VerifyBuffer(buffer, 25, 5); + + // Try to read outside buffered range after request has completed. + EXPECT_CALL(*this, ReadCallback(net::ERR_CACHE_MISS)); + ReadLoader(5, 10, buffer); + + // Try to read beyond the instance size. + EXPECT_CALL(*this, ReadCallback(0)); + ReadLoader(30, 10, buffer); +} + +TEST_F(BufferedResourceLoaderTest, ReadOutsideBuffer) { + Initialize(kHttpUrl, 10, 0x00FFFFFF); + Start(); + PartialResponse(10, 0x00FFFFFF, 0x01000000); + + uint8 buffer[10]; + InSequence s; + + // Read very far aheard will get a cache miss. + EXPECT_CALL(*this, ReadCallback(net::ERR_CACHE_MISS)); + ReadLoader(0x00FFFFFF, 1, buffer); + + // The following call will not call ReadCallback() because it is waiting for + // data to arrive. + ReadLoader(10, 10, buffer); + + // Writing to loader will fulfill the read request. + EXPECT_CALL(*this, ReadCallback(10)); + WriteLoader(10, 20); + VerifyBuffer(buffer, 10, 10); + + // The following call cannot be fulfilled now. + ReadLoader(25, 10, buffer); + + EXPECT_CALL(*this, ReadCallback(5)); + EXPECT_CALL(*this, NetworkCallback()); + loader_->didFinishLoading(url_loader_, 0); +} + +TEST_F(BufferedResourceLoaderTest, RequestFailedWhenRead) { + Initialize(kHttpUrl, 10, 29); + Start(); + PartialResponse(10, 29, 30); + + uint8 buffer[10]; + InSequence s; + + ReadLoader(10, 10, buffer); + EXPECT_CALL(*this, ReadCallback(net::ERR_FAILED)); + EXPECT_CALL(*this, NetworkCallback()); + WebURLError error; + error.reason = net::ERR_FAILED; + loader_->didFail(url_loader_, error); +} + +// Tests the logic of caching data to disk when media is paused. +TEST_F(BufferedResourceLoaderTest, AllowDefer_NoDataReceived) { + Initialize(kHttpUrl, 10, 99); + SetLoaderBuffer(10, 20); + Start(); + PartialResponse(10, 99, 100); + + // Start in undeferred state, then disallow defer, then allow defer + // without receiving data in between. + DisallowLoaderDefer(); + AllowLoaderDefer(); + StopWhenLoad(); +} + +TEST_F(BufferedResourceLoaderTest, AllowDefer_ReadSameWindow) { + Initialize(kHttpUrl, 10, 99); + SetLoaderBuffer(10, 20); + Start(); + PartialResponse(10, 99, 100); + + uint8 buffer[10]; + + // Start in undeferred state, disallow defer, receive data but don't shift + // buffer window, then allow defer and read. + DisallowLoaderDefer(); + WriteLoader(10, 10); + AllowLoaderDefer(); + + EXPECT_CALL(*this, ReadCallback(10)); + ReadLoader(10, 10, buffer); + VerifyBuffer(buffer, 10, 10); + StopWhenLoad(); +} + +TEST_F(BufferedResourceLoaderTest, AllowDefer_ReadPastWindow) { + Initialize(kHttpUrl, 10, 99); + SetLoaderBuffer(10, 20); + Start(); + PartialResponse(10, 99, 100); + + uint8 buffer[10]; + + // Not deferred, disallow defer, received data and shift buffer window, + // allow defer, then read in area outside of buffer window. + DisallowLoaderDefer(); + WriteLoader(10, 10); + WriteLoader(20, 50); + AllowLoaderDefer(); + + EXPECT_CALL(*this, ReadCallback(net::ERR_CACHE_MISS)); + ReadLoader(10, 10, buffer); + StopWhenLoad(); +} + +TEST_F(BufferedResourceLoaderTest, AllowDefer_DeferredNoDataReceived) { + Initialize(kHttpUrl, 10, 99); + SetLoaderBuffer(10, 20); + Start(); + PartialResponse(10, 99, 100); + + uint8 buffer[10]; + + // Start in deferred state, then disallow defer, receive no data, and + // allow defer and read. + EXPECT_CALL(*url_loader_, setDefersLoading(true)); + EXPECT_CALL(*this, NetworkCallback()); + WriteLoader(10, 40); + + DisallowLoaderDefer(); + AllowLoaderDefer(); + + EXPECT_CALL(*this, ReadCallback(10)); + ReadLoader(20, 10, buffer); + VerifyBuffer(buffer, 20, 10); + StopWhenLoad(); +} + +TEST_F(BufferedResourceLoaderTest, AllowDefer_DeferredReadSameWindow) { + Initialize(kHttpUrl, 10, 99); + SetLoaderBuffer(10, 20); + Start(); + PartialResponse(10, 99, 100); + + uint8 buffer[10]; + + // Start in deferred state, disallow defer, receive data and shift buffer + // window, allow defer, and read in a place that's still in the window. + EXPECT_CALL(*url_loader_, setDefersLoading(true)); + EXPECT_CALL(*this, NetworkCallback()); + WriteLoader(10, 30); + + DisallowLoaderDefer(); + WriteLoader(40, 5); + AllowLoaderDefer(); + + EXPECT_CALL(*this, ReadCallback(10)); + ReadLoader(20, 10, buffer); + VerifyBuffer(buffer, 20, 10); + StopWhenLoad(); +} + +TEST_F(BufferedResourceLoaderTest, AllowDefer_DeferredReadPastWindow) { + Initialize(kHttpUrl, 10, 99); + SetLoaderBuffer(10, 20); + Start(); + PartialResponse(10, 99, 100); + + uint8 buffer[10]; + + // Start in deferred state, disallow defer, receive data and shift buffer + // window, allow defer, and read outside of the buffer window. + EXPECT_CALL(*url_loader_, setDefersLoading(true)); + EXPECT_CALL(*this, NetworkCallback()); + WriteLoader(10, 40); + + DisallowLoaderDefer(); + WriteLoader(50, 20); + WriteLoader(70, 40); + AllowLoaderDefer(); + + EXPECT_CALL(*this, ReadCallback(net::ERR_CACHE_MISS)); + ReadLoader(20, 5, buffer); + StopWhenLoad(); +} +// TODO(hclam): add unit test for defer loading. + +} // namespace webkit_glue + diff --git a/webkit/glue/media/media_resource_loader_bridge_factory.cc b/webkit/glue/media/media_resource_loader_bridge_factory.cc deleted file mode 100644 index 3fb9d65..0000000 --- a/webkit/glue/media/media_resource_loader_bridge_factory.cc +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "webkit/glue/media/media_resource_loader_bridge_factory.h" - -#include "base/format_macros.h" -#include "base/string_util.h" -#include "base/stringprintf.h" - -namespace { - -// A constant for an unknown position. -const int64 kPositionNotSpecified = -1; - -} // namespace - -namespace webkit_glue { - -MediaResourceLoaderBridgeFactory::MediaResourceLoaderBridgeFactory( - const GURL& referrer, - const std::string& frame_origin, - const std::string& main_frame_origin, - int origin_pid, - int appcache_host_id, - int32 routing_id) - : referrer_(referrer), - frame_origin_(frame_origin), - main_frame_origin_(main_frame_origin), - origin_pid_(origin_pid), - appcache_host_id_(appcache_host_id), - routing_id_(routing_id) { -} - -MediaResourceLoaderBridgeFactory::~MediaResourceLoaderBridgeFactory() {} - -ResourceLoaderBridge* MediaResourceLoaderBridgeFactory::CreateBridge( - const GURL& url, - int load_flags, - int64 first_byte_position, - int64 last_byte_position) { - webkit_glue::ResourceLoaderBridge::RequestInfo request_info; - request_info.method = "GET"; - request_info.url = url; - request_info.first_party_for_cookies = url; - request_info.referrer = referrer_; - request_info.frame_origin = frame_origin_; - request_info.main_frame_origin = main_frame_origin_; - request_info.headers = GenerateHeaders(first_byte_position, - last_byte_position); - request_info.load_flags = load_flags; - request_info.requestor_pid = origin_pid_; - request_info.request_type = ResourceType::MEDIA; - request_info.appcache_host_id = appcache_host_id_; - request_info.routing_id = routing_id_; - return webkit_glue::ResourceLoaderBridge::Create(request_info); -} - -MediaResourceLoaderBridgeFactory::MediaResourceLoaderBridgeFactory() {} - -// static -const std::string MediaResourceLoaderBridgeFactory::GenerateHeaders ( - int64 first_byte_position, int64 last_byte_position) { - // Construct the range header. - std::string header; - if (first_byte_position > kPositionNotSpecified && - last_byte_position > kPositionNotSpecified) { - if (first_byte_position <= last_byte_position) { - header = base::StringPrintf("Range: bytes=%" PRId64 "-%" PRId64, - first_byte_position, - last_byte_position); - } - } else if (first_byte_position > kPositionNotSpecified) { - header = base::StringPrintf("Range: bytes=%" PRId64 "-", - first_byte_position); - } else if (last_byte_position > kPositionNotSpecified) { - NOTIMPLEMENTED() << "Suffix range not implemented"; - } - return header; -} - -} // namespace webkit_glue diff --git a/webkit/glue/media/media_resource_loader_bridge_factory.h b/webkit/glue/media/media_resource_loader_bridge_factory.h deleted file mode 100644 index ccacdc6..0000000 --- a/webkit/glue/media/media_resource_loader_bridge_factory.h +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef WEBKIT_GLUE_MEDIA_MEDIA_RESOURCE_LOADER_BRIDGE_FACTORY_H_ -#define WEBKIT_GLUE_MEDIA_MEDIA_RESOURCE_LOADER_BRIDGE_FACTORY_H_ - -#include "base/gtest_prod_util.h" -#include "webkit/glue/resource_loader_bridge.h" - -namespace webkit_glue { - -// A factory used to create a ResourceLoaderBridge for the media player. -// This factory is used also for testing. Testing code can use this class and -// override CreateBridge() to inject a mock ResourceLoaderBridge for code that -// interacts with it, e.g. BufferedDataSource. -class MediaResourceLoaderBridgeFactory { - public: - MediaResourceLoaderBridgeFactory( - const GURL& referrer, - const std::string& frame_origin, - const std::string& main_frame_origin, - int origin_pid, - int appcache_host_id, - int32 routing_id); - - virtual ~MediaResourceLoaderBridgeFactory(); - - // Factory method to create a ResourceLoaderBridge with the following - // parameters: - // |url| - URL of the resource to be loaded. - // |load_flags| - Load flags for this loading. - // |first_byte_position| - First byte position for a range request, -1 if not. - // |last_byte_position| - Last byte position for a range request, -1 if not. - virtual ResourceLoaderBridge* CreateBridge( - const GURL& url, - int load_flags, - int64 first_byte_position, - int64 last_byte_position); - - protected: - // An empty constructor only used by inherited classes. - MediaResourceLoaderBridgeFactory(); - - private: - FRIEND_TEST_ALL_PREFIXES(MediaResourceLoaderBridgeFactoryTest, - GenerateHeaders); - - // Returns a range request header using parameters |first_byte_position| and - // |last_byte_position|. - // Negative numbers other than -1 are not allowed for |first_byte_position| - // and |last_byte_position|. |first_byte_position| should always be less than - // or equal to |last_byte_position| if they are both not -1. - // Here's a list of valid parameters: - // |first_byte_position| |last_byte_position| - // 0 1000 - // 4096 4096 - // 0 -1 - // -1 -1 - // Empty string is returned on invalid parameters. - static const std::string GenerateHeaders(int64 first_byte_position, - int64 last_byte_position); - - GURL first_party_for_cookies_; - GURL referrer_; - std::string frame_origin_; - std::string main_frame_origin_; - std::string headers_; - int origin_pid_; - int appcache_host_id_; - int32 routing_id_; -}; - -} // namespace webkit_glue - -#endif // WEBKIT_GLUE_MEDIA_MEDIA_RESOURCE_LOADER_BRIDGE_FACTORY_H_ diff --git a/webkit/glue/media/media_resource_loader_bridge_factory_unittest.cc b/webkit/glue/media/media_resource_loader_bridge_factory_unittest.cc deleted file mode 100644 index 4c0126b..0000000 --- a/webkit/glue/media/media_resource_loader_bridge_factory_unittest.cc +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/http/http_util.h" -#include "webkit/glue/media/media_resource_loader_bridge_factory.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace webkit_glue { - -TEST(MediaResourceLoaderBridgeFactoryTest, GenerateHeaders) { - static const struct { - const bool success; - const int64 first_byte_position; - const int64 last_byte_position; - } data[] = { - { false, -1, -1 }, - { false, -5, 0 }, - { false, 100, 0 }, - { true, 0, -1 }, - { true, 0, 0 }, - { true, 100, 100 }, - { true, 50, -1 }, - { true, 10000, -1 }, - { true, 50, 100 }, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) { - std::string headers = MediaResourceLoaderBridgeFactory::GenerateHeaders( - data[i].first_byte_position, data[i].last_byte_position); - std::vector<net::HttpByteRange> ranges; - bool ret = net::HttpUtil::ParseRanges(headers, &ranges); - EXPECT_EQ(data[i].success, ret); - if (ret) { - EXPECT_EQ(1u, ranges.size()); - EXPECT_EQ(data[i].first_byte_position, - ranges[0].first_byte_position()); - EXPECT_EQ(data[i].last_byte_position, - ranges[0].last_byte_position()); - } - } -} - -} // namespace webkit_glue diff --git a/webkit/glue/media/mock_media_resource_loader_bridge_factory.h b/webkit/glue/media/mock_media_resource_loader_bridge_factory.h deleted file mode 100644 index 3c0a3ae..0000000 --- a/webkit/glue/media/mock_media_resource_loader_bridge_factory.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef WEBKIT_GLUE_MEDIA_MOCK_MEDIA_RESOURCE_LOADER_BRIDGE_FACTORY_H_ -#define WEBKIT_GLUE_MEDIA_MOCK_MEDIA_RESOURCE_LOADER_BRIDGE_FACTORY_H_ - -#include "testing/gmock/include/gmock/gmock.h" -#include "webkit/glue/media/media_resource_loader_bridge_factory.h" - -namespace webkit_glue { - -class MockMediaResourceLoaderBridgeFactory - : public webkit_glue::MediaResourceLoaderBridgeFactory { - public: - MockMediaResourceLoaderBridgeFactory() { - } - - virtual ~MockMediaResourceLoaderBridgeFactory() { - OnDestroy(); - } - - MOCK_METHOD4(CreateBridge, - webkit_glue::ResourceLoaderBridge*(const GURL& url, - int load_flags, - int64 first_byte_position, - int64 last_byte_position)); - MOCK_METHOD0(OnDestroy, void()); - - private: - DISALLOW_COPY_AND_ASSIGN(MockMediaResourceLoaderBridgeFactory); -}; - -} // namespace webkit_glue - -#endif // WEBKIT_GLUE_MEDIA_MOCK_MEDIA_RESOURCE_LOADER_BRIDGE_FACTORY_H_ diff --git a/webkit/glue/media/simple_data_source.cc b/webkit/glue/media/simple_data_source.cc index fd69a0a..8869e28 100644 --- a/webkit/glue/media/simple_data_source.cc +++ b/webkit/glue/media/simple_data_source.cc @@ -2,28 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "webkit/glue/media/simple_data_source.h" + #include "base/message_loop.h" #include "base/process_util.h" #include "media/base/filter_host.h" -#include "net/base/load_flags.h" #include "net/base/data_url.h" +#include "net/base/load_flags.h" #include "net/url_request/url_request_status.h" #include "third_party/WebKit/WebKit/chromium/public/WebKit.h" #include "third_party/WebKit/WebKit/chromium/public/WebKitClient.h" -#include "webkit/glue/media/simple_data_source.h" #include "webkit/glue/webkit_glue.h" namespace { -const char kHttpScheme[] = "http"; -const char kHttpsScheme[] = "https"; const char kDataScheme[] = "data"; -// A helper method that accepts only HTTP, HTTPS and FILE protocol. -bool IsDataProtocol(const GURL& url) { - return url.SchemeIs(kDataScheme); -} - } // namespace namespace webkit_glue { @@ -233,7 +227,7 @@ void SimpleDataSource::StartTask() { DCHECK_EQ(state_, INITIALIZING); - if (IsDataProtocol(url_)) { + if (url_.SchemeIs(kDataScheme)) { // If this using data protocol, we just need to decode it. std::string mime_type, charset; bool success = net::DataURL::Parse(url_, &mime_type, &charset, &data_); @@ -276,7 +270,7 @@ void SimpleDataSource::DoneInitialization_Locked(bool success) { host()->SetTotalBytes(size_); host()->SetBufferedBytes(size_); // If scheme is file or data, say we are loaded. - host()->SetLoaded(url_.SchemeIsFile() || IsDataProtocol(url_)); + host()->SetLoaded(url_.SchemeIsFile() || url_.SchemeIs(kDataScheme)); } else { host()->SetError(media::PIPELINE_ERROR_NETWORK); } diff --git a/webkit/glue/webkit_glue.gypi b/webkit/glue/webkit_glue.gypi index 1b9aa85..eb5b31b 100644 --- a/webkit/glue/webkit_glue.gypi +++ b/webkit/glue/webkit_glue.gypi @@ -252,8 +252,8 @@ '../plugins/ppapi/var_object_class.h', 'media/buffered_data_source.cc', 'media/buffered_data_source.h', - 'media/media_resource_loader_bridge_factory.cc', - 'media/media_resource_loader_bridge_factory.h', + 'media/buffered_resource_loader.cc', + 'media/buffered_resource_loader.h', 'media/simple_data_source.cc', 'media/simple_data_source.h', 'media/video_renderer_impl.cc', diff --git a/webkit/glue/webmediaplayer_impl.cc b/webkit/glue/webmediaplayer_impl.cc index 13c448e..e13d942 100644 --- a/webkit/glue/webmediaplayer_impl.cc +++ b/webkit/glue/webmediaplayer_impl.cc @@ -24,7 +24,6 @@ #include "third_party/WebKit/WebKit/chromium/public/WebURL.h" #include "third_party/WebKit/WebKit/chromium/public/WebVideoFrame.h" #include "webkit/glue/media/buffered_data_source.h" -#include "webkit/glue/media/media_resource_loader_bridge_factory.h" #include "webkit/glue/media/simple_data_source.h" #include "webkit/glue/media/video_renderer_impl.h" #include "webkit/glue/media/web_video_renderer.h" |