| Index: native_client_sdk/src/doc/_developer.chrome.com_generated/devguide/coding/url-loading.html
|
| diff --git a/native_client_sdk/src/doc/_developer.chrome.com_generated/devguide/coding/url-loading.html b/native_client_sdk/src/doc/_developer.chrome.com_generated/devguide/coding/url-loading.html
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a99b2149a9f5ffadd13bb01f9feb2e8bffcee7d8
|
| --- /dev/null
|
| +++ b/native_client_sdk/src/doc/_developer.chrome.com_generated/devguide/coding/url-loading.html
|
| @@ -0,0 +1,232 @@
|
| +{{+bindTo:partials.standard_nacl_article}}
|
| +
|
| +<section id="url-loading">
|
| +<span id="devguide-coding-url-loading"></span><h1 id="url-loading"><span id="devguide-coding-url-loading"></span>URL Loading</h1>
|
| +<div class="contents local topic" id="contents">
|
| +<ul class="small-gap">
|
| +<li><a class="reference internal" href="#introduction" id="id1">Introduction</a></li>
|
| +<li><a class="reference internal" href="#reference-information" id="id2">Reference information</a></li>
|
| +<li><a class="reference internal" href="#background" id="id3">Background</a></li>
|
| +<li><p class="first"><a class="reference internal" href="#the-url-loader-example" id="id4">The <code>url_loader</code> example</a></p>
|
| +<ul class="small-gap">
|
| +<li><a class="reference internal" href="#url-loading-overview" id="id5">URL loading overview</a></li>
|
| +</ul>
|
| +</li>
|
| +<li><p class="first"><a class="reference internal" href="#url-loader-deep-dive" id="id6"><code>url_loader</code> deep dive</a></p>
|
| +<ul class="small-gap">
|
| +<li><a class="reference internal" href="#setting-up-the-request" id="id7">Setting up the request</a></li>
|
| +<li><a class="reference internal" href="#downloading-the-data" id="id8">Downloading the data</a></li>
|
| +<li><a class="reference internal" href="#displaying-a-result" id="id9">Displaying a result</a></li>
|
| +</ul>
|
| +</li>
|
| +</ul>
|
| +</div>
|
| +<section id="introduction">
|
| +<h2 id="introduction">Introduction</h2>
|
| +<p>This chapter describes how to use the <a class="reference external" href="https://developers.google.com/native-client/peppercpp/classpp_1_1_u_r_l_loader">URLLoader API</a>
|
| +to load resources such as images and sound files from a server into your
|
| +application.</p>
|
| +<p>The example discussed in this chapter is included in the SDK in the directory
|
| +<code>examples/api/url_loader</code>.</p>
|
| +</section><section id="reference-information">
|
| +<h2 id="reference-information">Reference information</h2>
|
| +<p>For reference information related to loading data from URLs, see the
|
| +following documentation:</p>
|
| +<ul class="small-gap">
|
| +<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/url__loader_8h">url_loader.h</a> -
|
| +Contains <code>URLLoader</code> class for loading data from URLs</li>
|
| +<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/url__request__info_8h">url_request_info.h</a>
|
| +- Contains <code>URLRequest</code> class for creating and manipulating URL requests</li>
|
| +<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/url__response__info_8h">url_response_info.h</a>
|
| +- Contains <code>URLResponse</code> class for examaning URL responses</li>
|
| +</ul>
|
| +</section><section id="background">
|
| +<h2 id="background">Background</h2>
|
| +<p>When a user launches your Native Client web application, Chrome downloads and
|
| +caches your application’s HTML file, manifest file (.nmf), and Native Client
|
| +module (.pexe or .nexe). If your application needs additional assets, such as
|
| +images and sound files, it must explicitly load those assets. You can use the
|
| +Pepper APIs described in this chapter to load assets from a URL into your
|
| +application.</p>
|
| +<p>After you’ve loaded assets into your application, Chrome will cache those
|
| +assets. To avoid being at the whim of the Chrome cache, however, you may want
|
| +to use the <a class="reference external" href="https://developers.google.com/native-client/peppercpp/classpp_1_1_file_i_o">Pepper FileIO API</a>
|
| +to write those assets to a persistent, sandboxed location on the user’s file
|
| +system.</p>
|
| +</section><section id="the-url-loader-example">
|
| +<h2 id="the-url-loader-example">The <code>url_loader</code> example</h2>
|
| +<p>The SDK includes an example called <code>url_loader</code> demonstrating downloading
|
| +files from a server. This example has these primary files:</p>
|
| +<ul class="small-gap">
|
| +<li><code>index.html</code> - The HTML code that launches the Native Client module.</li>
|
| +<li><code>example.js</code> - The JavaScript file for index.html. It has code that sends
|
| +a PostMessage request to the Native Client module when the “Get URL” button
|
| +is clicked.</li>
|
| +<li><code>url_loader_success.html</code> - An HTML file on the server whose contents are
|
| +being retrieved using the <code>URLLoader</code> API.</li>
|
| +<li><code>url_loader.cc</code> - The code that sets up and provides and entry point into
|
| +the Native client module.</li>
|
| +<li><code>url_loader_handler.cc</code> - The code that retrieves the contents of the
|
| +url_loader_success.html file and returns the results (this is where the
|
| +bulk of the work is done).</li>
|
| +</ul>
|
| +<p>The remainder of this document covers the code in the <code>url_loader.cc</code> and
|
| +<code>url_loader_handler.cc</code> files.</p>
|
| +<section id="url-loading-overview">
|
| +<h3 id="url-loading-overview">URL loading overview</h3>
|
| +<p>Like many Pepper APIs, the <code>URLLoader</code> API includes a set of methods that
|
| +execute asynchronously and that invoke callback functions in your Native Client
|
| +module. The high-level flow for the <code>url_loader</code> example is described below.
|
| +Note that methods in the namespace <code>pp::URLLoader</code> are part of the Pepper
|
| +<code>URLLoader</code> API, while the rest of the functions are part of the code in the
|
| +Native Client module (specifically in the file <code>url_loader_handler.cc</code>). The
|
| +following image shows the flow of the <code>url_loader_handler</code> code:</p>
|
| +<img alt="/native-client/images/pepper-urlloader-api.png" src="/native-client/images/pepper-urlloader-api.png" />
|
| +<p>Following are the high-level steps involved in URL loading.</p>
|
| +<ol class="arabic simple">
|
| +<li>The Native Client module calls <code>pp::URLLoader::Open</code> to begin opening the
|
| +URL.</li>
|
| +<li>When <code>Open</code> completes, it invokes a callback function in the Native Client
|
| +module (in this case, <code>OnOpen</code>).</li>
|
| +<li>The Native Client module calls the Pepper function
|
| +<code>URLLoader::ReadResponseBody</code> to begin reading the response body with the
|
| +data. <code>ReadResponseBody</code> is passed an optional callback function in the
|
| +Native Client module (in this case, On <code>Read</code>). The callback function is
|
| +an optional callback because <code>ReadResponseBody</code> may read data and return
|
| +synchronously if data is available (this improves performance for large
|
| +files and fast connections).</li>
|
| +</ol>
|
| +<p>The remainder of this document demonstrates how the previous steps are
|
| +implemented in the <code>url_loader</code> example.</p>
|
| +</section></section><section id="url-loader-deep-dive">
|
| +<h2 id="url-loader-deep-dive"><code>url_loader</code> deep dive</h2>
|
| +<section id="setting-up-the-request">
|
| +<h3 id="setting-up-the-request">Setting up the request</h3>
|
| +<p><code>HandleMessage</code> in <code>url_loader.cc</code> creates a <code>URLLoaderHandler</code> instance
|
| +and passes it the URL of the asset to be retrieved. Then <code>HandleMessage</code>
|
| +calls <code>Start</code> to start retrieving the asset from the server:</p>
|
| +<pre class="prettyprint">
|
| +void URLLoaderInstance::HandleMessage(const pp::Var& var_message) {
|
| + if (!var_message.is_string()) {
|
| + return;
|
| + }
|
| + std::string message = var_message.AsString();
|
| + if (message.find(kLoadUrlMethodId) == 0) {
|
| + // The argument to getUrl is everything after the first ':'.
|
| + size_t sep_pos = message.find_first_of(kMessageArgumentSeparator);
|
| + if (sep_pos != std::string::npos) {
|
| + std::string url = message.substr(sep_pos + 1);
|
| + printf("URLLoaderInstance::HandleMessage('%s', '%s')\n",
|
| + message.c_str(),
|
| + url.c_str());
|
| + fflush(stdout);
|
| + URLLoaderHandler* handler = URLLoaderHandler::Create(this, url);
|
| + if (handler != NULL) {
|
| + // Starts asynchronous download. When download is finished or when an
|
| + // error occurs, |handler| posts the results back to the browser
|
| + // vis PostMessage and self-destroys.
|
| + handler->Start();
|
| + }
|
| + }
|
| + }
|
| +}
|
| +</pre>
|
| +<p>Notice that the constructor for <code>URLLoaderHandler</code> in
|
| +<code>url_loader_handler.cc</code> sets up the parameters of the URL request (using
|
| +<code>SetURL,</code> <code>SetMethod</code>, and <code>SetRecordDownloadProgress</code>):</p>
|
| +<pre class="prettyprint">
|
| +URLLoaderHandler::URLLoaderHandler(pp::Instance* instance,
|
| + const std::string& url)
|
| + : instance_(instance),
|
| + url_(url),
|
| + url_request_(instance),
|
| + url_loader_(instance),
|
| + buffer_(new char[READ_BUFFER_SIZE]),
|
| + cc_factory_(this) {
|
| + url_request_.SetURL(url);
|
| + url_request_.SetMethod("GET");
|
| + url_request_.SetRecordDownloadProgress(true);
|
| +}
|
| +</pre>
|
| +</section><section id="downloading-the-data">
|
| +<h3 id="downloading-the-data">Downloading the data</h3>
|
| +<p><code>Start</code> in <code>url_loader_handler.cc</code> creates a callback (<code>cc</code>) using a
|
| +<code>CompletionCallbackFactory</code>. The callback is passed to <code>Open</code> to be called
|
| +upon its completion. <code>Open</code> begins loading the <code>URLRequestInfo</code>.</p>
|
| +<pre class="prettyprint">
|
| +void URLLoaderHandler::Start() {
|
| + pp::CompletionCallback cc =
|
| + cc_factory_.NewCallback(&URLLoaderHandler::OnOpen);
|
| + url_loader_.Open(url_request_, cc);
|
| +}
|
| +</pre>
|
| +<p><code>OnOpen</code> ensures that the Open call was successful and, if so, calls
|
| +<code>GetDownloadProgress</code> to determine the amount of data to be downloaded so it
|
| +can allocate memory for the response body.</p>
|
| +<p>Note that the amount of data to be downloaded may be unknown, in which case
|
| +<code>GetDownloadProgress</code> sets <code>total_bytes_to_be_received</code> to -1. It is not a
|
| +problem if <code>total_bytes_to_be_received</code> is set to -1 or if
|
| +<code>GetDownloadProgress</code> fails; in these scenarios memory for the read buffer
|
| +can’t be allocated in advance and must be allocated as data is received.</p>
|
| +<p>Finally, <code>OnOpen</code> calls <code>ReadBody.</code></p>
|
| +<pre class="prettyprint">
|
| +void URLLoaderHandler::OnOpen(int32_t result) {
|
| + if (result != PP_OK) {
|
| + ReportResultAndDie(url_, "pp::URLLoader::Open() failed", false);
|
| + return;
|
| + }
|
| + int64_t bytes_received = 0;
|
| + int64_t total_bytes_to_be_received = 0;
|
| + if (url_loader_.GetDownloadProgress(&bytes_received,
|
| + &total_bytes_to_be_received)) {
|
| + if (total_bytes_to_be_received > 0) {
|
| + url_response_body_.reserve(total_bytes_to_be_received);
|
| + }
|
| + }
|
| + url_request_.SetRecordDownloadProgress(false);
|
| + ReadBody();
|
| +}
|
| +</pre>
|
| +<p><code>ReadBody</code> creates another <code>CompletionCallback</code> (a <code>NewOptionalCallback</code>)
|
| +and passes it to <code>ReadResponseBody,</code> which reads the response body, and
|
| +<code>AppendDataBytes,</code> which appends the resulting data to the previously read
|
| +data.</p>
|
| +<pre class="prettyprint">
|
| +void URLLoaderHandler::ReadBody() {
|
| + pp::CompletionCallback cc =
|
| + cc_factory_.NewOptionalCallback(&URLLoaderHandler::OnRead);
|
| + int32_t result = PP_OK;
|
| + do {
|
| + result = url_loader_.ReadResponseBody(buffer_, READ_BUFFER_SIZE, cc);
|
| + if (result > 0) {
|
| + AppendDataBytes(buffer_, result);
|
| + }
|
| + } while (result > 0);
|
| +
|
| + if (result != PP_OK_COMPLETIONPENDING) {
|
| + cc.Run(result);
|
| + }
|
| +}
|
| +
|
| +void URLLoaderHandler::AppendDataBytes(const char* buffer, int32_t num_bytes) {
|
| + if (num_bytes <= 0)
|
| + return;
|
| + num_bytes = std::min(READ_BUFFER_SIZE, num_bytes);
|
| + url_response_body_.insert(
|
| + url_response_body_.end(), buffer, buffer + num_bytes);
|
| +}
|
| +</pre>
|
| +<p>Eventually either all the bytes have been read for the entire file (resulting
|
| +in <code>PP_OK</code> or 0), all the bytes have been read for what has been
|
| +downloaded, but more is to be downloaded (<code>PP_OK_COMPLETIONPENDING</code> or -1),
|
| +or there is an error (less than -1). <code>OnRead</code> is called in the event of an
|
| +error or <code>PP_OK</code>.</p>
|
| +</section><section id="displaying-a-result">
|
| +<h3 id="displaying-a-result">Displaying a result</h3>
|
| +<p>OnRead calls <code>ReportResultAndDie</code> when either an error or <code>PP_OK</code> is
|
| +returned to indicate streaming of file is complete. <code>ReportResultAndDie</code> then
|
| +calls <code>ReportResult,</code> which calls <code>PostMessage</code> to send the result back to
|
| +the HTML page.</p>
|
| +</section></section></section>
|
| +
|
| +{{/partials.standard_nacl_article}}
|
|
|