Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(516)

Side by Side Diff: ppapi/proxy/url_loader_resource.cc

Issue 11416363: Implementation of URLLoader using PluginResource/ResourceHost. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 #include "ppapi/proxy/url_loader_resource.h"
6
7 #include "base/logging.h"
8 #include "ppapi/c/pp_completion_callback.h"
9 #include "ppapi/c/pp_errors.h"
10 #include "ppapi/c/ppb_url_loader.h"
11 #include "ppapi/c/trusted/ppb_url_loader_trusted.h"
12 #include "ppapi/proxy/dispatch_reply_message.h"
13 #include "ppapi/proxy/ppapi_messages.h"
14 #include "ppapi/proxy/ppb_file_ref_proxy.h"
15 #include "ppapi/proxy/url_request_info_resource.h"
16 #include "ppapi/proxy/url_response_info_resource.h"
17 #include "ppapi/shared_impl/ppapi_globals.h"
18 #include "ppapi/shared_impl/url_response_info_data.h"
19 #include "ppapi/thunk/enter.h"
20 #include "ppapi/thunk/resource_creation_api.h"
21
22 using ppapi::thunk::EnterResourceNoLock;
23 using ppapi::thunk::PPB_URLLoader_API;
24 using ppapi::thunk::PPB_URLRequestInfo_API;
25
26 #ifdef _MSC_VER
27 // Do not warn about use of std::copy with raw pointers.
28 #pragma warning(disable : 4996)
29 #endif
30
31 namespace ppapi {
32 namespace proxy {
33
34 URLLoaderResource::URLLoaderResource(Connection connection,
35 PP_Instance instance)
36 : PluginResource(connection, instance),
37 mode_(MODE_WAITING_TO_OPEN),
38 bytes_sent_(0),
39 total_bytes_to_be_sent_(-1),
40 bytes_received_(0),
41 total_bytes_to_be_received_(-1),
42 user_buffer_(NULL),
43 user_buffer_size_(0),
44 done_status_(PP_OK_COMPLETIONPENDING),
45 is_streaming_to_file_(false),
46 is_asynchronous_load_suspended_(false) {
47 SendCreate(RENDERER, PpapiHostMsg_URLLoader_Create());
48 }
49
50 URLLoaderResource::URLLoaderResource(Connection connection,
51 PP_Instance instance,
52 int pending_main_document_loader_id,
53 const ppapi::URLResponseInfoData& data)
54 : PluginResource(connection, instance),
55 mode_(MODE_OPENING),
56 bytes_sent_(0),
57 total_bytes_to_be_sent_(-1),
58 bytes_received_(0),
59 total_bytes_to_be_received_(-1),
60 user_buffer_(NULL),
61 user_buffer_size_(0),
62 done_status_(PP_OK_COMPLETIONPENDING),
63 is_streaming_to_file_(false),
64 is_asynchronous_load_suspended_(false) {
65 AttachToPendingHost(RENDERER, pending_main_document_loader_id);
66 SaveResponseInfo(data);
67 }
68
69 URLLoaderResource::~URLLoaderResource() {
70 }
71
72 PPB_URLLoader_API* URLLoaderResource::AsPPB_URLLoader_API() {
73 return this;
74 }
75
76 int32_t URLLoaderResource::Open(PP_Resource request_id,
77 scoped_refptr<TrackedCallback> callback) {
78 EnterResourceNoLock<PPB_URLRequestInfo_API> enter_request(request_id, true);
79 if (enter_request.failed()) {
80 Log(PP_LOGLEVEL_ERROR,
81 "PPB_URLLoader.Open: invalid request resource ID. (Hint to C++ wrapper"
82 " users: use the ResourceRequest constructor that takes an instance or"
83 " else the request will be null.)");
84 return PP_ERROR_BADARGUMENT;
85 }
86 return Open(enter_request.object()->GetData(), 0, callback);
87 }
88
89 int32_t URLLoaderResource::Open(
90 const ::ppapi::URLRequestInfoData& request_data,
91 int requestor_pid,
92 scoped_refptr<TrackedCallback> callback) {
93 int32_t rv = ValidateCallback(callback);
94 if (rv != PP_OK)
95 return rv;
96 if (mode_ != MODE_WAITING_TO_OPEN)
97 return PP_ERROR_INPROGRESS;
98
99 request_data_ = request_data;
100
101 mode_ = MODE_OPENING;
102 is_asynchronous_load_suspended_ = false;
103
104 RegisterCallback(callback);
105 Post(RENDERER, PpapiHostMsg_URLLoader_Open(request_data));
106 return PP_OK_COMPLETIONPENDING;
107 }
108
109 int32_t URLLoaderResource::FollowRedirect(
110 scoped_refptr<TrackedCallback> callback) {
111 int32_t rv = ValidateCallback(callback);
112 if (rv != PP_OK)
113 return rv;
114 if (mode_ != MODE_OPENING)
115 return PP_ERROR_INPROGRESS;
116
117 SetDefersLoading(false); // Allow the redirect to continue.
118 RegisterCallback(callback);
119 return PP_OK_COMPLETIONPENDING;
120 }
121
122 PP_Bool URLLoaderResource::GetUploadProgress(int64_t* bytes_sent,
123 int64_t* total_bytes_to_be_sent) {
124 if (!request_data_.record_upload_progress) {
125 *bytes_sent = 0;
126 *total_bytes_to_be_sent = 0;
127 return PP_FALSE;
128 }
129 *bytes_sent = bytes_sent_;
130 *total_bytes_to_be_sent = total_bytes_to_be_sent_;
131 return PP_TRUE;
132 }
133
134 PP_Bool URLLoaderResource::GetDownloadProgress(
135 int64_t* bytes_received,
136 int64_t* total_bytes_to_be_received) {
137 if (!request_data_.record_download_progress) {
138 *bytes_received = 0;
139 *total_bytes_to_be_received = 0;
140 return PP_FALSE;
141 }
142 *bytes_received = bytes_received_;
143 *total_bytes_to_be_received = total_bytes_to_be_received_;
144 return PP_TRUE;
145 }
146
147 PP_Resource URLLoaderResource::GetResponseInfo() {
148 if (response_info_.get())
149 return response_info_->GetReference();
150 return 0;
151 }
152
153 int32_t URLLoaderResource::ReadResponseBody(
154 void* buffer,
155 int32_t bytes_to_read,
156 scoped_refptr<TrackedCallback> callback) {
157 int32_t rv = ValidateCallback(callback);
158 if (rv != PP_OK)
159 return rv;
160 if (!response_info_.get() ||
161 !response_info_->data().body_as_file_ref.resource.is_null())
162 return PP_ERROR_FAILED;
163 if (bytes_to_read <= 0 || !buffer)
164 return PP_ERROR_BADARGUMENT;
165
166 user_buffer_ = static_cast<char*>(buffer);
167 user_buffer_size_ = bytes_to_read;
168
169 if (!buffer_.empty())
170 return FillUserBuffer();
171
172 // We may have already reached EOF.
173 if (done_status_ != PP_OK_COMPLETIONPENDING) {
174 user_buffer_ = NULL;
175 user_buffer_size_ = 0;
176 return done_status_;
177 }
178
179 RegisterCallback(callback);
180 return PP_OK_COMPLETIONPENDING;
181 }
182
183 int32_t URLLoaderResource::FinishStreamingToFile(
184 scoped_refptr<TrackedCallback> callback) {
185 int32_t rv = ValidateCallback(callback);
186 if (rv != PP_OK)
187 return rv;
188 if (!response_info_.get() ||
189 response_info_->data().body_as_file_ref.resource.is_null())
190 return PP_ERROR_FAILED;
191
192 // We may have already reached EOF.
193 if (done_status_ != PP_OK_COMPLETIONPENDING)
194 return done_status_;
195
196 is_streaming_to_file_ = true;
197 if (is_asynchronous_load_suspended_)
198 SetDefersLoading(false);
199
200 // Wait for didFinishLoading / didFail.
201 RegisterCallback(callback);
202 return PP_OK_COMPLETIONPENDING;
203 }
204
205 void URLLoaderResource::Close() {
206 mode_ = MODE_LOAD_COMPLETE;
207 done_status_ = PP_ERROR_ABORTED;
208
209 Post(RENDERER, PpapiHostMsg_URLLoader_Close());
210
211 // Abort the callbacks, the plugin doesn't want to be called back after this.
212 // TODO(brettw) this should fix bug 69457, mark it fixed. ============
213 if (TrackedCallback::IsPending(pending_callback_))
214 pending_callback_->PostAbort();
215 }
216
217 void URLLoaderResource::GrantUniversalAccess() {
218 Post(RENDERER, PpapiHostMsg_URLLoader_GrantUniversalAccess());
219 }
220
221 void URLLoaderResource::OnReplyReceived(
222 const ResourceMessageReplyParams& params,
223 const IPC::Message& msg) {
224 IPC_BEGIN_MESSAGE_MAP(URLLoaderResource, msg)
225 case PpapiPluginMsg_URLLoader_SendData::ID:
226 // Special message, manually dispatch since we don't want the automatic
227 // unpickling.
228 OnPluginMsgSendData(params, msg);
229 break;
230
231 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
232 PpapiPluginMsg_URLLoader_ReceivedResponse,
233 OnPluginMsgReceivedResponse)
234 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
235 PpapiPluginMsg_URLLoader_FinishedLoading,
236 OnPluginMsgFinishedLoading)
237 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
238 PpapiPluginMsg_URLLoader_UpdateProgress,
239 OnPluginMsgUpdateProgress)
240 IPC_END_MESSAGE_MAP()
241 }
242
243 void URLLoaderResource::OnPluginMsgReceivedResponse(
244 const ResourceMessageReplyParams& params,
245 const URLResponseInfoData& data) {
246 SaveResponseInfo(data);
247 RunCallback(PP_OK);
248 }
249
250 void URLLoaderResource::OnPluginMsgSendData(
251 const ResourceMessageReplyParams& params,
252 const IPC::Message& message) {
253 PickleIterator iter(message);
254 const char* data;
255 int data_length;
256 if (!iter.ReadData(&data, &data_length)) {
257 NOTREACHED() << "Expecting data";
258 return;
259 }
260
261 mode_ = MODE_STREAMING_DATA;
262 buffer_.insert(buffer_.end(), data, data + data_length);
263
264 // To avoid letting the network stack download an entire stream all at once,
265 // defer loading when we have enough buffer.
266 // Check for this before we run the callback, even though that could move
267 // data out of the buffer. Doing anything after the callback is unsafe.
268 DCHECK(request_data_.prefetch_buffer_lower_threshold <
269 request_data_.prefetch_buffer_upper_threshold);
270 if (!is_streaming_to_file_ &&
271 !is_asynchronous_load_suspended_ &&
272 (buffer_.size() >= static_cast<size_t>(
273 request_data_.prefetch_buffer_upper_threshold))) {
274 DVLOG(1) << "Suspending async load - buffer size: " << buffer_.size();
275 SetDefersLoading(true);
276 }
277
278 if (user_buffer_)
279 RunCallback(FillUserBuffer());
280 else
281 DCHECK(!TrackedCallback::IsPending(pending_callback_));
282 }
283
284 void URLLoaderResource::OnPluginMsgFinishedLoading(
285 const ResourceMessageReplyParams& params,
286 int32_t result) {
287 mode_ = MODE_LOAD_COMPLETE;
288 done_status_ = result;
289 user_buffer_ = NULL;
290 user_buffer_size_ = 0;
291
292 // If the client hasn't called any function that takes a callback since
293 // the initial call to Open, or called ReadResponseBody and got a
294 // synchronous return, then the callback will be NULL.
295 if (TrackedCallback::IsPending(pending_callback_))
296 RunCallback(done_status_);
297 }
298
299 void URLLoaderResource::OnPluginMsgUpdateProgress(
300 const ResourceMessageReplyParams& params,
301 int64_t bytes_sent,
302 int64_t total_bytes_to_be_sent,
303 int64_t bytes_received,
304 int64_t total_bytes_to_be_received) {
305 bytes_sent_ = bytes_sent;
306 total_bytes_to_be_sent_ = total_bytes_to_be_sent;
307 bytes_received_ = bytes_received;
308 total_bytes_to_be_received_ = total_bytes_to_be_received;
309 }
310
311 void URLLoaderResource::SetDefersLoading(bool defers_loading) {
312 Post(RENDERER, PpapiHostMsg_URLLoader_SetDeferLoading(defers_loading));
313 }
314
315 int32_t URLLoaderResource::ValidateCallback(
316 scoped_refptr<TrackedCallback> callback) {
317 DCHECK(callback);
318 if (TrackedCallback::IsPending(pending_callback_))
319 return PP_ERROR_INPROGRESS;
320 return PP_OK;
321 }
322
323 void URLLoaderResource::RegisterCallback(
324 scoped_refptr<TrackedCallback> callback) {
325 DCHECK(!TrackedCallback::IsPending(pending_callback_));
326 pending_callback_ = callback;
327 }
328
329 void URLLoaderResource::RunCallback(int32_t result) {
330 // This may be null when this is a main document loader.
331 if (!pending_callback_.get())
332 return;
333
334 // If |user_buffer_| was set as part of registering a callback, the paths
335 // which trigger that callack must have cleared it since the callback is now
336 // free to delete it.
337 DCHECK(!user_buffer_);
338
339 // As a second line of defense, clear the |user_buffer_| in case the
340 // callbacks get called in an unexpected order.
341 user_buffer_ = NULL;
342 user_buffer_size_ = 0;
343 pending_callback_->Run(result);
344 }
345
346 void URLLoaderResource::SaveResponseInfo(const URLResponseInfoData& data) {
347 // Create a proxy resource for the the file ref host resource if needed.
348 PP_Resource body_as_file_ref = 0;
349 if (!data.body_as_file_ref.resource.is_null()) {
350 thunk::EnterResourceCreationNoLock enter(pp_instance());
351 body_as_file_ref =
352 enter.functions()->CreateFileRef(data.body_as_file_ref);
353 }
354 response_info_ = new URLResponseInfoResource(
355 connection(), pp_instance(), data, body_as_file_ref);
356 }
357
358 size_t URLLoaderResource::FillUserBuffer() {
359 DCHECK(user_buffer_);
360 DCHECK(user_buffer_size_);
361
362 size_t bytes_to_copy = std::min(buffer_.size(), user_buffer_size_);
363 std::copy(buffer_.begin(), buffer_.begin() + bytes_to_copy, user_buffer_);
364 buffer_.erase(buffer_.begin(), buffer_.begin() + bytes_to_copy);
365
366 // If the buffer is getting too empty, resume asynchronous loading.
367 if (is_asynchronous_load_suspended_ &&
368 buffer_.size() <= static_cast<size_t>(
369 request_data_.prefetch_buffer_lower_threshold)) {
370 DVLOG(1) << "Resuming async load - buffer size: " << buffer_.size();
371 SetDefersLoading(false);
372 }
373
374 // Reset for next time.
375 user_buffer_ = NULL;
376 user_buffer_size_ = 0;
377 return bytes_to_copy;
378 }
379
380 } // namespace proxy
381 } // namespace ppapi
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698