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 |