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

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

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

Powered by Google App Engine
This is Rietveld 408576698