Chromium Code Reviews| Index: ppapi/examples/url_loader/streaming.cc |
| =================================================================== |
| --- ppapi/examples/url_loader/streaming.cc (revision 0) |
| +++ ppapi/examples/url_loader/streaming.cc (revision 0) |
| @@ -0,0 +1,172 @@ |
| +// Copyright (c) 2011 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. |
| + |
| +// This example shows how to use the URLLoader in streaming mode (reading to |
| +// memory as data comes over the network). This example uses PostMessage between |
| +// the plugin and the url_loader.html page in this directory to start the load |
| +// and to communicate the result. |
| +// |
| +// The other mode is to stream to a file instead. For that mode, call |
| +// URLLoader.FinishSthreamingToFile once the "Open" callback is complete, and |
| +// then call URLResponseInfo.GetBodyAsFileRef once the file stream is complete. |
| +// Stream-to-file is simpler, but won't allow you to get partial data as it |
|
darin (slow to review)
2011/07/09 04:01:27
This is not exactly true. You can open the file f
|
| +// comes over the network. |
| + |
| +#include "ppapi/cpp/completion_callback.h" |
| +#include "ppapi/cpp/instance.h" |
| +#include "ppapi/cpp/module.h" |
| +#include "ppapi/cpp/url_loader.h" |
| +#include "ppapi/cpp/url_request_info.h" |
| +#include "ppapi/cpp/url_response_info.h" |
| + |
| +// Buffer size for reading network data. |
| +const int kBufSize = 1024; |
|
darin (slow to review)
2011/07/09 04:01:27
nit: 'static'
|
| + |
| +class MyInstance : public pp::Instance { |
| + public: |
| + explicit MyInstance(PP_Instance instance) |
| + : pp::Instance(instance) { |
| + factory_.Initialize(this); |
| + } |
| + virtual ~MyInstance() { |
| + // Make sure to explicitly close the loader. If somebody else is holding a |
| + // reference to the URLLoader object when this class goes out of scope (so |
| + // the URLLoader outlives "this"), and you have an outstanding read |
| + // request, the URLLoader will write into invalid memory. |
| + loader_.Close(); |
| + } |
| + |
| + // Handler for the page sending us messages. |
| + virtual void HandleMessage(const pp::Var& message_data); |
| + |
| + private: |
| + // Called to initiate the request. |
| + void StartRequest(const std::string& url); |
| + |
| + // Callback for the URLLoader to tell us it finished opening the connection. |
| + void OnOpenComplete(int32_t result); |
| + |
| + // Starts streaming data. |
| + void ReadMore(); |
| + |
| + // Callback for the URLLoader to tell us when it finished a read. |
| + void OnReadComplete(int32_t result); |
| + |
| + // Forwards the given string to the page. |
| + void ReportResponse(const std::string& data); |
| + |
| + // Generates completion callbacks scoped to this class. |
| + pp::CompletionCallbackFactory<MyInstance> factory_; |
| + |
| + pp::URLLoader loader_; |
| + pp::URLResponseInfo response_; |
| + |
| + // The buffer used for the current read request. This is filled and then |
| + // copied into content_ to build up the entire document. |
| + char buf_[kBufSize]; |
| + |
| + // All the content loaded so far. |
| + std::string content_; |
| +}; |
| + |
| +void MyInstance::HandleMessage(const pp::Var& message_data) { |
| + if (message_data.is_string() && message_data.AsString() == "go") |
| + StartRequest("./fetched_content.html"); |
| +} |
| + |
| +void MyInstance::StartRequest(const std::string& url) { |
| + content_.clear(); |
| + |
| + pp::URLRequestInfo request(this); |
| + request.SetURL(url); |
| + request.SetMethod("GET"); |
| + |
| + loader_ = pp::URLLoader(this); |
| + loader_.Open(request, |
| + factory_.NewRequiredCallback(&MyInstance::OnOpenComplete)); |
| +} |
| + |
| +void MyInstance::OnOpenComplete(int32_t result) { |
| + if (result != PP_OK) { |
| + ReportResponse("URL could not be requested"); |
| + return; |
| + } |
| + |
| + response_ = loader_.GetResponseInfo(); |
| + |
| + // Here you would process the headers. A real program would want to at least |
| + // check the HTTP code and potentially cancel the request. |
| + |
| + // Start streaming. |
| + ReadMore(); |
| +} |
| + |
| +void MyInstance::ReadMore() { |
| + // Note that you specifically want an "optional" callback here. This will |
| + // allow Read() to return synchronously, ignoring your completion callback, |
| + // if data is available. For fast connections and large files, reading as |
| + // fast as we can will make a large performance difference. However, in the |
| + // case of a synchronous return, we need to be sure to delete our callback |
|
darin (slow to review)
2011/07/09 04:01:27
you say "be sure to delete our callback", but you
|
| + // since the loader won't do anything with it. |
| + pp::CompletionCallback cc = |
| + factory_.NewOptionalCallback(&MyInstance::OnReadComplete); |
| + int32_t result = PP_OK; |
| + do { |
| + result = loader_.ReadResponseBody(buf_, kBufSize, cc); |
| + // Handle streaming data directly. Note that we *don't* want to call |
| + // OnReadComplete here, since in the case of result > 0 it will schedule |
| + // another call to this function. If the network is very fast, we could |
| + // end up with a deeply recursive stack. |
| + if (result > 0) |
| + content_.append(buf_, result); |
| + } while (result > 0); |
| + |
| + // Either we reached the end of the stream or there was an error. We want |
|
darin (slow to review)
2011/07/09 04:01:27
It might help to say: "we reached the end of the
|
| + // OnReadComplete to get called no matter what to handle that case, whether |
| + // the error is synchronous or asynchronous. If the result code *is* |
| + // COMPLETIONPENDING, our callback will be called asynchronously. |
| + if (result != PP_OK_COMPLETIONPENDING) |
| + cc.Run(result); |
| +} |
| + |
| +void MyInstance::OnReadComplete(int32_t result) { |
| + if (result == PP_OK) { |
| + // Streaming the file is complete. |
| + ReportResponse(content_); |
| + } else if (result > 0) { |
| + // The URLLoader just filled "result" number of bytes into our buffer. |
| + // Save them and perform another read. |
| + content_.append(buf_, result); |
| + ReadMore(); |
| + } else { |
| + // A read error occurred. |
| + ReportResponse("A read error occurred"); |
| + } |
| +} |
| + |
| +void MyInstance::ReportResponse(const std::string& data) { |
| + PostMessage(pp::Var(data)); |
| +} |
| + |
| +// This object is the global object representing this plugin library as long |
| +// as it is loaded. |
| +class MyModule : public pp::Module { |
| + public: |
| + MyModule() : pp::Module() {} |
| + virtual ~MyModule() {} |
| + |
| + // Override CreateInstance to create your customized Instance object. |
| + virtual pp::Instance* CreateInstance(PP_Instance instance) { |
| + return new MyInstance(instance); |
| + } |
| +}; |
| + |
| +namespace pp { |
| + |
| +// Factory function for your specialization of the Module object. |
| +Module* CreateModule() { |
| + return new MyModule(); |
| +} |
| + |
| +} // namespace pp |
| Property changes on: ppapi/examples/url_loader/streaming.cc |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| + LF |