Home | History | Annotate | Download | only in plugin
      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 #ifndef NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_FILE_DOWNLOADER_H_
      6 #define NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_FILE_DOWNLOADER_H_
      7 
      8 #include <deque>
      9 
     10 #include "native_client/src/include/nacl_macros.h"
     11 #include "native_client/src/include/nacl_string.h"
     12 #include "native_client/src/trusted/validator/nacl_file_info.h"
     13 #include "ppapi/c/private/pp_file_handle.h"
     14 #include "ppapi/c/trusted/ppb_file_io_trusted.h"
     15 #include "ppapi/c/trusted/ppb_url_loader_trusted.h"
     16 #include "ppapi/cpp/file_io.h"
     17 #include "ppapi/cpp/instance.h"
     18 #include "ppapi/cpp/url_loader.h"
     19 #include "ppapi/cpp/url_response_info.h"
     20 #include "ppapi/native_client/src/trusted/plugin/callback_source.h"
     21 #include "ppapi/utility/completion_callback_factory.h"
     22 
     23 namespace plugin {
     24 
     25 class Plugin;
     26 
     27 typedef enum {
     28   DOWNLOAD_TO_FILE = 0,
     29   DOWNLOAD_TO_BUFFER,
     30   DOWNLOAD_STREAM,
     31   DOWNLOAD_NONE
     32 } DownloadMode;
     33 
     34 typedef enum {
     35   SCHEME_CHROME_EXTENSION,
     36   SCHEME_DATA,
     37   SCHEME_OTHER
     38 } UrlSchemeType;
     39 
     40 typedef std::vector<char>* FileStreamData;
     41 typedef CallbackSource<FileStreamData> StreamCallbackSource;
     42 typedef pp::CompletionCallbackWithOutput<FileStreamData> StreamCallback;
     43 
     44 // A class that wraps PPAPI URLLoader and FileIO functionality for downloading
     45 // the url into a file and providing an open file descriptor.
     46 class FileDownloader {
     47  public:
     48   // Ctor initializes |instance_| to NULL, be sure to call Initialize() before
     49   // calling Open(), or Open() will fail.
     50   FileDownloader()
     51       : instance_(NULL),
     52         file_open_notify_callback_(pp::BlockUntilComplete()),
     53         stream_finish_callback_(pp::BlockUntilComplete()),
     54         file_handle_(PP_kInvalidFileHandle),
     55         file_io_trusted_interface_(NULL),
     56         url_loader_trusted_interface_(NULL),
     57         open_time_(-1),
     58         mode_(DOWNLOAD_NONE),
     59         open_and_stream_(true),
     60         url_scheme_(SCHEME_OTHER),
     61         data_stream_callback_source_(NULL) {}
     62   ~FileDownloader() {}
     63 
     64   // Initialize() can only be called once during the lifetime of this instance.
     65   void Initialize(Plugin* instance);
     66 
     67   // Issues a GET on |url| to start downloading the response into a file,
     68   // and finish streaming it. |callback| will be run after streaming is
     69   // done or if an error prevents streaming from completing.
     70   // Returns true when callback is scheduled to be called on success or failure.
     71   // Returns false if callback is NULL, Initialize() has not been called or if
     72   // the PPB_FileIO_Trusted interface is not available.
     73   // If |record_progress| is true, then download progress will be recorded,
     74   // and can be polled through GetDownloadProgress().
     75   // If |progress_callback| is not NULL and |record_progress| is true,
     76   // then the callback will be invoked for every progress update received
     77   // by the loader.
     78   bool Open(const nacl::string& url,
     79             DownloadMode mode,
     80             const pp::CompletionCallback& callback,
     81             bool record_progress,
     82             PP_URLLoaderTrusted_StatusCallback progress_callback);
     83 
     84   // Similar to Open(), but used for streaming the |url| data directly to the
     85   // caller without writing to a temporary file. The callbacks provided by
     86   // |stream_callback_source| are expected to copy the data before returning.
     87   // |callback| is called once the response headers are received,
     88   // and streaming must be completed separately via FinishStreaming().
     89   bool OpenStream(const nacl::string& url,
     90                   const pp::CompletionCallback& callback,
     91                   StreamCallbackSource* stream_callback_source);
     92 
     93   // Finish streaming the response body for a URL request started by either
     94   // Open() or OpenStream().  If DownloadMode is DOWNLOAD_TO_FILE,
     95   // then the response body is streamed to a file, the file is opened and
     96   // a file descriptor is made available.  Runs the given |callback| when
     97   // streaming is done.
     98   void FinishStreaming(const pp::CompletionCallback& callback);
     99 
    100   // Bypasses downloading and takes a handle to the open file. To get the fd,
    101   // call GetFileInfo().
    102   void OpenFast(const nacl::string& url, PP_FileHandle file_handle,
    103                 uint64_t file_token_lo, uint64_t file_token_hi);
    104 
    105   // Return a structure describing the file opened, including a file desc.
    106   // If downloading and opening succeeded, this returns a valid read-only
    107   // POSIX file descriptor.  On failure, the return value is an invalid
    108   // descriptor.  The file descriptor is owned by this instance, so the
    109   // delegate does not have to close it.
    110   struct NaClFileInfo GetFileInfo();
    111 
    112   // Returns the time delta between the call to Open() and this function.
    113   int64_t TimeSinceOpenMilliseconds() const;
    114 
    115   // The value of |url_| changes over the life of this instance.  When the file
    116   // is first opened, |url_| is a copy of the URL used to open the file, which
    117   // can be a relative URL.  Once the GET request has finished, and the contents
    118   // of the file represented by |url_| are available, |url_| is the full URL
    119   // including the scheme, host and full path.
    120   const nacl::string& url() const { return url_; }
    121 
    122   // Returns the url passed to Open().
    123   const nacl::string& url_to_open() const { return url_to_open_; }
    124 
    125   // Returns the PP_Resource of the active URL loader, or kInvalidResource.
    126   PP_Resource url_loader() const { return url_loader_.pp_resource(); }
    127 
    128   // GetDownloadProgress() returns the current download progress, which is
    129   // meaningful after Open() has been called. Progress only refers to the
    130   // response body and does not include the headers.
    131   //
    132   // This data is only available if the |record_progress| true in the
    133   // Open() call.  If progress is being recorded, then |bytes_received|
    134   // will be set to the number of bytes received thus far,
    135   // and |total_bytes_to_be_received| will be set to the total number
    136   // of bytes to be received.  The total bytes to be received may be unknown,
    137   // in which case |total_bytes_to_be_received| will be set to -1.
    138   bool GetDownloadProgress(int64_t* bytes_received,
    139                            int64_t* total_bytes_to_be_received) const;
    140 
    141   // Returns the buffer used for DOWNLOAD_TO_BUFFER mode.
    142   const std::deque<char>& buffer() const { return buffer_; }
    143 
    144   bool streaming_to_file() const;
    145   bool streaming_to_buffer() const;
    146   bool streaming_to_user() const;
    147   bool not_streaming() const;
    148 
    149   int status_code() const { return status_code_; }
    150   nacl::string GetResponseHeaders() const;
    151 
    152  private:
    153   NACL_DISALLOW_COPY_AND_ASSIGN(FileDownloader);
    154   // This class loads and opens the file in three steps for DOWNLOAD_TO_FILE:
    155   //   1) Ask the browser to start streaming |url_| as a file.
    156   //   2) Ask the browser to finish streaming if headers indicate success.
    157   //   3) Ask the browser to open the file, so we can get the file descriptor.
    158   // For DOWNLOAD_TO_BUFFER, the process is very similar:
    159   //   1) Ask the browser to start streaming |url_| to an internal buffer.
    160   //   2) Ask the browser to finish streaming to |temp_buffer_| on success.
    161   //   3) Wait for streaming to finish, filling |buffer_| incrementally.
    162   // Each step is done asynchronously using callbacks.  We create callbacks
    163   // through a factory to take advantage of ref-counting.
    164   // DOWNLOAD_STREAM is similar to DOWNLOAD_TO_BUFFER except the downloaded
    165   // data is passed directly to the user instead of saved in a buffer.
    166   // The public Open*() functions start step 1), and the public FinishStreaming
    167   // function proceeds to step 2) and 3).
    168   bool InitialResponseIsValid(int32_t pp_error);
    169   void URLLoadStartNotify(int32_t pp_error);
    170   void URLLoadFinishNotify(int32_t pp_error);
    171   void URLBufferStartNotify(int32_t pp_error);
    172   void URLReadBodyNotify(int32_t pp_error);
    173   void StreamFinishNotify(int32_t pp_error);
    174 
    175   Plugin* instance_;
    176   nacl::string url_to_open_;
    177   nacl::string url_;
    178   pp::URLResponseInfo url_response_;
    179   pp::CompletionCallback file_open_notify_callback_;
    180   pp::CompletionCallback stream_finish_callback_;
    181   pp::FileIO file_reader_;
    182   PP_FileHandle file_handle_;
    183   struct NaClFileToken file_token_;
    184   const PPB_FileIOTrusted* file_io_trusted_interface_;
    185   const PPB_URLLoaderTrusted* url_loader_trusted_interface_;
    186   pp::URLLoader url_loader_;
    187   pp::CompletionCallbackFactory<FileDownloader> callback_factory_;
    188   int64_t open_time_;
    189   int32_t status_code_;
    190   DownloadMode mode_;
    191   bool open_and_stream_;
    192   static const uint32_t kTempBufferSize = 2048;
    193   std::vector<char> temp_buffer_;
    194   std::deque<char> buffer_;
    195   UrlSchemeType url_scheme_;
    196   StreamCallbackSource* data_stream_callback_source_;
    197 };
    198 }  // namespace plugin;
    199 #endif  // NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_FILE_DOWNLOADER_H_
    200