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