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. 29 const int kBufSize = 1024; 30 31 class 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 80 void MyInstance::HandleMessage(const pp::Var& message_data) { 81 if (message_data.is_string() && message_data.AsString() == "go") 82 StartRequest("./fetched_content.html"); 83 } 84 85 void 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 98 void 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 110 void 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 120 void 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 132 void 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 147 void 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. 153 class 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 164 namespace pp { 165 166 // Factory function for your specialization of the Module object. 167 Module* CreateModule() { 168 return new MyModule(); 169 } 170 171 } // namespace pp 172