| // 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 "stream to file" mode where |
| // the browser writes incoming data to a file, which you can read out via the |
| // file I/O APIs. |
| // |
| // 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. |
| |
| #include <stdint.h> |
| |
| #include "ppapi/c/ppb_file_io.h" |
| #include "ppapi/cpp/file_io.h" |
| #include "ppapi/cpp/file_ref.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); |
| |
| // Callback for when the file is completely filled with the download |
| void OnStreamComplete(int32_t result); |
| |
| void OnOpenFileComplete(int32_t result); |
| 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_; |
| pp::FileRef dest_file_; |
| pp::FileIO file_io_; |
| |
| // 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"); |
| request.SetStreamToFile(true); |
| |
| 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; |
| } |
| |
| loader_.FinishStreamingToFile( |
| factory_.NewCallback(&MyInstance::OnStreamComplete)); |
| response_ = loader_.GetResponseInfo(); |
| dest_file_ = response_.GetBodyAsFileRef(); |
| } |
| |
| void MyInstance::OnStreamComplete(int32_t result) { |
| if (result == PP_OK) { |
| file_io_ = pp::FileIO(this); |
| file_io_.Open(dest_file_, PP_FILEOPENFLAG_READ, |
| factory_.NewCallback(&MyInstance::OnOpenFileComplete)); |
| } else { |
| ReportResponse("Could not stream to file"); |
| } |
| } |
| |
| void MyInstance::OnOpenFileComplete(int32_t result) { |
| if (result == PP_OK) { |
| // Note we only read the first 1024 bytes from the file in this example |
| // to keep things simple. Please see a file I/O example for more details |
| // on reading files. |
| file_io_.Read(0, buf_, kBufSize, |
| factory_.NewCallback(&MyInstance::OnReadComplete)); |
| } else { |
| ReportResponse("Could not open file"); |
| } |
| } |
| |
| void MyInstance::OnReadComplete(int32_t result) { |
| if (result >= 0) { |
| content_.append(buf_, result); |
| ReportResponse(buf_); |
| } else { |
| ReportResponse("Could not read file"); |
| } |
| |
| // Release everything. |
| loader_ = pp::URLLoader(); |
| response_ = pp::URLResponseInfo(); |
| dest_file_ = pp::FileRef(); |
| file_io_ = pp::FileIO(); |
| } |
| |
| 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 |