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