1a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// found in the LICENSE file.
4a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
5a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// This example shows how to use the URLLoader in "stream to file" mode where
6a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// the browser writes incoming data to a file, which you can read out via the
7a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// file I/O APIs.
8c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch//
9a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// This example uses PostMessage between the plugin and the url_loader.html
10c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// page in this directory to start the load and to communicate the result.
11a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
12f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ppapi/c/ppb_file_io.h"
13f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ppapi/cpp/file_io.h"
14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ppapi/cpp/file_ref.h"
15a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ppapi/cpp/instance.h"
16a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ppapi/cpp/module.h"
17a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ppapi/cpp/url_loader.h"
18a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ppapi/cpp/url_request_info.h"
19a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ppapi/cpp/url_response_info.h"
20a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ppapi/utility/completion_callback_factory.h"
21a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// When compiling natively on Windows, PostMessage can be #define-d to
236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// something else.
246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#ifdef PostMessage
256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#undef PostMessage
266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#endif
2758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
28a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Buffer size for reading network data.
29a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)const int kBufSize = 1024;
3058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
3158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)class MyInstance : public pp::Instance {
3258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) public:
3358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  explicit MyInstance(PP_Instance instance)
3458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      : pp::Instance(instance) {
3558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    factory_.Initialize(this);
3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
37a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  virtual ~MyInstance() {
38a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // Make sure to explicitly close the loader. If somebody else is holding a
39a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // reference to the URLLoader object when this class goes out of scope (so
40a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // the URLLoader outlives "this"), and you have an outstanding read
41a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // request, the URLLoader will write into invalid memory.
426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    loader_.Close();
436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Handler for the page sending us messages.
466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  virtual void HandleMessage(const pp::Var& message_data);
476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) private:
496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Called to initiate the request.
506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  void StartRequest(const std::string& url);
516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Callback for the URLLoader to tell us it finished opening the connection.
536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  void OnOpenComplete(int32_t result);
546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Callback for when the file is completely filled with the download
56a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void OnStreamComplete(int32_t result);
57a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
58a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void OnOpenFileComplete(int32_t result);
59a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void OnReadComplete(int32_t result);
60a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
61a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Forwards the given string to the page.
62a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  void ReportResponse(const std::string& data);
63a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Generates completion callbacks scoped to this class.
6558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  pp::CompletionCallbackFactory<MyInstance> factory_;
66a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  pp::URLLoader loader_;
68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  pp::URLResponseInfo response_;
69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  pp::FileRef dest_file_;
70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  pp::FileIO file_io_;
71a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
72a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // The buffer used for the current read request. This is filled and then
73a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // copied into content_ to build up the entire document.
74  char buf_[kBufSize];
75
76  // All the content loaded so far.
77  std::string content_;
78};
79
80void MyInstance::HandleMessage(const pp::Var& message_data) {
81  if (message_data.is_string() && message_data.AsString() == "go")
82    StartRequest("./fetched_content.html");
83}
84
85void MyInstance::StartRequest(const std::string& url) {
86  content_.clear();
87
88  pp::URLRequestInfo request(this);
89  request.SetURL(url);
90  request.SetMethod("GET");
91  request.SetStreamToFile(true);
92
93  loader_ = pp::URLLoader(this);
94  loader_.Open(request,
95               factory_.NewCallback(&MyInstance::OnOpenComplete));
96}
97
98void MyInstance::OnOpenComplete(int32_t result) {
99  if (result != PP_OK) {
100    ReportResponse("URL could not be requested");
101    return;
102  }
103
104  loader_.FinishStreamingToFile(
105      factory_.NewCallback(&MyInstance::OnStreamComplete));
106  response_ = loader_.GetResponseInfo();
107  dest_file_ = response_.GetBodyAsFileRef();
108}
109
110void MyInstance::OnStreamComplete(int32_t result) {
111  if (result == PP_OK) {
112    file_io_ = pp::FileIO(this);
113    file_io_.Open(dest_file_, PP_FILEOPENFLAG_READ,
114        factory_.NewCallback(&MyInstance::OnOpenFileComplete));
115  } else {
116    ReportResponse("Could not stream to file");
117  }
118}
119
120void MyInstance::OnOpenFileComplete(int32_t result) {
121  if (result == PP_OK) {
122    // Note we only read the first 1024 bytes from the file in this example
123    // to keep things simple. Please see a file I/O example for more details
124    // on reading files.
125    file_io_.Read(0, buf_, kBufSize,
126        factory_.NewCallback(&MyInstance::OnReadComplete));
127  } else {
128    ReportResponse("Could not open file");
129  }
130}
131
132void MyInstance::OnReadComplete(int32_t result) {
133  if (result >= 0) {
134    content_.append(buf_, result);
135    ReportResponse(buf_);
136  } else {
137    ReportResponse("Could not read file");
138  }
139
140  // Release everything.
141  loader_ = pp::URLLoader();
142  response_ = pp::URLResponseInfo();
143  dest_file_ = pp::FileRef();
144  file_io_ = pp::FileIO();
145}
146
147void MyInstance::ReportResponse(const std::string& data) {
148  PostMessage(pp::Var(data));
149}
150
151// This object is the global object representing this plugin library as long
152// as it is loaded.
153class MyModule : public pp::Module {
154 public:
155  MyModule() : pp::Module() {}
156  virtual ~MyModule() {}
157
158  // Override CreateInstance to create your customized Instance object.
159  virtual pp::Instance* CreateInstance(PP_Instance instance) {
160    return new MyInstance(instance);
161  }
162};
163
164namespace pp {
165
166// Factory function for your specialization of the Module object.
167Module* CreateModule() {
168  return new MyModule();
169}
170
171}  // namespace pp
172