| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // This example shows how to use the URLLoader in streaming mode (reading to | 5 // This example shows how to use the URLLoader in "stream to file" mode where |
| 6 // memory as data comes over the network). This example uses PostMessage between | 6 // the browser writes incoming data to a file, which you can read out via the |
| 7 // the plugin and the url_loader.html page in this directory to start the load | 7 // file I/O APIs. |
| 8 // and to communicate the result. | |
| 9 // | 8 // |
| 10 // The other mode is to stream to a file instead. For that mode, call | 9 // This example uses PostMessage between the plugin and the url_loader.html |
| 11 // URLLoader.FinishSthreamingToFile once the "Open" callback is complete, and | 10 // page in this directory to start the load and to communicate the result. |
| 12 // then call URLResponseInfo.GetBodyAsFileRef once the file stream is complete. | |
| 13 | 11 |
| 12 #include "ppapi/c/ppb_file_io.h" |
| 13 #include "ppapi/cpp/file_io.h" |
| 14 #include "ppapi/cpp/file_ref.h" |
| 14 #include "ppapi/cpp/instance.h" | 15 #include "ppapi/cpp/instance.h" |
| 15 #include "ppapi/cpp/module.h" | 16 #include "ppapi/cpp/module.h" |
| 16 #include "ppapi/cpp/url_loader.h" | 17 #include "ppapi/cpp/url_loader.h" |
| 17 #include "ppapi/cpp/url_request_info.h" | 18 #include "ppapi/cpp/url_request_info.h" |
| 18 #include "ppapi/cpp/url_response_info.h" | 19 #include "ppapi/cpp/url_response_info.h" |
| 19 #include "ppapi/utility/completion_callback_factory.h" | 20 #include "ppapi/utility/completion_callback_factory.h" |
| 20 | 21 |
| 21 // When compiling natively on Windows, PostMessage can be #define-d to | 22 // When compiling natively on Windows, PostMessage can be #define-d to |
| 22 // something else. | 23 // something else. |
| 23 #ifdef PostMessage | 24 #ifdef PostMessage |
| (...skipping 20 matching lines...) Expand all Loading... |
| 44 // Handler for the page sending us messages. | 45 // Handler for the page sending us messages. |
| 45 virtual void HandleMessage(const pp::Var& message_data); | 46 virtual void HandleMessage(const pp::Var& message_data); |
| 46 | 47 |
| 47 private: | 48 private: |
| 48 // Called to initiate the request. | 49 // Called to initiate the request. |
| 49 void StartRequest(const std::string& url); | 50 void StartRequest(const std::string& url); |
| 50 | 51 |
| 51 // Callback for the URLLoader to tell us it finished opening the connection. | 52 // Callback for the URLLoader to tell us it finished opening the connection. |
| 52 void OnOpenComplete(int32_t result); | 53 void OnOpenComplete(int32_t result); |
| 53 | 54 |
| 54 // Starts streaming data. | 55 // Callback for when the file is completely filled with the download |
| 55 void ReadMore(); | 56 void OnStreamComplete(int32_t result); |
| 56 | 57 |
| 57 // Callback for the URLLoader to tell us when it finished a read. | 58 void OnOpenFileComplete(int32_t result); |
| 58 void OnReadComplete(int32_t result); | 59 void OnReadComplete(int32_t result); |
| 59 | 60 |
| 60 // Forwards the given string to the page. | 61 // Forwards the given string to the page. |
| 61 void ReportResponse(const std::string& data); | 62 void ReportResponse(const std::string& data); |
| 62 | 63 |
| 63 // Generates completion callbacks scoped to this class. | 64 // Generates completion callbacks scoped to this class. |
| 64 pp::CompletionCallbackFactory<MyInstance> factory_; | 65 pp::CompletionCallbackFactory<MyInstance> factory_; |
| 65 | 66 |
| 66 pp::URLLoader loader_; | 67 pp::URLLoader loader_; |
| 67 pp::URLResponseInfo response_; | 68 pp::URLResponseInfo response_; |
| 69 pp::FileRef dest_file_; |
| 70 pp::FileIO file_io_; |
| 68 | 71 |
| 69 // The buffer used for the current read request. This is filled and then | 72 // The buffer used for the current read request. This is filled and then |
| 70 // copied into content_ to build up the entire document. | 73 // copied into content_ to build up the entire document. |
| 71 char buf_[kBufSize]; | 74 char buf_[kBufSize]; |
| 72 | 75 |
| 73 // All the content loaded so far. | 76 // All the content loaded so far. |
| 74 std::string content_; | 77 std::string content_; |
| 75 }; | 78 }; |
| 76 | 79 |
| 77 void MyInstance::HandleMessage(const pp::Var& message_data) { | 80 void MyInstance::HandleMessage(const pp::Var& message_data) { |
| 78 if (message_data.is_string() && message_data.AsString() == "go") | 81 if (message_data.is_string() && message_data.AsString() == "go") |
| 79 StartRequest("./fetched_content.html"); | 82 StartRequest("./fetched_content.html"); |
| 80 } | 83 } |
| 81 | 84 |
| 82 void MyInstance::StartRequest(const std::string& url) { | 85 void MyInstance::StartRequest(const std::string& url) { |
| 83 content_.clear(); | 86 content_.clear(); |
| 84 | 87 |
| 85 pp::URLRequestInfo request(this); | 88 pp::URLRequestInfo request(this); |
| 86 request.SetURL(url); | 89 request.SetURL(url); |
| 87 request.SetMethod("GET"); | 90 request.SetMethod("GET"); |
| 91 request.SetStreamToFile(true); |
| 88 | 92 |
| 89 loader_ = pp::URLLoader(this); | 93 loader_ = pp::URLLoader(this); |
| 90 loader_.Open(request, | 94 loader_.Open(request, |
| 91 factory_.NewCallback(&MyInstance::OnOpenComplete)); | 95 factory_.NewCallback(&MyInstance::OnOpenComplete)); |
| 92 } | 96 } |
| 93 | 97 |
| 94 void MyInstance::OnOpenComplete(int32_t result) { | 98 void MyInstance::OnOpenComplete(int32_t result) { |
| 95 if (result != PP_OK) { | 99 if (result != PP_OK) { |
| 96 ReportResponse("URL could not be requested"); | 100 ReportResponse("URL could not be requested"); |
| 97 return; | 101 return; |
| 98 } | 102 } |
| 99 | 103 |
| 104 loader_.FinishStreamingToFile( |
| 105 factory_.NewCallback(&MyInstance::OnStreamComplete)); |
| 100 response_ = loader_.GetResponseInfo(); | 106 response_ = loader_.GetResponseInfo(); |
| 101 | 107 dest_file_ = response_.GetBodyAsFileRef(); |
| 102 // Here you would process the headers. A real program would want to at least | |
| 103 // check the HTTP code and potentially cancel the request. | |
| 104 | |
| 105 // Start streaming. | |
| 106 ReadMore(); | |
| 107 } | 108 } |
| 108 | 109 |
| 109 void MyInstance::ReadMore() { | 110 void MyInstance::OnStreamComplete(int32_t result) { |
| 110 // Note that you specifically want an "optional" callback here. This will | 111 if (result == PP_OK) { |
| 111 // allow Read() to return synchronously, ignoring your completion callback, | 112 file_io_ = pp::FileIO(this); |
| 112 // if data is available. For fast connections and large files, reading as | 113 file_io_.Open(dest_file_, PP_FILEOPENFLAG_READ, |
| 113 // fast as we can will make a large performance difference. However, in the | 114 factory_.NewCallback(&MyInstance::OnOpenFileComplete)); |
| 114 // case of a synchronous return, we need to be sure to run the callback we | 115 } else { |
| 115 // created since the loader won't do anything with it. | 116 ReportResponse("Could not stream to file"); |
| 116 pp::CompletionCallback cc = | 117 } |
| 117 factory_.NewOptionalCallback(&MyInstance::OnReadComplete); | 118 } |
| 118 int32_t result = PP_OK; | |
| 119 do { | |
| 120 result = loader_.ReadResponseBody(buf_, kBufSize, cc); | |
| 121 // Handle streaming data directly. Note that we *don't* want to call | |
| 122 // OnReadComplete here, since in the case of result > 0 it will schedule | |
| 123 // another call to this function. If the network is very fast, we could | |
| 124 // end up with a deeply recursive stack. | |
| 125 if (result > 0) | |
| 126 content_.append(buf_, result); | |
| 127 } while (result > 0); | |
| 128 | 119 |
| 129 if (result != PP_OK_COMPLETIONPENDING) { | 120 void MyInstance::OnOpenFileComplete(int32_t result) { |
| 130 // Either we reached the end of the stream (result == PP_OK) or there was | 121 if (result == PP_OK) { |
| 131 // an error. We want OnReadComplete to get called no matter what to handle | 122 // Note we only read the first 1024 bytes from the file in this example |
| 132 // that case, whether the error is synchronous or asynchronous. If the | 123 // to keep things simple. Please see a file I/O example for more details |
| 133 // result code *is* COMPLETIONPENDING, our callback will be called | 124 // on reading files. |
| 134 // asynchronously. | 125 file_io_.Read(0, buf_, kBufSize, |
| 135 cc.Run(result); | 126 factory_.NewCallback(&MyInstance::OnReadComplete)); |
| 127 } else { |
| 128 ReportResponse("Could not open file"); |
| 136 } | 129 } |
| 137 } | 130 } |
| 138 | 131 |
| 139 void MyInstance::OnReadComplete(int32_t result) { | 132 void MyInstance::OnReadComplete(int32_t result) { |
| 140 if (result == PP_OK) { | 133 if (result >= 0) { |
| 141 // Streaming the file is complete. | |
| 142 ReportResponse(content_); | |
| 143 } else if (result > 0) { | |
| 144 // The URLLoader just filled "result" number of bytes into our buffer. | |
| 145 // Save them and perform another read. | |
| 146 content_.append(buf_, result); | 134 content_.append(buf_, result); |
| 147 ReadMore(); | 135 ReportResponse(buf_); |
| 148 } else { | 136 } else { |
| 149 // A read error occurred. | 137 ReportResponse("Could not read file"); |
| 150 ReportResponse("A read error occurred"); | |
| 151 } | 138 } |
| 139 |
| 140 // Release everything. |
| 141 loader_ = pp::URLLoader(); |
| 142 response_ = pp::URLResponseInfo(); |
| 143 dest_file_ = pp::FileRef(); |
| 144 file_io_ = pp::FileIO(); |
| 152 } | 145 } |
| 153 | 146 |
| 154 void MyInstance::ReportResponse(const std::string& data) { | 147 void MyInstance::ReportResponse(const std::string& data) { |
| 155 PostMessage(pp::Var(data)); | 148 PostMessage(pp::Var(data)); |
| 156 } | 149 } |
| 157 | 150 |
| 158 // This object is the global object representing this plugin library as long | 151 // This object is the global object representing this plugin library as long |
| 159 // as it is loaded. | 152 // as it is loaded. |
| 160 class MyModule : public pp::Module { | 153 class MyModule : public pp::Module { |
| 161 public: | 154 public: |
| 162 MyModule() : pp::Module() {} | 155 MyModule() : pp::Module() {} |
| 163 virtual ~MyModule() {} | 156 virtual ~MyModule() {} |
| 164 | 157 |
| 165 // Override CreateInstance to create your customized Instance object. | 158 // Override CreateInstance to create your customized Instance object. |
| 166 virtual pp::Instance* CreateInstance(PP_Instance instance) { | 159 virtual pp::Instance* CreateInstance(PP_Instance instance) { |
| 167 return new MyInstance(instance); | 160 return new MyInstance(instance); |
| 168 } | 161 } |
| 169 }; | 162 }; |
| 170 | 163 |
| 171 namespace pp { | 164 namespace pp { |
| 172 | 165 |
| 173 // Factory function for your specialization of the Module object. | 166 // Factory function for your specialization of the Module object. |
| 174 Module* CreateModule() { | 167 Module* CreateModule() { |
| 175 return new MyModule(); | 168 return new MyModule(); |
| 176 } | 169 } |
| 177 | 170 |
| 178 } // namespace pp | 171 } // namespace pp |
| OLD | NEW |