Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ppapi / examples / url_loader / streaming.cc
blob762a00bc3e3b9bf0a4e14b11c5ddbea32f77d177
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.
9 //
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
20 // something else.
21 #ifdef PostMessage
22 #undef PostMessage
23 #endif
25 // Buffer size for reading network data.
26 const int kBufSize = 1024;
28 class MyInstance : public pp::Instance {
29 public:
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.
39 loader_.Close();
42 // Handler for the page sending us messages.
43 virtual void HandleMessage(const pp::Var& message_data);
45 private:
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.
53 void ReadMore();
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.
69 char buf_[kBufSize];
71 // All the content loaded so far.
72 std::string content_;
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) {
81 content_.clear();
83 pp::URLRequestInfo request(this);
84 request.SetURL(url);
85 request.SetMethod("GET");
87 loader_ = pp::URLLoader(this);
88 loader_.Open(request,
89 factory_.NewCallback(&MyInstance::OnOpenComplete));
92 void MyInstance::OnOpenComplete(int32_t result) {
93 if (result != PP_OK) {
94 ReportResponse("URL could not be requested");
95 return;
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.
103 // Start streaming.
104 ReadMore();
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;
117 do {
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.
123 if (result > 0)
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
132 // asynchronously.
133 cc.Run(result);
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);
145 ReadMore();
146 } else {
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
157 // as it is loaded.
158 class MyModule : public pp::Module {
159 public:
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);
169 namespace pp {
171 // Factory function for your specialization of the Module object.
172 Module* CreateModule() {
173 return new MyModule();
176 } // namespace pp