summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ppapi/cpp/url_loader.h59
-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
-rw-r--r--ppapi/ppapi_tests.gypi10
6 files changed, 262 insertions, 58 deletions
diff --git a/ppapi/cpp/url_loader.h b/ppapi/cpp/url_loader.h
index 0cfe5ea..e090fb3 100644
--- a/ppapi/cpp/url_loader.h
+++ b/ppapi/cpp/url_loader.h
@@ -17,64 +17,7 @@ class URLResponseInfo;
// URLLoader provides an API to download URLs.
//
-// EXAMPLE USAGE:
-//
-// class MyHandler {
-// public:
-// MyHandler(Instance* instance)
-// : factory_(this),
-// loader_(instance),
-// did_open_(false) {
-// }
-// void ProcessURL(const char* url) {
-// CompletionCallback* cc = NewCallback();
-// int32_t rv = loader_.Open(MakeRequest(url), cc);
-// if (rv != PP_OK_COMPLETIONPENDING)
-// cc->Run(rv);
-// }
-// private:
-// CompletionCallback* NewCallback() {
-// return factory_.NewOptionalCallback(&MyHandler::DidCompleteIO);
-// }
-// URLRequestInfo MakeRequest(const char* url) {
-// URLRequestInfo request;
-// request.SetURL(url);
-// request.SetMethod("GET");
-// request.SetFollowRedirects(true);
-// return request;
-// }
-// void DidCompleteIO(int32_t result) {
-// if (result > 0) {
-// // buf_ now contains 'result' number of bytes from the URL.
-// ProcessBytes(buf_, result);
-// ReadMore();
-// } else if (result == PP_OK && !did_open_) {
-// // Headers are available, and we can start reading the body.
-// did_open_ = true;
-// ProcessResponseInfo(loader_.GetResponseInfo());
-// ReadMore();
-// } else {
-// // Done reading (possibly with an error given by 'result').
-// }
-// }
-// void ReadMore() {
-// CompletionCallback* cc = NewCallback();
-// int32_t rv = fio_.Read(offset_, buf_, sizeof(buf_), cc);
-// if (rv != PP_OK_COMPLETIONPENDING)
-// cc->Run(rv);
-// }
-// void ProcessResponseInfo(const URLResponseInfo& response_info) {
-// // Read response headers, etc.
-// }
-// void ProcessBytes(const char* bytes, int32_t length) {
-// // Do work ...
-// }
-// pp::CompletionCallbackFactory<MyHandler> factory_;
-// pp::URLLoader loader_;
-// char buf_[4096];
-// bool did_open_;
-// };
-//
+// Please see the example in ppapi/examples/url_loader/url_loader.cc.
class URLLoader : public Resource {
public:
// Creates an is_null() URLLoader object.
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>
+
diff --git a/ppapi/ppapi_tests.gypi b/ppapi/ppapi_tests.gypi
index 79cfaa4..93f9c88 100644
--- a/ppapi/ppapi_tests.gypi
+++ b/ppapi/ppapi_tests.gypi
@@ -314,6 +314,16 @@
],
},
{
+ 'target_name': 'ppapi_example_url_loader',
+ 'dependencies': [
+ 'ppapi_example_skeleton',
+ 'ppapi.gyp:ppapi_cpp',
+ ],
+ 'sources': [
+ 'examples/url_loader/streaming.cc',
+ ],
+ },
+ {
'target_name': 'ppapi_example_gles2',
'dependencies': [
'ppapi_example_skeleton',