summaryrefslogtreecommitdiffstats
path: root/ppapi/examples/url_loader/streaming.cc
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-12 18:03:14 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-12 18:03:14 +0000
commit417d2d1f242f7a5256ab7c7437f7ed6e060b95f3 (patch)
treeb1df6bf7b044028eb24f339e57b60070a5e0e016 /ppapi/examples/url_loader/streaming.cc
parent6695341f93d2f2b46db6c4c69550e3bbe7996999 (diff)
downloadchromium_src-417d2d1f242f7a5256ab7c7437f7ed6e060b95f3.zip
chromium_src-417d2d1f242f7a5256ab7c7437f7ed6e060b95f3.tar.gz
chromium_src-417d2d1f242f7a5256ab7c7437f7ed6e060b95f3.tar.bz2
Add an example for using the URLLoader in streaming mode. This also avoids the
infinite recursion bug of the old example (and actually compiles, the old example had a lot of typos). BUG=69203 Review URL: http://codereview.chromium.org/7330027 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@92196 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi/examples/url_loader/streaming.cc')
-rw-r--r--ppapi/examples/url_loader/streaming.cc172
1 files changed, 172 insertions, 0 deletions
diff --git a/ppapi/examples/url_loader/streaming.cc b/ppapi/examples/url_loader/streaming.cc
new file mode 100644
index 0000000..b6df6cb
--- /dev/null
+++ b/ppapi/examples/url_loader/streaming.cc
@@ -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.
+
+#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;
+
+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 run the callback we
+ // created 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);
+
+ if (result != PP_OK_COMPLETIONPENDING) {
+ // Either we reached the end of the stream (result == PP_OK) or there was
+ // an error. We want 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.
+ 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