summaryrefslogtreecommitdiffstats
path: root/ppapi/examples
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
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')
-rw-r--r--ppapi/examples/url_loader/README_chrome_developer.txt22
-rw-r--r--ppapi/examples/url_loader/fetched_content.html4
-rw-r--r--ppapi/examples/url_loader/streaming.cc172
-rw-r--r--ppapi/examples/url_loader/url_loader.html53
4 files changed, 251 insertions, 0 deletions
diff --git a/ppapi/examples/url_loader/README_chrome_developer.txt b/ppapi/examples/url_loader/README_chrome_developer.txt
new file mode 100644
index 0000000..c9a6721
--- /dev/null
+++ b/ppapi/examples/url_loader/README_chrome_developer.txt
@@ -0,0 +1,22 @@
+If you're a Chrome developer, here's how to run this example:
+
+Build the example, i.e. "make ppapi_example_url_loader" on Linux.
+
+In the "src" directory, start the test server:
+
+ On Linux:
+ export PYTHONPATH=third_party/pyftpdlib:third_party/tlslite:third_party
+ python net/tools/testserver/testserver.py --port=1337 --data-dir=ppapi/examples/url_loader
+
+ On Windows:
+ set PYTHONPATH=third_party\pyftpdlib;third_party\tlslite:third_party
+ python net/tools/testserver/testserver.py --port=1337 --data-dir=ppapi/examples/url_loader
+
+Then load the page:
+
+ On Linux:
+ out/Debug/chrome --register-pepper-plugins="[[[ YOUR SOURCE DIR ]]]/out/Debug/lib.target/libppapi_example_url_loader.so;application/x-ppapi-url-loader-example" http://127.0.0.1:1337/files/url_loader.html
+
+ On Windows just substitute the generated .dll name for the .so.
+
+And click the button!
diff --git a/ppapi/examples/url_loader/fetched_content.html b/ppapi/examples/url_loader/fetched_content.html
new file mode 100644
index 0000000..16ab8ec
--- /dev/null
+++ b/ppapi/examples/url_loader/fetched_content.html
@@ -0,0 +1,4 @@
+This is the <b>content</b> of the page that was fetched.
+<p>
+<h1>If you see this</h1>
+Everything worked great.
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
diff --git a/ppapi/examples/url_loader/url_loader.html b/ppapi/examples/url_loader/url_loader.html
new file mode 100644
index 0000000..39f4494
--- /dev/null
+++ b/ppapi/examples/url_loader/url_loader.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+ <!--
+ 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 just uses postMessage to tell the plugin to fetch a file.
+ The plugin will echo the contents of that file back to us and we'll display
+ it on the page.
+ -->
+<head>
+ <title>URLLoader Example</title>
+</head>
+
+<body>
+ <script>
+
+ function StartRequest() {
+ var plugin = document.getElementById("plugin");
+ var inputBox = document.getElementById("inputBox");
+ plugin.postMessage("go");
+ }
+
+ </script>
+
+ <p>This test must be run over HTTP. If you're a Chrome developer, see the
+ README_chrome_developer.txt in this directory for how to run.</p>
+
+ <button onclick="StartRequest()">Start request</button>
+ <object id="plugin" type="application/x-ppapi-url-loader-example"
+ width="1" height="1">
+ </object>
+ <hr>
+ <div id="log_result" style="background-color:#EEE; border:1px solid black;">
+ <i>Result will go here...</i>
+ </div>
+
+ <script>
+
+ function HandleMessage(message_event) {
+ document.getElementById("log_result").innerHTML = message_event.data;
+ }
+
+ // Attach a listener for the message event. This must happen after the plugin
+ // object was created.
+ var plugin = document.getElementById("plugin");
+ plugin.addEventListener("message", HandleMessage, false);
+
+ </script>
+</body>
+</html>
+