diff options
author | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-02 22:58:29 +0000 |
---|---|---|
committer | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-02 22:58:29 +0000 |
commit | 3967b2db4a911dc106c09b04ff9840653191064c (patch) | |
tree | 1a2ee7aaa71fc21255089bf2c86bcf48239d8a52 /webkit/glue/media | |
parent | 42009f379758c9ebfb7e8e97f0159e2f61a66445 (diff) | |
download | chromium_src-3967b2db4a911dc106c09b04ff9840653191064c.zip chromium_src-3967b2db4a911dc106c09b04ff9840653191064c.tar.gz chromium_src-3967b2db4a911dc106c09b04ff9840653191064c.tar.bz2 |
Refactoring BufferedDataSource to work with WebURLLoader instead of a MediaResourceLoaderBridge.
One thing to notice is that both buffered_data_source_unittest and simple_data_source_unittest need to have a way to inject a MockWebURLLoader into the BufferedResourceLoader and the SimpleDataSource. In order to make sure a new one is not created during a Start(), I introduced the function SetURLLoaderForTest and keep_test_loader flag.
Patch by annacc@chromium.org:
http://codereview.chromium.org/3863002/
BUG=16751
TEST=src/xcodebuild/Debug/test_shell_tests --gtest_filter=Buffered*
src/xcodebuild/Debug/test_shell_tests --gtest_filter=Simple*
src/webkit/tools/layout_tests/run_webkit_tests.sh --debug media
webkit/tools/layout_tests/run_webkit_tests.sh --debug http/tests/media
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@68094 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue/media')
-rw-r--r-- | webkit/glue/media/buffered_data_source.cc | 309 | ||||
-rw-r--r-- | webkit/glue/media/buffered_data_source.h | 107 | ||||
-rw-r--r-- | webkit/glue/media/buffered_data_source_unittest.cc | 227 | ||||
-rw-r--r-- | webkit/glue/media/simple_data_source.cc | 127 | ||||
-rw-r--r-- | webkit/glue/media/simple_data_source.h | 72 | ||||
-rw-r--r-- | webkit/glue/media/simple_data_source_unittest.cc | 95 |
6 files changed, 546 insertions, 391 deletions
diff --git a/webkit/glue/media/buffered_data_source.cc b/webkit/glue/media/buffered_data_source.cc index 29c86ac..75fbe5b 100644 --- a/webkit/glue/media/buffered_data_source.cc +++ b/webkit/glue/media/buffered_data_source.cc @@ -4,19 +4,33 @@ #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 "media/base/filter_host.h" #include "media/base/media_format.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" -#include "net/http/http_response_headers.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"; @@ -70,10 +84,10 @@ bool IsDataProtocol(const GURL& url) { } // namespace namespace webkit_glue { + ///////////////////////////////////////////////////////////////////////////// // BufferedResourceLoader BufferedResourceLoader::BufferedResourceLoader( - webkit_glue::MediaResourceLoaderBridgeFactory* bridge_factory, const GURL& url, int64 first_byte_position, int64 last_byte_position) @@ -83,12 +97,10 @@ BufferedResourceLoader::BufferedResourceLoader( completed_(false), range_requested_(false), partial_response_(false), - bridge_factory_(bridge_factory), url_(url), first_byte_position_(first_byte_position), last_byte_position_(last_byte_position), start_callback_(NULL), - bridge_(NULL), offset_(0), content_length_(kPositionNotSpecified), instance_size_(kPositionNotSpecified), @@ -97,20 +109,24 @@ BufferedResourceLoader::BufferedResourceLoader( read_size_(0), read_buffer_(NULL), first_offset_(0), - last_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) { + NetworkEventCallback* event_callback, + WebFrame* frame) { // Make sure we have not started. - DCHECK(!bridge_.get()); 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); @@ -122,21 +138,26 @@ void BufferedResourceLoader::Start(net::CompletionCallback* start_callback, offset_ = first_byte_position_; } - // Creates the bridge on render thread since we can only access - // ResourceDispatcher on this thread. - bridge_.reset( - bridge_factory_->CreateBridge( - url_, - net::LOAD_NORMAL, - first_byte_position_, - last_byte_position_)); - // Increment the reference count right before we start the request. This // reference will be release when this request has ended. AddRef(); - // And start the resource loading. - bridge_->Start(this); + // Prepare the request. + WebURLRequest request(url_); + request.setHTTPHeaderField(WebString::fromUTF8("Range"), + WebString::fromUTF8(GenerateHeaders( + first_byte_position_, + last_byte_position_))); + frame->setReferrerForRequest(request, WebKit::WebURL()); + // TODO(annacc): we should be using createAssociatedURLLoader() instead? + frame->dispatchWillSendRequest(request); + + // This flag is for unittests as we don't want to reset |url_loader| + if (!keep_test_loader_) + url_loader_.reset(WebKit::webKitClient()->createURLLoader()); + + // Start the resource loading. + url_loader_->loadAsynchronously(request, this); } void BufferedResourceLoader::Stop() { @@ -153,14 +174,15 @@ void BufferedResourceLoader::Stop() { // Destroy internal buffer. buffer_.reset(); - if (bridge_.get()) { - // Cancel the request. This method call will cancel the request - // asynchronously. We may still get data or messages until we receive - // a response completed message. + if (url_loader_.get()) { if (deferred_) - bridge_->SetDefersLoading(false); + url_loader_->setDefersLoading(false); deferred_ = false; - bridge_->Cancel(); + + if (!completed_) { + url_loader_->cancel(); + completed_ = true; + } } } @@ -231,38 +253,47 @@ void BufferedResourceLoader::SetAllowDefer(bool is_allowed) { DisableDeferIfNeeded(); } +void BufferedResourceLoader::SetURLLoaderForTest(WebURLLoader* mock_loader) { + url_loader_.reset(mock_loader); + keep_test_loader_ = true; +} + ///////////////////////////////////////////////////////////////////////////// -// BufferedResourceLoader, -// webkit_glue::ResourceLoaderBridge::Peer implementations -bool BufferedResourceLoader::OnReceivedRedirect( - const GURL& new_url, - const webkit_glue::ResourceResponseInfo& info, - bool* has_new_first_party_for_cookies, - GURL* new_first_party_for_cookies) { - DCHECK(bridge_.get()); - - // Save the new URL. - url_ = new_url; - // TODO(wtc): should we return a new first party for cookies URL? - *has_new_first_party_for_cookies = false; +// 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()) - return true; + if (!start_callback_.get()) { + // Set the url in the request to an invalid value (empty url). + newRequest.setURL(WebKit::WebURL()); + return; + } - if (!IsProtocolSupportedForMedia(new_url)) { + 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 false; + return; } - return true; + + url_ = newRequest.url(); } -void BufferedResourceLoader::OnReceivedResponse( - const webkit_glue::ResourceResponseInfo& info, - bool content_filtered) { - DCHECK(bridge_.get()); +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. @@ -275,23 +306,18 @@ void BufferedResourceLoader::OnReceivedResponse( // response for HTTP and HTTPS protocol. if (IsHttpProtocol(url_)) { int error = net::OK; - if (!info.headers) { - // We expect to receive headers because this is a HTTP or HTTPS protocol, - // if not report failure. - error = net::ERR_INVALID_RESPONSE; - } else { - if (info.headers->response_code() == 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(info)) - error = net::ERR_INVALID_RESPONSE; - } else if (info.headers->response_code() != kHttpOK) { - // We didn't request a range but server didn't reply with "200 OK". - error = net::ERR_FAILED; - } + + 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) { @@ -305,9 +331,9 @@ void BufferedResourceLoader::OnReceivedResponse( partial_response_ = range_requested_; } - // |info.content_length| can be -1, in that case |content_length_| is + // Expected content length can be -1, in that case |content_length_| is // not specified and this is a streaming response. - content_length_ = info.content_length; + content_length_ = response.expectedContentLength(); // If we have not requested a range, then the size of the instance is equal // to the content length. @@ -318,8 +344,12 @@ void BufferedResourceLoader::OnReceivedResponse( DoneStart(net::OK); } -void BufferedResourceLoader::OnReceivedData(const char* data, int len) { - DCHECK(bridge_.get()); +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. @@ -327,7 +357,7 @@ void BufferedResourceLoader::OnReceivedData(const char* data, int len) { return; // Writes more data to |buffer_|. - buffer_->Append(reinterpret_cast<const uint8*>(data), len); + buffer_->Append(reinterpret_cast<const uint8*>(data), data_length); // If there is an active read request, try to fulfill the request. if (HasPendingRead() && CanFulfillRead()) { @@ -350,18 +380,28 @@ void BufferedResourceLoader::OnReceivedData(const char* data, int len) { NotifyNetworkEvent(); } -void BufferedResourceLoader::OnCompletedRequest( - const URLRequestStatus& status, - const std::string& security_info, - const base::Time& completion_time) { - DCHECK(bridge_.get()); +void BufferedResourceLoader::didDownloadData( + WebKit::WebURLLoader* loader, + int dataLength) { + NOTIMPLEMENTED(); +} + +void BufferedResourceLoader::didReceiveCachedMetadata( + WebURLLoader* loader, + const char* data, + int data_length) { + NOTIMPLEMENTED(); +} - // Saves the information that the request has completed. +void BufferedResourceLoader::didFinishLoading( + WebURLLoader* loader, + double finishTime) { + DCHECK(!completed_); completed_ = true; // If there is a start callback, calls it. if (start_callback_.get()) { - DoneStart(status.os_error()); + DoneStart(net::OK); } // If there is a pending read but the request has ended, returns with what @@ -370,16 +410,11 @@ void BufferedResourceLoader::OnCompletedRequest( // Make sure we have a valid buffer before we satisfy a read request. DCHECK(buffer_.get()); - if (status.is_success()) { - // Try to fulfill with what is in the buffer. - if (CanFulfillRead()) - ReadInternal(); - else - DoneRead(net::ERR_CACHE_MISS); - } else { - // If the request has failed, then fail the read. - DoneRead(net::ERR_FAILED); - } + // 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. @@ -388,10 +423,31 @@ void BufferedResourceLoader::OnCompletedRequest( // Notify that network response is completed. NotifyNetworkEvent(); - // We incremented the reference count when the loader was started. We balance - // that reference here so that we get destroyed. This is also the only safe - // place to destroy the ResourceLoaderBridge. - bridge_.reset(); + 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(); } @@ -405,8 +461,8 @@ void BufferedResourceLoader::EnableDeferIfNeeded() { buffer_->forward_bytes() >= buffer_->forward_capacity()) { deferred_ = true; - if (bridge_.get()) - bridge_->SetDefersLoading(true); + if (url_loader_.get()) + url_loader_->setDefersLoading(true); NotifyNetworkEvent(); } @@ -418,8 +474,8 @@ void BufferedResourceLoader::DisableDeferIfNeeded() { buffer_->forward_bytes() < buffer_->forward_capacity() / 2)) { deferred_ = false; - if (bridge_.get()) - bridge_->SetDefersLoading(false); + if (url_loader_.get()) + url_loader_->setDefersLoading(false); NotifyNetworkEvent(); } @@ -480,18 +536,21 @@ void BufferedResourceLoader::ReadInternal() { } bool BufferedResourceLoader::VerifyPartialResponse( - const ResourceResponseInfo& info) { - int64 first_byte_position, last_byte_position, instance_size; - if (!info.headers->GetContentRange(&first_byte_position, - &last_byte_position, - &instance_size)) { + 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) + if (instance_size != kPositionNotSpecified) { instance_size_ = instance_size; + } - if (first_byte_position_ != -1 && + if (first_byte_position_ != kPositionNotSpecified && first_byte_position_ != first_byte_position) { return false; } @@ -501,6 +560,27 @@ bool BufferedResourceLoader::VerifyPartialResponse( 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(); @@ -525,12 +605,12 @@ void BufferedResourceLoader::NotifyNetworkEvent() { // BufferedDataSource BufferedDataSource::BufferedDataSource( MessageLoop* render_loop, - webkit_glue::MediaResourceLoaderBridgeFactory* bridge_factory) + WebFrame* frame) : total_bytes_(kPositionNotSpecified), loaded_(false), streaming_(false), + frame_(frame), single_origin_(true), - bridge_factory_(bridge_factory), loader_(NULL), network_activity_(false), initialize_callback_(NULL), @@ -558,7 +638,7 @@ BufferedResourceLoader* BufferedDataSource::CreateResourceLoader( int64 first_byte_position, int64 last_byte_position) { DCHECK(MessageLoop::current() == render_loop_); - return new BufferedResourceLoader(bridge_factory_.get(), url_, + return new BufferedResourceLoader(url_, first_byte_position, last_byte_position); } @@ -658,12 +738,12 @@ void BufferedDataSource::Abort() { // If we are told to abort, immediately return from any pending read // with an error. if (read_callback_.get()) { - { AutoLock auto_lock(lock_); DoneRead_Locked(net::ERR_FAILED); - } - CleanupTask(); } + + CleanupTask(); + frame_ = NULL; } ///////////////////////////////////////////////////////////////////////////// @@ -690,7 +770,8 @@ void BufferedDataSource::InitializeTask() { loader_ = CreateResourceLoader(0, 1024); loader_->Start( NewCallback(this, &BufferedDataSource::HttpInitialStartCallback), - NewCallback(this, &BufferedDataSource::NetworkEventCallback)); + NewCallback(this, &BufferedDataSource::NetworkEventCallback), + frame_); } else { // For all other protocols, assume they support range request. We fetch // the full range of the resource to obtain the instance size because @@ -698,7 +779,8 @@ void BufferedDataSource::InitializeTask() { loader_ = CreateResourceLoader(-1, -1); loader_->Start( NewCallback(this, &BufferedDataSource::NonHttpInitialStartCallback), - NewCallback(this, &BufferedDataSource::NetworkEventCallback)); + NewCallback(this, &BufferedDataSource::NetworkEventCallback), + frame_); } } @@ -775,7 +857,8 @@ void BufferedDataSource::RestartLoadingTask() { loader_->SetAllowDefer(!media_is_paused_); loader_->Start( NewCallback(this, &BufferedDataSource::PartialReadStartCallback), - NewCallback(this, &BufferedDataSource::NetworkEventCallback)); + NewCallback(this, &BufferedDataSource::NetworkEventCallback), + frame_); } void BufferedDataSource::WatchDogTask() { @@ -806,7 +889,8 @@ void BufferedDataSource::WatchDogTask() { loader_->SetAllowDefer(!media_is_paused_); loader_->Start( NewCallback(this, &BufferedDataSource::PartialReadStartCallback), - NewCallback(this, &BufferedDataSource::NetworkEventCallback)); + NewCallback(this, &BufferedDataSource::NetworkEventCallback), + frame_); } void BufferedDataSource::SetPlaybackRateTask(float playback_rate) { @@ -829,7 +913,7 @@ void BufferedDataSource::SetPlaybackRateTask(float playback_rate) { // prior to make this method call. void BufferedDataSource::ReadInternal() { DCHECK(MessageLoop::current() == render_loop_); - DCHECK(loader_.get()); + DCHECK(loader_); // First we prepare the intermediate read buffer for BufferedResourceLoader // to write to. @@ -904,7 +988,8 @@ void BufferedDataSource::HttpInitialStartCallback(int error) { loader_ = CreateResourceLoader(-1, -1); loader_->Start( NewCallback(this, &BufferedDataSource::HttpInitialStartCallback), - NewCallback(this, &BufferedDataSource::NetworkEventCallback)); + NewCallback(this, &BufferedDataSource::NetworkEventCallback), + frame_); return; } diff --git a/webkit/glue/media/buffered_data_source.h b/webkit/glue/media/buffered_data_source.h index 2af9e84..674d5f4 100644 --- a/webkit/glue/media/buffered_data_source.h +++ b/webkit/glue/media/buffered_data_source.h @@ -19,33 +19,38 @@ #include "media/base/seekable_buffer.h" #include "net/base/completion_callback.h" #include "net/base/file_stream.h" -#include "webkit/glue/media/media_resource_loader_bridge_factory.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; +} + namespace webkit_glue { + ///////////////////////////////////////////////////////////////////////////// // BufferedResourceLoader // This class works inside demuxer thread and render thread. It contains a -// resource loader bridge 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. +// 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_glue::ResourceLoaderBridge::Peer { + public WebKit::WebURLLoaderClient { public: typedef Callback0::Type NetworkEventCallback; - // |bridge_factory| - Factory to create a ResourceLoaderBridge. // |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( - webkit_glue::MediaResourceLoaderBridgeFactory* bridge_factory, - const GURL& url, - int64 first_byte_position, - int64 last_byte_position); + 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 @@ -62,7 +67,8 @@ class BufferedResourceLoader : // |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); + NetworkEventCallback* event_callback, + WebKit::WebFrame* frame); // Stop this loader, cancels and request and release internal buffer. virtual void Stop(); @@ -109,23 +115,38 @@ class BufferedResourceLoader : // Returns resulting URL. virtual const GURL& url() { return url_; } + // Used to inject a mock used for unittests. + virtual void SetURLLoaderForTest(WebKit::WebURLLoader* mock_loader); + ///////////////////////////////////////////////////////////////////////////// - // webkit_glue::ResourceLoaderBridge::Peer implementations. - virtual void OnUploadProgress(uint64 position, uint64 size) {} - virtual bool OnReceivedRedirect( - const GURL& new_url, - const webkit_glue::ResourceResponseInfo& info, - bool* has_new_first_party_for_cookies, - GURL* new_first_party_for_cookies); - virtual void OnReceivedResponse( - const webkit_glue::ResourceResponseInfo& info, - bool content_filtered); - virtual void OnDownloadedData(int len) {} - virtual void OnReceivedData(const char* data, int len); - virtual void OnCompletedRequest( - const URLRequestStatus& status, - const std::string& security_info, - const base::Time& completion_time); + // 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>; @@ -153,7 +174,16 @@ class BufferedResourceLoader : void ReadInternal(); // If we have made a range request, verify the response from the server. - bool VerifyPartialResponse(const ResourceResponseInfo& info); + 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. @@ -185,7 +215,9 @@ class BufferedResourceLoader : // True if response data received is a partial range. bool partial_response_; - webkit_glue::MediaResourceLoaderBridgeFactory* bridge_factory_; + // 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_; @@ -195,7 +227,6 @@ class BufferedResourceLoader : // Members used during request start. scoped_ptr<net::CompletionCallback> start_callback_; - scoped_ptr<webkit_glue::ResourceLoaderBridge> bridge_; int64 offset_; int64 content_length_; int64 instance_size_; @@ -212,14 +243,16 @@ class BufferedResourceLoader : 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, - webkit_glue::MediaResourceLoaderBridgeFactory* bridge_factory); + BufferedDataSource(MessageLoop* render_loop, + WebKit::WebFrame* frame); virtual ~BufferedDataSource(); @@ -338,12 +371,12 @@ class BufferedDataSource : public WebDataSource { // i.e. range request is not supported. bool streaming_; + // A webframe for loading. + WebKit::WebFrame* frame_; + // True if the media resource has a single origin. bool single_origin_; - // A factory object to produce ResourceLoaderBridge. - scoped_ptr<webkit_glue::MediaResourceLoaderBridgeFactory> bridge_factory_; - // A resource loader for the media resource. scoped_refptr<BufferedResourceLoader> loader_; diff --git a/webkit/glue/media/buffered_data_source_unittest.cc b/webkit/glue/media/buffered_data_source_unittest.cc index 81103b2..5fad3a4 100644 --- a/webkit/glue/media/buffered_data_source_unittest.cc +++ b/webkit/glue/media/buffered_data_source_unittest.cc @@ -13,13 +13,21 @@ #include "media/base/mock_filter_host.h" #include "media/base/mock_filters.h" #include "net/base/net_errors.h" -#include "net/http/http_response_headers.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/media/mock_media_resource_loader_bridge_factory.h" -#include "webkit/glue/mock_resource_loader_bridge.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; @@ -33,11 +41,22 @@ 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, @@ -52,25 +71,23 @@ 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) { - URLRequestStatus status; - status.set_status(URLRequestStatus::CANCELED); - status.set_os_error(net::ERR_ABORTED); - loader->OnCompletedRequest(status, "", base::Time()); + WebURLError error; + error.reason = net::ERR_ABORTED; + error.domain = WebString::fromUTF8(net::kErrorDomain); + loader->didFail(NULL, error); } class BufferedResourceLoaderTest : public testing::Test { public: BufferedResourceLoaderTest() { - bridge_.reset(new StrictMock<MockResourceLoaderBridge>()); + url_loader_ = new NiceMock<MockWebURLLoader>(); for (int i = 0; i < kDataSize; ++i) data_[i] = i; } - ~BufferedResourceLoaderTest() { - if (bridge_.get()) - EXPECT_CALL(*bridge_, OnDestroy()); - EXPECT_CALL(bridge_factory_, OnDestroy()); + virtual ~BufferedResourceLoaderTest() { + ignore_result(frame_.release()); } void Initialize(const char* url, int first_position, int last_position) { @@ -78,8 +95,11 @@ class BufferedResourceLoaderTest : public testing::Test { first_position_ = first_position; last_position_ = last_position; - loader_ = new BufferedResourceLoader(&bridge_factory_, gurl_, + 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) { @@ -89,25 +109,23 @@ class BufferedResourceLoaderTest : public testing::Test { void Start() { InSequence s; - EXPECT_CALL(bridge_factory_, - CreateBridge(gurl_, _, first_position_, last_position_)) - .WillOnce(Return(bridge_.get())); - EXPECT_CALL(*bridge_, Start(loader_.get())); + EXPECT_CALL(*url_loader_, loadAsynchronously(_, loader_.get())); loader_->Start( NewCallback(this, &BufferedResourceLoaderTest::StartCallback), - NewCallback(this, &BufferedResourceLoaderTest::NetworkCallback)); + NewCallback(this, &BufferedResourceLoaderTest::NetworkCallback), + frame_.get()); } void FullResponse(int64 instance_size) { EXPECT_CALL(*this, StartCallback(net::OK)); - ResourceResponseInfo info; - std::string header = base::StringPrintf("HTTP/1.1 200 OK\n" - "Content-Length: %" PRId64, - instance_size); - replace(header.begin(), header.end(), '\n', '\0'); - info.headers = new net::HttpResponseHeaders(header); - info.content_length = instance_size; - loader_->OnReceivedResponse(info, false); + + 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()); @@ -117,17 +135,17 @@ class BufferedResourceLoaderTest : public testing::Test { int64 instance_size) { EXPECT_CALL(*this, StartCallback(net::OK)); int64 content_length = last_position - first_position + 1; - ResourceResponseInfo info; - std::string header = base::StringPrintf("HTTP/1.1 206 Partial Content\n" - "Content-Range: bytes " + + WebURLResponse response(gurl_); + response.setHTTPHeaderField(WebString::fromUTF8("Content-Range"), + WebString::fromUTF8(base::StringPrintf("bytes " "%" PRId64 "-%" PRId64 "/%" PRId64, first_position, last_position, - instance_size); - replace(header.begin(), header.end(), '\n', '\0'); - info.headers = new net::HttpResponseHeaders(header); - info.content_length = content_length; - loader_->OnReceivedResponse(info, false); + 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()); @@ -135,22 +153,17 @@ class BufferedResourceLoaderTest : public testing::Test { void StopWhenLoad() { InSequence s; - EXPECT_CALL(*bridge_, Cancel()) + EXPECT_CALL(*url_loader_, cancel()) .WillOnce(RequestCanceled(loader_)); - EXPECT_CALL(*bridge_, OnDestroy()) - .WillOnce(Invoke(this, &BufferedResourceLoaderTest::ReleaseBridge)); loader_->Stop(); } - void ReleaseBridge() { - ignore_result(bridge_.release()); - } - // Helper method to write to |loader_| from |data_|. void WriteLoader(int position, int size) { EXPECT_CALL(*this, NetworkCallback()) .RetiresOnSaturation(); - loader_->OnReceivedData(reinterpret_cast<char*>(data_ + position), size); + loader_->didReceiveData(url_loader_, + reinterpret_cast<char*>(data_ + position), size); } // Helper method to read from |loader_|. @@ -167,7 +180,7 @@ class BufferedResourceLoaderTest : public testing::Test { // Helper method to disallow deferring in |loader_|. void DisallowLoaderDefer() { if (loader_->deferred_) { - EXPECT_CALL(*bridge_, SetDefersLoading(false)); + EXPECT_CALL(*url_loader_, setDefersLoading(false)); EXPECT_CALL(*this, NetworkCallback()); } loader_->SetAllowDefer(false); @@ -188,8 +201,8 @@ class BufferedResourceLoaderTest : public testing::Test { int64 last_position_; scoped_refptr<BufferedResourceLoader> loader_; - StrictMock<MockMediaResourceLoaderBridgeFactory> bridge_factory_; - scoped_ptr<StrictMock<MockResourceLoaderBridge> > bridge_; + NiceMock<MockWebURLLoader>* url_loader_; + scoped_ptr<NiceMock<MockWebFrame> > frame_; uint8 data_[kDataSize]; @@ -203,35 +216,19 @@ TEST_F(BufferedResourceLoaderTest, StartStop) { StopWhenLoad(); } -// Tests that HTTP header is missing in the response. -TEST_F(BufferedResourceLoaderTest, MissingHttpHeader) { - Initialize(kHttpUrl, -1, -1); - Start(); - - EXPECT_CALL(*this, StartCallback(net::ERR_INVALID_RESPONSE)); - EXPECT_CALL(*bridge_, Cancel()) - .WillOnce(RequestCanceled(loader_)); - EXPECT_CALL(*bridge_, OnDestroy()) - .WillOnce(Invoke(this, &BufferedResourceLoaderTest::ReleaseBridge)); - - ResourceResponseInfo info; - loader_->OnReceivedResponse(info, false); -} - // 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(*bridge_, Cancel()) + EXPECT_CALL(*url_loader_, cancel()) .WillOnce(RequestCanceled(loader_)); - EXPECT_CALL(*bridge_, OnDestroy()) - .WillOnce(Invoke(this, &BufferedResourceLoaderTest::ReleaseBridge)); - ResourceResponseInfo info; - info.headers = new net::HttpResponseHeaders("HTTP/1.1 404 Not Found\n"); - loader_->OnReceivedResponse(info, false); + 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. @@ -264,19 +261,16 @@ TEST_F(BufferedResourceLoaderTest, InvalidPartialResponse) { Start(); EXPECT_CALL(*this, StartCallback(net::ERR_INVALID_RESPONSE)); - EXPECT_CALL(*bridge_, Cancel()) + EXPECT_CALL(*url_loader_, cancel()) .WillOnce(RequestCanceled(loader_)); - EXPECT_CALL(*bridge_, OnDestroy()) - .WillOnce(Invoke(this, &BufferedResourceLoaderTest::ReleaseBridge)); - - ResourceResponseInfo info; - std::string header = base::StringPrintf("HTTP/1.1 206 Partial Content\n" - "Content-Range: bytes %d-%d/%d", - 1, 10, 1024); - replace(header.begin(), header.end(), '\n', '\0'); - info.headers = new net::HttpResponseHeaders(header); - info.content_length = 10; - loader_->OnReceivedResponse(info, false); + + 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. @@ -314,11 +308,7 @@ TEST_F(BufferedResourceLoaderTest, BufferAndRead) { // Response has completed. EXPECT_CALL(*this, NetworkCallback()); - EXPECT_CALL(*bridge_, OnDestroy()) - .WillOnce(Invoke(this, &BufferedResourceLoaderTest::ReleaseBridge)); - URLRequestStatus status; - status.set_status(URLRequestStatus::SUCCESS); - loader_->OnCompletedRequest(status, "", base::Time()); + loader_->didFinishLoading(url_loader_, 0); // Try to read 10 from position 25 will just return with 5 bytes. EXPECT_CALL(*this, ReadCallback(5)); @@ -360,11 +350,7 @@ TEST_F(BufferedResourceLoaderTest, ReadOutsideBuffer) { EXPECT_CALL(*this, ReadCallback(5)); EXPECT_CALL(*this, NetworkCallback()); - EXPECT_CALL(*bridge_, OnDestroy()) - .WillOnce(Invoke(this, &BufferedResourceLoaderTest::ReleaseBridge)); - URLRequestStatus status; - status.set_status(URLRequestStatus::SUCCESS); - loader_->OnCompletedRequest(status, "", base::Time()); + loader_->didFinishLoading(url_loader_, 0); } TEST_F(BufferedResourceLoaderTest, RequestFailedWhenRead) { @@ -378,11 +364,9 @@ TEST_F(BufferedResourceLoaderTest, RequestFailedWhenRead) { ReadLoader(10, 10, buffer); EXPECT_CALL(*this, ReadCallback(net::ERR_FAILED)); EXPECT_CALL(*this, NetworkCallback()); - EXPECT_CALL(*bridge_, OnDestroy()) - .WillOnce(Invoke(this, &BufferedResourceLoaderTest::ReleaseBridge)); - URLRequestStatus status; - status.set_status(URLRequestStatus::FAILED); - loader_->OnCompletedRequest(status, "", base::Time()); + WebURLError error; + error.reason = net::ERR_FAILED; + loader_->didFail(url_loader_, error); } // Tests the logic of caching data to disk when media is paused. @@ -449,7 +433,7 @@ TEST_F(BufferedResourceLoaderTest, AllowDefer_DeferredNoDataReceived) { // Start in deferred state, then disallow defer, receive no data, and // allow defer and read. - EXPECT_CALL(*bridge_, SetDefersLoading(true)); + EXPECT_CALL(*url_loader_, setDefersLoading(true)); EXPECT_CALL(*this, NetworkCallback()); WriteLoader(10, 40); @@ -472,7 +456,7 @@ TEST_F(BufferedResourceLoaderTest, AllowDefer_DeferredReadSameWindow) { // 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(*bridge_, SetDefersLoading(true)); + EXPECT_CALL(*url_loader_, setDefersLoading(true)); EXPECT_CALL(*this, NetworkCallback()); WriteLoader(10, 30); @@ -496,7 +480,7 @@ TEST_F(BufferedResourceLoaderTest, AllowDefer_DeferredReadPastWindow) { // Start in deferred state, disallow defer, receive data and shift buffer // window, allow defer, and read outside of the buffer window. - EXPECT_CALL(*bridge_, SetDefersLoading(true)); + EXPECT_CALL(*url_loader_, setDefersLoading(true)); EXPECT_CALL(*this, NetworkCallback()); WriteLoader(10, 40); @@ -509,16 +493,16 @@ TEST_F(BufferedResourceLoaderTest, AllowDefer_DeferredReadPastWindow) { ReadLoader(20, 5, buffer); StopWhenLoad(); } - // TODO(hclam): add unit test for defer loading. class MockBufferedResourceLoader : public BufferedResourceLoader { public: - MockBufferedResourceLoader() : BufferedResourceLoader(NULL, GURL(), 0, 0) { + MockBufferedResourceLoader() : BufferedResourceLoader(GURL(), 0, 0) { } - MOCK_METHOD2(Start, void(net::CompletionCallback* read_callback, - NetworkEventCallback* network_callback)); + MOCK_METHOD3(Start, void(net::CompletionCallback* read_callback, + NetworkEventCallback* network_callback, + WebFrame* frame)); MOCK_METHOD0(Stop, void()); MOCK_METHOD4(Read, void(int64 position, int read_size, uint8* buffer, net::CompletionCallback* callback)); @@ -541,8 +525,8 @@ class MockBufferedResourceLoader : public BufferedResourceLoader { class MockBufferedDataSource : public BufferedDataSource { public: MockBufferedDataSource( - MessageLoop* message_loop, MediaResourceLoaderBridgeFactory* factory) - : BufferedDataSource(message_loop, factory) { + MessageLoop* message_loop, WebFrame* frame) + : BufferedDataSource(message_loop, frame) { } virtual base::TimeDelta GetTimeoutMilliseconds() { @@ -561,8 +545,6 @@ class BufferedDataSourceTest : public testing::Test { public: BufferedDataSourceTest() { message_loop_ = MessageLoop::current(); - bridge_factory_.reset( - new StrictMock<MockMediaResourceLoaderBridgeFactory>()); // Prepare test data. for (size_t i = 0; i < sizeof(data_); ++i) { @@ -571,20 +553,14 @@ class BufferedDataSourceTest : public testing::Test { } virtual ~BufferedDataSourceTest() { - if (data_source_) { - // Release the bridge factory because we don't own it. - // Expects bridge factory to be destroyed along with data source. - EXPECT_CALL(*bridge_factory_, OnDestroy()) - .WillOnce(Invoke(this, - &BufferedDataSourceTest::ReleaseBridgeFactory)); - } + ignore_result(frame_.release()); } void ExpectCreateAndStartResourceLoader(int start_error) { EXPECT_CALL(*data_source_, CreateResourceLoader(_, _)) .WillOnce(Return(loader_.get())); - EXPECT_CALL(*loader_, Start(NotNull(), NotNull())) + EXPECT_CALL(*loader_, Start(NotNull(), NotNull(), NotNull())) .WillOnce( DoAll(Assign(&error_, start_error), Invoke(this, @@ -597,15 +573,10 @@ class BufferedDataSourceTest : public testing::Test { // Saves the url first. gurl_ = GURL(url); - media::MediaFormat url_format; - url_format.SetAsString(media::MediaFormat::kMimeType, - media::mime_type::kURL); - url_format.SetAsString(media::MediaFormat::kURL, url); - data_source_ = new MockBufferedDataSource(MessageLoop::current(), - bridge_factory_.get()); - CHECK(data_source_); + frame_.reset(new NiceMock<MockWebFrame>()); - // There is no need to provide a message loop to data source. + data_source_ = new MockBufferedDataSource(MessageLoop::current(), + frame_.get()); data_source_->set_host(&host_); scoped_refptr<NiceMock<MockBufferedResourceLoader> > first_loader( @@ -631,7 +602,7 @@ class BufferedDataSourceTest : public testing::Test { // Replace loader_ with a new instance. loader_ = new NiceMock<MockBufferedResourceLoader>(); - // Create and start Make sure Start() is called the new loader. + // Create and start. Make sure Start() is called on the new loader. ExpectCreateAndStartResourceLoader(net::OK); // Update initialization variable since we know the second loader will @@ -705,13 +676,10 @@ class BufferedDataSourceTest : public testing::Test { message_loop_->RunAllPending(); } - void ReleaseBridgeFactory() { - ignore_result(bridge_factory_.release()); - } - void InvokeStartCallback( net::CompletionCallback* callback, - BufferedResourceLoader::NetworkEventCallback* network_callback) { + BufferedResourceLoader::NetworkEventCallback* network_callback, + WebFrame* frame) { callback->RunWithParams(Tuple1<int>(error_)); delete callback; // TODO(hclam): Save this callback. @@ -790,7 +758,7 @@ class BufferedDataSourceTest : public testing::Test { .WillOnce(Return(new_loader)); // 3. Then the new loader will be started. - EXPECT_CALL(*new_loader, Start(NotNull(), NotNull())) + EXPECT_CALL(*new_loader, Start(NotNull(), NotNull(), NotNull())) .WillOnce(DoAll(Assign(&error_, net::OK), Invoke(this, &BufferedDataSourceTest::InvokeStartCallback))); @@ -856,7 +824,7 @@ class BufferedDataSourceTest : public testing::Test { // 3. Then the new loader will be started and respond to queries about // whether this is a partial response using the value of the previous // loader. - EXPECT_CALL(*new_loader, Start(NotNull(), NotNull())) + EXPECT_CALL(*new_loader, Start(NotNull(), NotNull(), NotNull())) .WillOnce(DoAll(Assign(&error_, net::OK), Invoke(this, &BufferedDataSourceTest::InvokeStartCallback))); @@ -889,10 +857,9 @@ class BufferedDataSourceTest : public testing::Test { MOCK_METHOD1(ReadCallback, void(size_t size)); - scoped_ptr<StrictMock<MockMediaResourceLoaderBridgeFactory> > - bridge_factory_; scoped_refptr<NiceMock<MockBufferedResourceLoader> > loader_; scoped_refptr<MockBufferedDataSource> data_source_; + scoped_ptr<NiceMock<MockWebFrame> > frame_; StrictMock<media::MockFilterHost> host_; GURL gurl_; diff --git a/webkit/glue/media/simple_data_source.cc b/webkit/glue/media/simple_data_source.cc index 291928e..97a9c39 100644 --- a/webkit/glue/media/simple_data_source.cc +++ b/webkit/glue/media/simple_data_source.cc @@ -7,10 +7,10 @@ #include "media/base/filter_host.h" #include "net/base/load_flags.h" #include "net/base/data_url.h" -#include "net/http/http_response_headers.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/resource_loader_bridge.h" #include "webkit/glue/webkit_glue.h" namespace { @@ -30,12 +30,13 @@ namespace webkit_glue { SimpleDataSource::SimpleDataSource( MessageLoop* render_loop, - webkit_glue::MediaResourceLoaderBridgeFactory* bridge_factory) + WebKit::WebFrame* frame) : render_loop_(render_loop), - bridge_factory_(bridge_factory), + frame_(frame), size_(-1), single_origin_(true), - state_(UNINITIALIZED) { + state_(UNINITIALIZED), + keep_test_loader_(false) { DCHECK(render_loop); } @@ -108,34 +109,81 @@ bool SimpleDataSource::IsStreaming() { return false; } -bool SimpleDataSource::OnReceivedRedirect( - const GURL& new_url, - const webkit_glue::ResourceResponseInfo& info, - bool* has_new_first_party_for_cookies, - GURL* new_first_party_for_cookies) { +void SimpleDataSource::SetURLLoaderForTest(WebKit::WebURLLoader* mock_loader) { + url_loader_.reset(mock_loader); + keep_test_loader_ = true; +} + +void SimpleDataSource::willSendRequest( + WebKit::WebURLLoader* loader, + WebKit::WebURLRequest& newRequest, + const WebKit::WebURLResponse& redirectResponse) { DCHECK(MessageLoop::current() == render_loop_); - single_origin_ = url_.GetOrigin() == new_url.GetOrigin(); + single_origin_ = url_.GetOrigin() == GURL(newRequest.url()).GetOrigin(); - // TODO(wtc): should we return a new first party for cookies URL? - *has_new_first_party_for_cookies = false; - return true; + url_ = newRequest.url(); } -void SimpleDataSource::OnReceivedResponse( - const webkit_glue::ResourceResponseInfo& info, - bool content_filtered) { +void SimpleDataSource::didSendData( + WebKit::WebURLLoader* loader, + unsigned long long bytesSent, + unsigned long long totalBytesToBeSent) { + NOTIMPLEMENTED(); +} + +void SimpleDataSource::didReceiveResponse( + WebKit::WebURLLoader* loader, + const WebKit::WebURLResponse& response) { DCHECK(MessageLoop::current() == render_loop_); - size_ = info.content_length; + size_ = response.expectedContentLength(); +} + +void SimpleDataSource::didDownloadData( + WebKit::WebURLLoader* loader, + int dataLength) { + NOTIMPLEMENTED(); } -void SimpleDataSource::OnReceivedData(const char* data, int len) { +void SimpleDataSource::didReceiveData( + WebKit::WebURLLoader* loader, + const char* data, + int data_length) { DCHECK(MessageLoop::current() == render_loop_); - data_.append(data, len); + data_.append(data, data_length); +} + +void SimpleDataSource::didReceiveCachedMetadata( + WebKit::WebURLLoader* loader, + const char* data, + int dataLength) { + NOTIMPLEMENTED(); +} + +void SimpleDataSource::didFinishLoading( + WebKit::WebURLLoader* loader, + double finishTime) { + DCHECK(MessageLoop::current() == render_loop_); + AutoLock auto_lock(lock_); + // It's possible this gets called after Stop(), in which case |host_| is no + // longer valid. + if (state_ == STOPPED) + return; + + // Otherwise we should be initializing and have created a WebURLLoader. + DCHECK_EQ(state_, INITIALIZING); + + // If we don't get a content length or the request has failed, report it + // as a network error. + if (size_ == -1) + size_ = data_.length(); + DCHECK(static_cast<size_t>(size_) == data_.length()); + + DoneInitialization_Locked(true); } -void SimpleDataSource::OnCompletedRequest(const URLRequestStatus& status, - const std::string& security_info, - const base::Time& completion_time) { +void SimpleDataSource::didFail( + WebKit::WebURLLoader* loader, + const WebKit::WebURLError& error) { DCHECK(MessageLoop::current() == render_loop_); AutoLock auto_lock(lock_); // It's possible this gets called after Stop(), in which case |host_| is no @@ -143,10 +191,8 @@ void SimpleDataSource::OnCompletedRequest(const URLRequestStatus& status, if (state_ == STOPPED) return; - // Otherwise we should be initializing and have created a bridge. + // Otherwise we should be initializing and have created a WebURLLoader. DCHECK_EQ(state_, INITIALIZING); - DCHECK(bridge_.get()); - bridge_.reset(); // If we don't get a content length or the request has failed, report it // as a network error. @@ -154,7 +200,7 @@ void SimpleDataSource::OnCompletedRequest(const URLRequestStatus& status, size_ = data_.length(); DCHECK(static_cast<size_t>(size_) == data_.length()); - DoneInitialization_Locked(status.is_success()); + DoneInitialization_Locked(false); } bool SimpleDataSource::HasSingleOrigin() { @@ -164,7 +210,7 @@ bool SimpleDataSource::HasSingleOrigin() { void SimpleDataSource::Abort() { DCHECK(MessageLoop::current() == render_loop_); - NOTIMPLEMENTED(); + frame_ = NULL; } void SimpleDataSource::SetURL(const GURL& url) { @@ -183,6 +229,8 @@ void SimpleDataSource::StartTask() { if (state_ == STOPPED) return; + CHECK(frame_); + DCHECK_EQ(state_, INITIALIZING); if (IsDataProtocol(url_)) { @@ -194,10 +242,19 @@ void SimpleDataSource::StartTask() { size_ = data_.length(); DoneInitialization_Locked(success); } else { - // Create our bridge and start loading the resource. - bridge_.reset(bridge_factory_->CreateBridge( - url_, net::LOAD_BYPASS_CACHE, -1, -1)); - bridge_->Start(this); + // Prepare the request. + WebKit::WebURLRequest request(url_); + + frame_->setReferrerForRequest(request, WebKit::WebURL()); + // TODO(annacc): we should be using createAssociatedURLLoader() instead? + frame_->dispatchWillSendRequest(request); + + // This flag is for unittests as we don't want to reset |url_loader| + if (!keep_test_loader_) + url_loader_.reset(WebKit::webKitClient()->createURLLoader()); + + // Start the resource loading. + url_loader_->loadAsynchronously(request, this); } } @@ -207,9 +264,9 @@ void SimpleDataSource::CancelTask() { DCHECK_EQ(state_, STOPPED); // Cancel any pending requests. - if (bridge_.get()) { - bridge_->Cancel(); - bridge_.reset(); + if (url_loader_.get()) { + url_loader_->cancel(); + url_loader_.reset(); } } diff --git a/webkit/glue/media/simple_data_source.h b/webkit/glue/media/simple_data_source.h index ff1e247..4cfc989 100644 --- a/webkit/glue/media/simple_data_source.h +++ b/webkit/glue/media/simple_data_source.h @@ -10,10 +10,17 @@ #ifndef WEBKIT_GLUE_MEDIA_SIMPLE_DATA_SOURCE_H_ #define WEBKIT_GLUE_MEDIA_SIMPLE_DATA_SOURCE_H_ +#include <algorithm> +#include <string> + #include "base/message_loop.h" #include "base/scoped_ptr.h" #include "media/base/filters.h" -#include "webkit/glue/media/media_resource_loader_bridge_factory.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 "third_party/WebKit/WebKit/chromium/public/WebURLResponse.h" #include "webkit/glue/media/web_data_source.h" class MessageLoop; @@ -22,11 +29,9 @@ class WebMediaPlayerDelegateImpl; namespace webkit_glue { class SimpleDataSource : public WebDataSource, - public webkit_glue::ResourceLoaderBridge::Peer { + public WebKit::WebURLLoaderClient { public: - SimpleDataSource( - MessageLoop* render_loop, - webkit_glue::MediaResourceLoaderBridgeFactory* bridge_factory); + SimpleDataSource(MessageLoop* render_loop, WebKit::WebFrame* frame); virtual ~SimpleDataSource(); // MediaFilter implementation. @@ -41,21 +46,37 @@ class SimpleDataSource : public WebDataSource, virtual bool GetSize(int64* size_out); virtual bool IsStreaming(); - // webkit_glue::ResourceLoaderBridge::Peer implementation. - virtual void OnUploadProgress(uint64 position, uint64 size) {} - virtual bool OnReceivedRedirect( - const GURL& new_url, - const webkit_glue::ResourceResponseInfo& info, - bool* has_new_first_party_for_cookies, - GURL* new_first_party_for_cookies); - virtual void OnReceivedResponse( - const webkit_glue::ResourceResponseInfo& info, - bool content_filtered); - virtual void OnDownloadedData(int len) {} - virtual void OnReceivedData(const char* data, int len); - virtual void OnCompletedRequest(const URLRequestStatus& status, - const std::string& security_info, - const base::Time& completion_time); + // 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&); // webkit_glue::WebDataSource implementation. virtual bool HasSingleOrigin(); @@ -77,11 +98,11 @@ class SimpleDataSource : public WebDataSource, // Primarily used for asserting the bridge is loading on the render thread. MessageLoop* render_loop_; - // Factory to create a bridge. - scoped_ptr<webkit_glue::MediaResourceLoaderBridgeFactory> bridge_factory_; + // A webframe for loading. + WebKit::WebFrame* frame_; - // Bridge used to load the media resource. - scoped_ptr<webkit_glue::ResourceLoaderBridge> bridge_; + // Does the work of loading and sends data back to this client. + scoped_ptr<WebKit::WebURLLoader> url_loader_; media::MediaFormat media_format_; GURL url_; @@ -104,6 +125,9 @@ class SimpleDataSource : public WebDataSource, // Filter callbacks. scoped_ptr<media::FilterCallback> initialize_callback_; + // Used to ensure mocks for unittests are used instead of reset in Start(). + bool keep_test_loader_; + DISALLOW_COPY_AND_ASSIGN(SimpleDataSource); }; diff --git a/webkit/glue/media/simple_data_source_unittest.cc b/webkit/glue/media/simple_data_source_unittest.cc index 537798f..c214949 100644 --- a/webkit/glue/media/simple_data_source_unittest.cc +++ b/webkit/glue/media/simple_data_source_unittest.cc @@ -6,9 +6,15 @@ #include "media/base/filters.h" #include "media/base/mock_filter_host.h" #include "media/base/mock_filters.h" -#include "webkit/glue/media/mock_media_resource_loader_bridge_factory.h" +#include "net/base/net_errors.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFrame.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 "webkit/glue/media/simple_data_source.h" -#include "webkit/glue/mock_resource_loader_bridge.h" +#include "webkit/glue/mock_webframe.h" +#include "webkit/glue/mock_weburlloader_impl.h" using ::testing::_; using ::testing::DoAll; @@ -21,6 +27,11 @@ using ::testing::SetArgumentPointee; using ::testing::StrictMock; using ::testing::WithArgs; +using WebKit::WebURLError; +using WebKit::WebURLLoader; +using WebKit::WebURLRequest; +using WebKit::WebURLResponse; + namespace { const int kDataSize = 1024; @@ -39,68 +50,56 @@ namespace webkit_glue { class SimpleDataSourceTest : public testing::Test { public: SimpleDataSourceTest() { - bridge_factory_.reset( - new NiceMock<MockMediaResourceLoaderBridgeFactory>()); - bridge_.reset(new NiceMock<MockResourceLoaderBridge>()); - for (int i = 0; i < kDataSize; ++i) { data_[i] = i; } } virtual ~SimpleDataSourceTest() { - if (bridge_.get()) - EXPECT_CALL(*bridge_, OnDestroy()); - if (bridge_factory_.get()) - EXPECT_CALL(*bridge_factory_, OnDestroy()); + ignore_result(frame_.release()); } void InitializeDataSource(const char* url) { + gurl_ = GURL(url); + + frame_.reset(new NiceMock<MockWebFrame>()); + url_loader_ = new NiceMock<MockWebURLLoader>(); + data_source_ = new SimpleDataSource(MessageLoop::current(), - bridge_factory_.get()); - CHECK(data_source_); + frame_.get()); // There is no need to provide a message loop to data source. data_source_->set_host(&host_); + data_source_->SetURLLoaderForTest(url_loader_); - // First a bridge is created. InSequence s; - EXPECT_CALL(*bridge_factory_, CreateBridge(GURL(url), _, -1, -1)) - .WillOnce(Return(bridge_.get())); - EXPECT_CALL(*bridge_, Start(data_source_.get())) - .WillOnce(Return(true)); data_source_->Initialize(url, callback_.NewCallback()); - MessageLoop::current()->RunAllPending(); } void RequestSucceeded(bool is_loaded) { - ResourceResponseInfo info; - info.content_length = kDataSize; + WebURLResponse response(gurl_); + response.setExpectedContentLength(kDataSize); - data_source_->OnReceivedResponse(info, false); + data_source_->didReceiveResponse(NULL, response); int64 size; EXPECT_TRUE(data_source_->GetSize(&size)); EXPECT_EQ(kDataSize, size); - for (int i = 0; i < kDataSize; ++i) - data_source_->OnReceivedData(data_ + i, 1); + for (int i = 0; i < kDataSize; ++i) { + data_source_->didReceiveData(NULL, data_ + i, 1); + } EXPECT_CALL(host_, SetLoaded(is_loaded)); InSequence s; - EXPECT_CALL(*bridge_, OnDestroy()) - .WillOnce(Invoke(this, &SimpleDataSourceTest::ReleaseBridge)); EXPECT_CALL(host_, SetTotalBytes(kDataSize)); EXPECT_CALL(host_, SetBufferedBytes(kDataSize)); EXPECT_CALL(callback_, OnFilterCallback()); EXPECT_CALL(callback_, OnCallbackDestroyed()); - URLRequestStatus status; - status.set_status(URLRequestStatus::SUCCESS); - status.set_os_error(0); - data_source_->OnCompletedRequest(status, "", base::Time()); + data_source_->didFinishLoading(NULL, 0); // Let the tasks to be executed. MessageLoop::current()->RunAllPending(); @@ -108,28 +107,23 @@ class SimpleDataSourceTest : public testing::Test { void RequestFailed() { InSequence s; - EXPECT_CALL(*bridge_, OnDestroy()) - .WillOnce(Invoke(this, &SimpleDataSourceTest::ReleaseBridge)); EXPECT_CALL(host_, SetError(media::PIPELINE_ERROR_NETWORK)); EXPECT_CALL(callback_, OnFilterCallback()); EXPECT_CALL(callback_, OnCallbackDestroyed()); - URLRequestStatus status; - status.set_status(URLRequestStatus::FAILED); - status.set_os_error(100); - data_source_->OnCompletedRequest(status, "", base::Time()); + WebURLError error; + error.reason = net::ERR_FAILED; + data_source_->didFail(NULL, error); // Let the tasks to be executed. MessageLoop::current()->RunAllPending(); } void DestroyDataSource() { - EXPECT_CALL(*bridge_factory_, OnDestroy()) - .WillOnce(Invoke(this, &SimpleDataSourceTest::ReleaseBridgeFactory)); - StrictMock<media::MockFilterCallback> callback; EXPECT_CALL(callback, OnFilterCallback()); EXPECT_CALL(callback, OnCallbackDestroyed()); + data_source_->Stop(callback.NewCallback()); MessageLoop::current()->RunAllPending(); @@ -148,23 +142,17 @@ class SimpleDataSourceTest : public testing::Test { } } - void ReleaseBridge() { - ignore_result(bridge_.release()); - } - - void ReleaseBridgeFactory() { - ignore_result(bridge_factory_.release()); - } - MOCK_METHOD1(ReadCallback, void(size_t size)); protected: + GURL gurl_; scoped_ptr<MessageLoop> message_loop_; - scoped_ptr<NiceMock<MockMediaResourceLoaderBridgeFactory> > bridge_factory_; - scoped_ptr<NiceMock<MockResourceLoaderBridge> > bridge_; + NiceMock<MockWebURLLoader>* url_loader_; scoped_refptr<SimpleDataSource> data_source_; StrictMock<media::MockFilterHost> host_; StrictMock<media::MockFilterCallback> callback_; + scoped_ptr<NiceMock<MockWebFrame> > frame_; + char data_[kDataSize]; DISALLOW_COPY_AND_ASSIGN(SimpleDataSourceTest); @@ -189,13 +177,16 @@ TEST_F(SimpleDataSourceTest, InitializeFile) { } TEST_F(SimpleDataSourceTest, InitializeData) { + frame_.reset(new NiceMock<MockWebFrame>()); + url_loader_ = new NiceMock<MockWebURLLoader>(); + data_source_ = new SimpleDataSource(MessageLoop::current(), - bridge_factory_.get()); + frame_.get()); EXPECT_TRUE(data_source_->IsUrlSupported(kDataUrl)); - CHECK(data_source_); // There is no need to provide a message loop to data source. data_source_->set_host(&host_); + data_source_->SetURLLoaderForTest(url_loader_); EXPECT_CALL(host_, SetLoaded(true)); EXPECT_CALL(host_, SetTotalBytes(sizeof(kDataUrlDecoded))); @@ -218,9 +209,7 @@ TEST_F(SimpleDataSourceTest, RequestFailed) { TEST_F(SimpleDataSourceTest, StopWhenDownloading) { InitializeDataSource(kHttpUrl); - EXPECT_CALL(*bridge_, Cancel()); - EXPECT_CALL(*bridge_, OnDestroy()) - .WillOnce(Invoke(this, &SimpleDataSourceTest::ReleaseBridge)); + EXPECT_CALL(*url_loader_, cancel()); EXPECT_CALL(callback_, OnCallbackDestroyed()); DestroyDataSource(); } |