| OLD | NEW |
| (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 #include <stdint.h> | |
| 6 #include <stdlib.h> | |
| 7 | |
| 8 #include <iostream> | |
| 9 #include <sstream> | |
| 10 #include <string> | |
| 11 #include <queue> | |
| 12 | |
| 13 #include "native_client/src/shared/platform/nacl_check.h" | |
| 14 | |
| 15 | |
| 16 | |
| 17 #include "ppapi/c/pp_errors.h" | |
| 18 #include "ppapi/c/ppb_file_io.h" | |
| 19 | |
| 20 #include "ppapi/cpp/completion_callback.h" | |
| 21 #include "ppapi/cpp/instance.h" | |
| 22 #include "ppapi/cpp/file_ref.h" | |
| 23 #include "ppapi/cpp/file_io.h" | |
| 24 #include "ppapi/cpp/module.h" | |
| 25 #include "ppapi/cpp/url_response_info.h" | |
| 26 #include "ppapi/cpp/url_loader.h" | |
| 27 #include "ppapi/cpp/url_request_info.h" | |
| 28 #include "ppapi/cpp/var.h" | |
| 29 | |
| 30 using std::string; | |
| 31 using std::ostringstream; | |
| 32 | |
| 33 const int kDefaultChunkSize = 1024; | |
| 34 | |
| 35 | |
| 36 class MyInstance : public pp::Instance { | |
| 37 private: | |
| 38 string url_; | |
| 39 bool stream_to_file_; | |
| 40 uint32_t chunk_size_; | |
| 41 bool debug_; | |
| 42 bool pdebug_; | |
| 43 | |
| 44 void ParseArgs(uint32_t argc, const char* argn[], const char* argv[]) { | |
| 45 for (uint32_t i = 0; i < argc; ++i) { | |
| 46 const std::string tag = argn[i]; | |
| 47 if (tag == "chunk_size") chunk_size_ = strtol(argv[i], 0, 0); | |
| 48 if (tag == "url") url_ = argv[i]; | |
| 49 if (tag == "to_file") stream_to_file_ = strtol(argv[i], 0, 0); | |
| 50 if (tag == "debug") debug_ = strtol(argv[i], 0, 0); | |
| 51 if (tag == "pdebug") pdebug_ = strtol(argv[i], 0, 0); | |
| 52 // ignore other tags | |
| 53 } | |
| 54 } | |
| 55 | |
| 56 public: | |
| 57 void Message(const string& s) { | |
| 58 ostringstream stream; | |
| 59 stream << pp_instance() << ": " << s; | |
| 60 pp::Var message(stream.str()); | |
| 61 PostMessage(message); | |
| 62 } | |
| 63 | |
| 64 | |
| 65 void Debug(const string& s) { | |
| 66 if (debug_) { | |
| 67 std::cout << "DEBUG: " << s; | |
| 68 } | |
| 69 if (pdebug_) { | |
| 70 Message("DEBUG: " + s); | |
| 71 } | |
| 72 } | |
| 73 | |
| 74 explicit MyInstance(PP_Instance instance) | |
| 75 : pp::Instance(instance), | |
| 76 url_("no_url_given.html"), | |
| 77 stream_to_file_(true), | |
| 78 chunk_size_(kDefaultChunkSize), | |
| 79 debug_(false), | |
| 80 pdebug_(false) { | |
| 81 } | |
| 82 | |
| 83 virtual ~MyInstance() {} | |
| 84 | |
| 85 // Defined below. This function does the real work by delegating it to | |
| 86 // either ReaderStreamAsFile or ReaderResponseBody | |
| 87 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]); | |
| 88 }; | |
| 89 | |
| 90 | |
| 91 | |
| 92 class ReaderStreamAsFile { | |
| 93 private: | |
| 94 uint32_t current_offset_; | |
| 95 uint32_t chunk_size_; | |
| 96 char* buffer_; | |
| 97 pp::URLResponseInfo* response_info_; | |
| 98 pp::FileRef* file_ref_; | |
| 99 pp::FileIO* file_io_; | |
| 100 MyInstance* instance_; | |
| 101 pp::URLLoader loader_; | |
| 102 | |
| 103 // forward to instance | |
| 104 void Message(const string& s) { | |
| 105 instance_->Message(s); | |
| 106 } | |
| 107 | |
| 108 void Debug(const string& s) { | |
| 109 instance_->Debug(s); | |
| 110 } | |
| 111 | |
| 112 static void ReadCompleteCallback(void* thiz, int32_t result) { | |
| 113 ReaderStreamAsFile* reader = static_cast<ReaderStreamAsFile*>(thiz); | |
| 114 ostringstream stream; | |
| 115 stream << "ReadCompleteCallback Bytes Read: " << result; | |
| 116 reader->Debug(stream.str()); | |
| 117 if (result <= 0) { | |
| 118 reader->Message("COMPLETE"); | |
| 119 return; | |
| 120 } | |
| 121 | |
| 122 reader->current_offset_ += result; | |
| 123 reader->ReadMore(); | |
| 124 } | |
| 125 | |
| 126 void ReadMore() { | |
| 127 pp::CompletionCallback cc(ReadCompleteCallback, this); | |
| 128 cc.set_flags(PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); | |
| 129 int32_t rv = file_io_->Read(current_offset_, buffer_, chunk_size_, cc); | |
| 130 if (rv == PP_OK) { | |
| 131 cc.Run(rv); | |
| 132 } else if (rv != PP_OK_COMPLETIONPENDING) { | |
| 133 Message("Error: ReadMore unexpected rv"); | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 static void OpenFileCompleteCallback(void* thiz, int32_t result) { | |
| 138 ReaderStreamAsFile* reader = static_cast<ReaderStreamAsFile*>(thiz); | |
| 139 | |
| 140 if (result != PP_OK) { | |
| 141 reader->Message("Error: FileOpenCompleteCallback unexpected result"); | |
| 142 return; | |
| 143 } | |
| 144 | |
| 145 reader->ReadMore(); | |
| 146 } | |
| 147 | |
| 148 void OpenFile() { | |
| 149 file_ref_ = new pp::FileRef(loader_.GetResponseInfo().GetBodyAsFileRef()); | |
| 150 CHECK(!file_ref_->is_null()); | |
| 151 | |
| 152 file_io_ = new pp::FileIO(instance_); | |
| 153 CHECK(!file_io_->is_null()); | |
| 154 | |
| 155 pp::CompletionCallback cc(OpenFileCompleteCallback, this); | |
| 156 int32_t rv = file_io_->Open(*file_ref_, PP_FILEOPENFLAG_READ, cc); | |
| 157 if (rv != PP_OK_COMPLETIONPENDING) { | |
| 158 Message("Error: OpenFile unexpected rv"); | |
| 159 } | |
| 160 } | |
| 161 | |
| 162 static void FinishCompleteCallback(void* thiz, int32_t result) { | |
| 163 ReaderStreamAsFile* reader = static_cast<ReaderStreamAsFile*>(thiz); | |
| 164 if (result != PP_OK) { | |
| 165 reader->Message("Error: FinishCompleteCallback unexpected result"); | |
| 166 return; | |
| 167 } | |
| 168 | |
| 169 reader->OpenFile(); | |
| 170 } | |
| 171 | |
| 172 void Finish() { | |
| 173 pp::CompletionCallback cc(FinishCompleteCallback, this); | |
| 174 cc.set_flags(PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); | |
| 175 int32_t rv = loader_.FinishStreamingToFile(cc); | |
| 176 if (rv == PP_OK) { | |
| 177 cc.Run(rv); | |
| 178 } else if (rv != PP_OK_COMPLETIONPENDING) { | |
| 179 Message("Error: Finish unexpected rv"); | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 // this callback handles both regular and "stream-to-file" mode | |
| 184 // But control flow diverges afterwards | |
| 185 static void OpenURLCompleteCallback(void* thiz, int32_t result) { | |
| 186 ReaderStreamAsFile* reader = static_cast<ReaderStreamAsFile*>(thiz); | |
| 187 | |
| 188 pp::URLResponseInfo response_info(reader->loader_.GetResponseInfo()); | |
| 189 CHECK(!response_info.is_null()); | |
| 190 int32_t status_code = response_info.GetStatusCode(); | |
| 191 if (status_code != 200) { | |
| 192 reader->Message("Error: OpenURLCompleteCallback unexpected status code"); | |
| 193 return; | |
| 194 } | |
| 195 | |
| 196 reader->Finish(); | |
| 197 } | |
| 198 | |
| 199 void OpenURL(const string& url) { | |
| 200 pp::URLRequestInfo request(instance_); | |
| 201 request.SetURL(url); | |
| 202 request.SetStreamToFile(true); | |
| 203 | |
| 204 pp::CompletionCallback cc(OpenURLCompleteCallback, this); | |
| 205 int32_t rv = loader_.Open(request, cc); | |
| 206 if (rv != PP_OK_COMPLETIONPENDING) { | |
| 207 Message("Error: OpenURL unexpected rv"); | |
| 208 } | |
| 209 } | |
| 210 | |
| 211 public: | |
| 212 ReaderStreamAsFile(MyInstance* instance, | |
| 213 uint32_t chunk_size, | |
| 214 const string& url) : | |
| 215 current_offset_(0), | |
| 216 chunk_size_(chunk_size), | |
| 217 buffer_(new char[chunk_size]), | |
| 218 response_info_(0), | |
| 219 file_ref_(0), | |
| 220 file_io_(0), | |
| 221 instance_(instance), | |
| 222 loader_(instance) { | |
| 223 OpenURL(url); | |
| 224 } | |
| 225 }; | |
| 226 | |
| 227 | |
| 228 class ReaderResponseBody { | |
| 229 private: | |
| 230 uint32_t chunk_size_; | |
| 231 char* buffer_; | |
| 232 MyInstance* instance_; | |
| 233 pp::URLLoader loader_; | |
| 234 | |
| 235 // forward to instance | |
| 236 void Message(const string& s) { | |
| 237 instance_->Message(s); | |
| 238 } | |
| 239 | |
| 240 void Debug(const string& s) { | |
| 241 instance_->Debug(s); | |
| 242 } | |
| 243 | |
| 244 static void ReadCompleteCallback(void* thiz, int32_t result) { | |
| 245 ReaderResponseBody* reader = static_cast<ReaderResponseBody*>(thiz); | |
| 246 ostringstream stream; | |
| 247 stream << "ReadCompleteCallback Bytes Read: " << result; | |
| 248 reader->Debug(stream.str()); | |
| 249 if (result <= 0) { | |
| 250 reader->Message("COMPLETE"); | |
| 251 return; | |
| 252 } | |
| 253 reader->ReadMore(); | |
| 254 } | |
| 255 | |
| 256 void ReadMore() { | |
| 257 pp::CompletionCallback cc(ReadCompleteCallback, this); | |
| 258 cc.set_flags(PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); | |
| 259 int rv = loader_.ReadResponseBody(buffer_, chunk_size_, cc); | |
| 260 if (rv == PP_OK) { | |
| 261 cc.Run(rv); | |
| 262 } else if (rv != PP_OK_COMPLETIONPENDING) { | |
| 263 Message("Error: ReadMore unexpected rv"); | |
| 264 } | |
| 265 } | |
| 266 | |
| 267 static void LoadCompleteCallback(void* thiz, int32_t result) { | |
| 268 ReaderResponseBody* reader = static_cast<ReaderResponseBody*>(thiz); | |
| 269 ostringstream stream; | |
| 270 stream << "LoadCompleteCallback: " << result; | |
| 271 reader->Debug(stream.str()); | |
| 272 pp::URLResponseInfo response_info(reader->loader_.GetResponseInfo()); | |
| 273 CHECK(!response_info.is_null()); | |
| 274 int32_t status_code = response_info.GetStatusCode(); | |
| 275 if (status_code != 200) { | |
| 276 reader->Message("Error: LoadCompleteCallback unexpected status code"); | |
| 277 return; | |
| 278 } | |
| 279 | |
| 280 reader->ReadMore(); | |
| 281 } | |
| 282 | |
| 283 public: | |
| 284 ReaderResponseBody(MyInstance* instance, | |
| 285 uint32_t chunk_size, | |
| 286 const string& url) : | |
| 287 chunk_size_(chunk_size), | |
| 288 buffer_(new char[chunk_size]), | |
| 289 instance_(instance), | |
| 290 loader_(instance) { | |
| 291 pp::URLRequestInfo request(instance_); | |
| 292 request.SetURL(url); | |
| 293 request.SetStreamToFile(false); | |
| 294 | |
| 295 pp::CompletionCallback cc(LoadCompleteCallback, this); | |
| 296 int32_t rv = loader_.Open(request, cc); | |
| 297 if (rv != PP_OK_COMPLETIONPENDING) { | |
| 298 Message("Error: ReaderResponseBody: unexpected rv"); | |
| 299 } | |
| 300 } | |
| 301 }; | |
| 302 | |
| 303 // Defined here because of circular class visibility issues | |
| 304 bool MyInstance::Init(uint32_t argc, const char* argn[], const char* argv[]) { | |
| 305 ParseArgs(argc, argn, argv); | |
| 306 if (stream_to_file_) { | |
| 307 new ReaderStreamAsFile(this, chunk_size_, url_); | |
| 308 } else { | |
| 309 new ReaderResponseBody(this, chunk_size_, url_); | |
| 310 } | |
| 311 return true; | |
| 312 } | |
| 313 | |
| 314 // standard boilerplate code below | |
| 315 class MyModule : public pp::Module { | |
| 316 public: | |
| 317 virtual pp::Instance* CreateInstance(PP_Instance instance) { | |
| 318 return new MyInstance(instance); | |
| 319 } | |
| 320 }; | |
| 321 | |
| 322 namespace pp { | |
| 323 Module* CreateModule() { | |
| 324 return new MyModule(); | |
| 325 } | |
| 326 } | |
| OLD | NEW |