| // Copyright (c) 2012 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. See stream_to_file.cc | |
| #include <stdint.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" | |
| #include "ppapi/utility/completion_callback_factory.h" | |
| // When compiling natively on Windows, PostMessage can be #define-d to | |
| // something else. | |
| #ifdef PostMessage | |
| #undef PostMessage | |
| #endif | |
| // 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_.NewCallback(&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 |