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.
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.
10 // The other mode is to stream to a file instead. See stream_to_file.cc
12 #include "ppapi/cpp/instance.h"
13 #include "ppapi/cpp/module.h"
14 #include "ppapi/cpp/url_loader.h"
15 #include "ppapi/cpp/url_request_info.h"
16 #include "ppapi/cpp/url_response_info.h"
17 #include "ppapi/utility/completion_callback_factory.h"
19 // When compiling natively on Windows, PostMessage can be #define-d to
25 // Buffer size for reading network data.
26 const int kBufSize
= 1024;
28 class MyInstance
: public pp::Instance
{
30 explicit MyInstance(PP_Instance instance
)
31 : pp::Instance(instance
) {
32 factory_
.Initialize(this);
34 virtual ~MyInstance() {
35 // Make sure to explicitly close the loader. If somebody else is holding a
36 // reference to the URLLoader object when this class goes out of scope (so
37 // the URLLoader outlives "this"), and you have an outstanding read
38 // request, the URLLoader will write into invalid memory.
42 // Handler for the page sending us messages.
43 virtual void HandleMessage(const pp::Var
& message_data
);
46 // Called to initiate the request.
47 void StartRequest(const std::string
& url
);
49 // Callback for the URLLoader to tell us it finished opening the connection.
50 void OnOpenComplete(int32_t result
);
52 // Starts streaming data.
55 // Callback for the URLLoader to tell us when it finished a read.
56 void OnReadComplete(int32_t result
);
58 // Forwards the given string to the page.
59 void ReportResponse(const std::string
& data
);
61 // Generates completion callbacks scoped to this class.
62 pp::CompletionCallbackFactory
<MyInstance
> factory_
;
64 pp::URLLoader loader_
;
65 pp::URLResponseInfo response_
;
67 // The buffer used for the current read request. This is filled and then
68 // copied into content_ to build up the entire document.
71 // All the content loaded so far.
75 void MyInstance::HandleMessage(const pp::Var
& message_data
) {
76 if (message_data
.is_string() && message_data
.AsString() == "go")
77 StartRequest("./fetched_content.html");
80 void MyInstance::StartRequest(const std::string
& url
) {
83 pp::URLRequestInfo
request(this);
85 request
.SetMethod("GET");
87 loader_
= pp::URLLoader(this);
89 factory_
.NewCallback(&MyInstance::OnOpenComplete
));
92 void MyInstance::OnOpenComplete(int32_t result
) {
93 if (result
!= PP_OK
) {
94 ReportResponse("URL could not be requested");
98 response_
= loader_
.GetResponseInfo();
100 // Here you would process the headers. A real program would want to at least
101 // check the HTTP code and potentially cancel the request.
107 void MyInstance::ReadMore() {
108 // Note that you specifically want an "optional" callback here. This will
109 // allow Read() to return synchronously, ignoring your completion callback,
110 // if data is available. For fast connections and large files, reading as
111 // fast as we can will make a large performance difference. However, in the
112 // case of a synchronous return, we need to be sure to run the callback we
113 // created since the loader won't do anything with it.
114 pp::CompletionCallback cc
=
115 factory_
.NewOptionalCallback(&MyInstance::OnReadComplete
);
116 int32_t result
= PP_OK
;
118 result
= loader_
.ReadResponseBody(buf_
, kBufSize
, cc
);
119 // Handle streaming data directly. Note that we *don't* want to call
120 // OnReadComplete here, since in the case of result > 0 it will schedule
121 // another call to this function. If the network is very fast, we could
122 // end up with a deeply recursive stack.
124 content_
.append(buf_
, result
);
125 } while (result
> 0);
127 if (result
!= PP_OK_COMPLETIONPENDING
) {
128 // Either we reached the end of the stream (result == PP_OK) or there was
129 // an error. We want OnReadComplete to get called no matter what to handle
130 // that case, whether the error is synchronous or asynchronous. If the
131 // result code *is* COMPLETIONPENDING, our callback will be called
137 void MyInstance::OnReadComplete(int32_t result
) {
138 if (result
== PP_OK
) {
139 // Streaming the file is complete.
140 ReportResponse(content_
);
141 } else if (result
> 0) {
142 // The URLLoader just filled "result" number of bytes into our buffer.
143 // Save them and perform another read.
144 content_
.append(buf_
, result
);
147 // A read error occurred.
148 ReportResponse("A read error occurred");
152 void MyInstance::ReportResponse(const std::string
& data
) {
153 PostMessage(pp::Var(data
));
156 // This object is the global object representing this plugin library as long
158 class MyModule
: public pp::Module
{
160 MyModule() : pp::Module() {}
161 virtual ~MyModule() {}
163 // Override CreateInstance to create your customized Instance object.
164 virtual pp::Instance
* CreateInstance(PP_Instance instance
) {
165 return new MyInstance(instance
);
171 // Factory function for your specialization of the Module object.
172 Module
* CreateModule() {
173 return new MyModule();