Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(361)

Side by Side Diff: ppapi/examples/url_loader/streaming.cc

Issue 7330027: Add an example for using the URLLoader in streaming mode. This also avoids the (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 9 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 streaming mode (reading to
6 // memory as data comes over the network). This example uses PostMessage between
7 // the plugin and the url_loader.html page in this directory to start the load
8 // and to communicate the result.
9 //
10 // The other mode is to stream to a file instead. For that mode, call
11 // URLLoader.FinishSthreamingToFile once the "Open" callback is complete, and
12 // then call URLResponseInfo.GetBodyAsFileRef once the file stream is complete.
13 // Stream-to-file is simpler, but won't allow you to get partial data as it
darin (slow to review) 2011/07/09 04:01:27 This is not exactly true. You can open the file f
14 // comes over the network.
15
16 #include "ppapi/cpp/completion_callback.h"
17 #include "ppapi/cpp/instance.h"
18 #include "ppapi/cpp/module.h"
19 #include "ppapi/cpp/url_loader.h"
20 #include "ppapi/cpp/url_request_info.h"
21 #include "ppapi/cpp/url_response_info.h"
22
23 // Buffer size for reading network data.
24 const int kBufSize = 1024;
darin (slow to review) 2011/07/09 04:01:27 nit: 'static'
25
26 class MyInstance : public pp::Instance {
27 public:
28 explicit MyInstance(PP_Instance instance)
29 : pp::Instance(instance) {
30 factory_.Initialize(this);
31 }
32 virtual ~MyInstance() {
33 // Make sure to explicitly close the loader. If somebody else is holding a
34 // reference to the URLLoader object when this class goes out of scope (so
35 // the URLLoader outlives "this"), and you have an outstanding read
36 // request, the URLLoader will write into invalid memory.
37 loader_.Close();
38 }
39
40 // Handler for the page sending us messages.
41 virtual void HandleMessage(const pp::Var& message_data);
42
43 private:
44 // Called to initiate the request.
45 void StartRequest(const std::string& url);
46
47 // Callback for the URLLoader to tell us it finished opening the connection.
48 void OnOpenComplete(int32_t result);
49
50 // Starts streaming data.
51 void ReadMore();
52
53 // Callback for the URLLoader to tell us when it finished a read.
54 void OnReadComplete(int32_t result);
55
56 // Forwards the given string to the page.
57 void ReportResponse(const std::string& data);
58
59 // Generates completion callbacks scoped to this class.
60 pp::CompletionCallbackFactory<MyInstance> factory_;
61
62 pp::URLLoader loader_;
63 pp::URLResponseInfo response_;
64
65 // The buffer used for the current read request. This is filled and then
66 // copied into content_ to build up the entire document.
67 char buf_[kBufSize];
68
69 // All the content loaded so far.
70 std::string content_;
71 };
72
73 void MyInstance::HandleMessage(const pp::Var& message_data) {
74 if (message_data.is_string() && message_data.AsString() == "go")
75 StartRequest("./fetched_content.html");
76 }
77
78 void MyInstance::StartRequest(const std::string& url) {
79 content_.clear();
80
81 pp::URLRequestInfo request(this);
82 request.SetURL(url);
83 request.SetMethod("GET");
84
85 loader_ = pp::URLLoader(this);
86 loader_.Open(request,
87 factory_.NewRequiredCallback(&MyInstance::OnOpenComplete));
88 }
89
90 void MyInstance::OnOpenComplete(int32_t result) {
91 if (result != PP_OK) {
92 ReportResponse("URL could not be requested");
93 return;
94 }
95
96 response_ = loader_.GetResponseInfo();
97
98 // Here you would process the headers. A real program would want to at least
99 // check the HTTP code and potentially cancel the request.
100
101 // Start streaming.
102 ReadMore();
103 }
104
105 void MyInstance::ReadMore() {
106 // Note that you specifically want an "optional" callback here. This will
107 // allow Read() to return synchronously, ignoring your completion callback,
108 // if data is available. For fast connections and large files, reading as
109 // fast as we can will make a large performance difference. However, in the
110 // case of a synchronous return, we need to be sure to delete our callback
darin (slow to review) 2011/07/09 04:01:27 you say "be sure to delete our callback", but you
111 // since the loader won't do anything with it.
112 pp::CompletionCallback cc =
113 factory_.NewOptionalCallback(&MyInstance::OnReadComplete);
114 int32_t result = PP_OK;
115 do {
116 result = loader_.ReadResponseBody(buf_, kBufSize, cc);
117 // Handle streaming data directly. Note that we *don't* want to call
118 // OnReadComplete here, since in the case of result > 0 it will schedule
119 // another call to this function. If the network is very fast, we could
120 // end up with a deeply recursive stack.
121 if (result > 0)
122 content_.append(buf_, result);
123 } while (result > 0);
124
125 // Either we reached the end of the stream or there was an error. We want
darin (slow to review) 2011/07/09 04:01:27 It might help to say: "we reached the end of the
126 // OnReadComplete to get called no matter what to handle that case, whether
127 // the error is synchronous or asynchronous. If the result code *is*
128 // COMPLETIONPENDING, our callback will be called asynchronously.
129 if (result != PP_OK_COMPLETIONPENDING)
130 cc.Run(result);
131 }
132
133 void MyInstance::OnReadComplete(int32_t result) {
134 if (result == PP_OK) {
135 // Streaming the file is complete.
136 ReportResponse(content_);
137 } else if (result > 0) {
138 // The URLLoader just filled "result" number of bytes into our buffer.
139 // Save them and perform another read.
140 content_.append(buf_, result);
141 ReadMore();
142 } else {
143 // A read error occurred.
144 ReportResponse("A read error occurred");
145 }
146 }
147
148 void MyInstance::ReportResponse(const std::string& data) {
149 PostMessage(pp::Var(data));
150 }
151
152 // This object is the global object representing this plugin library as long
153 // as it is loaded.
154 class MyModule : public pp::Module {
155 public:
156 MyModule() : pp::Module() {}
157 virtual ~MyModule() {}
158
159 // Override CreateInstance to create your customized Instance object.
160 virtual pp::Instance* CreateInstance(PP_Instance instance) {
161 return new MyInstance(instance);
162 }
163 };
164
165 namespace pp {
166
167 // Factory function for your specialization of the Module object.
168 Module* CreateModule() {
169 return new MyModule();
170 }
171
172 } // namespace pp
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698