1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5// This example shows how to use the URLLoader in "stream to file" mode where 6// the browser writes incoming data to a file, which you can read out via the 7// file I/O APIs. 8// 9// This example uses PostMessage between the plugin and the url_loader.html 10// page in this directory to start the load and to communicate the result. 11 12#include "ppapi/c/ppb_file_io.h" 13#include "ppapi/cpp/file_io.h" 14#include "ppapi/cpp/file_ref.h" 15#include "ppapi/cpp/instance.h" 16#include "ppapi/cpp/module.h" 17#include "ppapi/cpp/url_loader.h" 18#include "ppapi/cpp/url_request_info.h" 19#include "ppapi/cpp/url_response_info.h" 20#include "ppapi/utility/completion_callback_factory.h" 21 22// When compiling natively on Windows, PostMessage can be #define-d to 23// something else. 24#ifdef PostMessage 25#undef PostMessage 26#endif 27 28// Buffer size for reading network data. 29const int kBufSize = 1024; 30 31class MyInstance : public pp::Instance { 32 public: 33 explicit MyInstance(PP_Instance instance) 34 : pp::Instance(instance) { 35 factory_.Initialize(this); 36 } 37 virtual ~MyInstance() { 38 // Make sure to explicitly close the loader. If somebody else is holding a 39 // reference to the URLLoader object when this class goes out of scope (so 40 // the URLLoader outlives "this"), and you have an outstanding read 41 // request, the URLLoader will write into invalid memory. 42 loader_.Close(); 43 } 44 45 // Handler for the page sending us messages. 46 virtual void HandleMessage(const pp::Var& message_data); 47 48 private: 49 // Called to initiate the request. 50 void StartRequest(const std::string& url); 51 52 // Callback for the URLLoader to tell us it finished opening the connection. 53 void OnOpenComplete(int32_t result); 54 55 // Callback for when the file is completely filled with the download 56 void OnStreamComplete(int32_t result); 57 58 void OnOpenFileComplete(int32_t result); 59 void OnReadComplete(int32_t result); 60 61 // Forwards the given string to the page. 62 void ReportResponse(const std::string& data); 63 64 // Generates completion callbacks scoped to this class. 65 pp::CompletionCallbackFactory<MyInstance> factory_; 66 67 pp::URLLoader loader_; 68 pp::URLResponseInfo response_; 69 pp::FileRef dest_file_; 70 pp::FileIO file_io_; 71 72 // The buffer used for the current read request. This is filled and then 73 // copied into content_ to build up the entire document. 74 char buf_[kBufSize]; 75 76 // All the content loaded so far. 77 std::string content_; 78}; 79 80void MyInstance::HandleMessage(const pp::Var& message_data) { 81 if (message_data.is_string() && message_data.AsString() == "go") 82 StartRequest("./fetched_content.html"); 83} 84 85void MyInstance::StartRequest(const std::string& url) { 86 content_.clear(); 87 88 pp::URLRequestInfo request(this); 89 request.SetURL(url); 90 request.SetMethod("GET"); 91 request.SetStreamToFile(true); 92 93 loader_ = pp::URLLoader(this); 94 loader_.Open(request, 95 factory_.NewCallback(&MyInstance::OnOpenComplete)); 96} 97 98void MyInstance::OnOpenComplete(int32_t result) { 99 if (result != PP_OK) { 100 ReportResponse("URL could not be requested"); 101 return; 102 } 103 104 loader_.FinishStreamingToFile( 105 factory_.NewCallback(&MyInstance::OnStreamComplete)); 106 response_ = loader_.GetResponseInfo(); 107 dest_file_ = response_.GetBodyAsFileRef(); 108} 109 110void MyInstance::OnStreamComplete(int32_t result) { 111 if (result == PP_OK) { 112 file_io_ = pp::FileIO(this); 113 file_io_.Open(dest_file_, PP_FILEOPENFLAG_READ, 114 factory_.NewCallback(&MyInstance::OnOpenFileComplete)); 115 } else { 116 ReportResponse("Could not stream to file"); 117 } 118} 119 120void MyInstance::OnOpenFileComplete(int32_t result) { 121 if (result == PP_OK) { 122 // Note we only read the first 1024 bytes from the file in this example 123 // to keep things simple. Please see a file I/O example for more details 124 // on reading files. 125 file_io_.Read(0, buf_, kBufSize, 126 factory_.NewCallback(&MyInstance::OnReadComplete)); 127 } else { 128 ReportResponse("Could not open file"); 129 } 130} 131 132void MyInstance::OnReadComplete(int32_t result) { 133 if (result >= 0) { 134 content_.append(buf_, result); 135 ReportResponse(buf_); 136 } else { 137 ReportResponse("Could not read file"); 138 } 139 140 // Release everything. 141 loader_ = pp::URLLoader(); 142 response_ = pp::URLResponseInfo(); 143 dest_file_ = pp::FileRef(); 144 file_io_ = pp::FileIO(); 145} 146 147void MyInstance::ReportResponse(const std::string& data) { 148 PostMessage(pp::Var(data)); 149} 150 151// This object is the global object representing this plugin library as long 152// as it is loaded. 153class MyModule : public pp::Module { 154 public: 155 MyModule() : pp::Module() {} 156 virtual ~MyModule() {} 157 158 // Override CreateInstance to create your customized Instance object. 159 virtual pp::Instance* CreateInstance(PP_Instance instance) { 160 return new MyInstance(instance); 161 } 162}; 163 164namespace pp { 165 166// Factory function for your specialization of the Module object. 167Module* CreateModule() { 168 return new MyModule(); 169} 170 171} // namespace pp 172