Home | History | Annotate | Download | only in url_loader
      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.
      4 
      5 // This example shows how to use the URLLoader in "stream to file" mode where
      6 // the browser writes incoming data to a file, which you can read out via the
      7 // file I/O APIs.
      8 //
      9 // This example uses PostMessage between the plugin and the url_loader.html
     10 // page in this directory to start the load and to communicate the result.
     11 
     12 #include "ppapi/c/ppb_file_io.h"
     13 #include "ppapi/cpp/file_io.h"
     14 #include "ppapi/cpp/file_ref.h"
     15 #include "ppapi/cpp/instance.h"
     16 #include "ppapi/cpp/module.h"
     17 #include "ppapi/cpp/url_loader.h"
     18 #include "ppapi/cpp/url_request_info.h"
     19 #include "ppapi/cpp/url_response_info.h"
     20 #include "ppapi/utility/completion_callback_factory.h"
     21 
     22 // When compiling natively on Windows, PostMessage can be #define-d to
     23 // something else.
     24 #ifdef PostMessage
     25 #undef PostMessage
     26 #endif
     27 
     28 // Buffer size for reading network data.
     29 const int kBufSize = 1024;
     30 
     31 class MyInstance : public pp::Instance {
     32  public:
     33   explicit MyInstance(PP_Instance instance)
     34       : pp::Instance(instance) {
     35     factory_.Initialize(this);
     36   }
     37   virtual ~MyInstance() {
     38     // Make sure to explicitly close the loader. If somebody else is holding a
     39     // reference to the URLLoader object when this class goes out of scope (so
     40     // the URLLoader outlives "this"), and you have an outstanding read
     41     // request, the URLLoader will write into invalid memory.
     42     loader_.Close();
     43   }
     44 
     45   // Handler for the page sending us messages.
     46   virtual void HandleMessage(const pp::Var& message_data);
     47 
     48  private:
     49   // Called to initiate the request.
     50   void StartRequest(const std::string& url);
     51 
     52   // Callback for the URLLoader to tell us it finished opening the connection.
     53   void OnOpenComplete(int32_t result);
     54 
     55   // Callback for when the file is completely filled with the download
     56   void OnStreamComplete(int32_t result);
     57 
     58   void OnOpenFileComplete(int32_t result);
     59   void OnReadComplete(int32_t result);
     60 
     61   // Forwards the given string to the page.
     62   void ReportResponse(const std::string& data);
     63 
     64   // Generates completion callbacks scoped to this class.
     65   pp::CompletionCallbackFactory<MyInstance> factory_;
     66 
     67   pp::URLLoader loader_;
     68   pp::URLResponseInfo response_;
     69   pp::FileRef dest_file_;
     70   pp::FileIO file_io_;
     71 
     72   // The buffer used for the current read request. This is filled and then
     73   // 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 
     80 void MyInstance::HandleMessage(const pp::Var& message_data) {
     81   if (message_data.is_string() && message_data.AsString() == "go")
     82     StartRequest("./fetched_content.html");
     83 }
     84 
     85 void 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 
     98 void 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 
    110 void 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 
    120 void 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 
    132 void 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 
    147 void 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.
    153 class 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 
    164 namespace pp {
    165 
    166 // Factory function for your specialization of the Module object.
    167 Module* CreateModule() {
    168   return new MyModule();
    169 }
    170 
    171 }  // namespace pp
    172