OLD | NEW |
| (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/ppb_url_loader_proxy.h" | |
6 | |
7 #include <algorithm> | |
8 #include <deque> | |
9 #include <vector> | |
10 | |
11 #include "base/bind.h" | |
12 #include "base/logging.h" | |
13 #include "build/build_config.h" | |
14 #include "ppapi/c/pp_completion_callback.h" | |
15 #include "ppapi/c/pp_errors.h" | |
16 #include "ppapi/c/pp_resource.h" | |
17 #include "ppapi/c/ppb_url_loader.h" | |
18 #include "ppapi/c/private/ppb_proxy_private.h" | |
19 #include "ppapi/c/trusted/ppb_url_loader_trusted.h" | |
20 #include "ppapi/proxy/enter_proxy.h" | |
21 #include "ppapi/proxy/host_dispatcher.h" | |
22 #include "ppapi/proxy/plugin_dispatcher.h" | |
23 #include "ppapi/proxy/plugin_resource_tracker.h" | |
24 #include "ppapi/proxy/ppapi_messages.h" | |
25 #include "ppapi/proxy/ppb_file_ref_proxy.h" | |
26 #include "ppapi/shared_impl/scoped_pp_resource.h" | |
27 #include "ppapi/shared_impl/tracked_callback.h" | |
28 #include "ppapi/thunk/enter.h" | |
29 #include "ppapi/thunk/ppb_url_loader_api.h" | |
30 #include "ppapi/thunk/ppb_url_request_info_api.h" | |
31 #include "ppapi/thunk/resource_creation_api.h" | |
32 #include "ppapi/thunk/thunk.h" | |
33 | |
34 #if defined(OS_LINUX) | |
35 #include <sys/shm.h> | |
36 #endif | |
37 | |
38 using ppapi::thunk::EnterResourceNoLock; | |
39 using ppapi::thunk::PPB_URLLoader_API; | |
40 using ppapi::thunk::ResourceCreationAPI; | |
41 | |
42 namespace ppapi { | |
43 namespace proxy { | |
44 | |
45 namespace { | |
46 | |
47 // The maximum size we'll read into the plugin without being explicitly | |
48 // asked for a larger buffer. | |
49 const int32_t kMaxReadBufferSize = 16777216; // 16MB | |
50 | |
51 #if !defined(OS_NACL) | |
52 // Called in the renderer when the byte counts have changed. We send a message | |
53 // to the plugin to synchronize its counts so it can respond to status polls | |
54 // from the plugin. | |
55 void UpdateResourceLoadStatus(PP_Instance pp_instance, | |
56 PP_Resource pp_resource, | |
57 int64 bytes_sent, | |
58 int64 total_bytes_to_be_sent, | |
59 int64 bytes_received, | |
60 int64 total_bytes_to_be_received) { | |
61 Dispatcher* dispatcher = HostDispatcher::GetForInstance(pp_instance); | |
62 if (!dispatcher) | |
63 return; | |
64 | |
65 PPBURLLoader_UpdateProgress_Params params; | |
66 params.instance = pp_instance; | |
67 params.resource.SetHostResource(pp_instance, pp_resource); | |
68 params.bytes_sent = bytes_sent; | |
69 params.total_bytes_to_be_sent = total_bytes_to_be_sent; | |
70 params.bytes_received = bytes_received; | |
71 params.total_bytes_to_be_received = total_bytes_to_be_received; | |
72 dispatcher->Send(new PpapiMsg_PPBURLLoader_UpdateProgress( | |
73 API_ID_PPB_URL_LOADER, params)); | |
74 } | |
75 #endif // !defined(OS_NACL) | |
76 | |
77 InterfaceProxy* CreateURLLoaderProxy(Dispatcher* dispatcher) { | |
78 return new PPB_URLLoader_Proxy(dispatcher); | |
79 } | |
80 | |
81 } // namespace | |
82 | |
83 // URLLoader ------------------------------------------------------------------- | |
84 | |
85 class URLLoader : public Resource, public PPB_URLLoader_API { | |
86 public: | |
87 URLLoader(const HostResource& resource); | |
88 virtual ~URLLoader(); | |
89 | |
90 // Resource overrides. | |
91 virtual PPB_URLLoader_API* AsPPB_URLLoader_API() OVERRIDE; | |
92 | |
93 // PPB_URLLoader_API implementation. | |
94 virtual int32_t Open(PP_Resource request_id, | |
95 scoped_refptr<TrackedCallback> callback) OVERRIDE; | |
96 virtual int32_t Open(const URLRequestInfoData& data, | |
97 int requestor_pid, | |
98 scoped_refptr<TrackedCallback> callback) OVERRIDE; | |
99 virtual int32_t FollowRedirect( | |
100 scoped_refptr<TrackedCallback> callback) OVERRIDE; | |
101 virtual PP_Bool GetUploadProgress(int64_t* bytes_sent, | |
102 int64_t* total_bytes_to_be_sent) OVERRIDE; | |
103 virtual PP_Bool GetDownloadProgress( | |
104 int64_t* bytes_received, | |
105 int64_t* total_bytes_to_be_received) OVERRIDE; | |
106 virtual PP_Resource GetResponseInfo() OVERRIDE; | |
107 virtual int32_t ReadResponseBody( | |
108 void* buffer, | |
109 int32_t bytes_to_read, | |
110 scoped_refptr<TrackedCallback> callback) OVERRIDE; | |
111 virtual int32_t FinishStreamingToFile( | |
112 scoped_refptr<TrackedCallback> callback) OVERRIDE; | |
113 virtual void Close() OVERRIDE; | |
114 virtual void GrantUniversalAccess() OVERRIDE; | |
115 virtual void SetStatusCallback( | |
116 PP_URLLoaderTrusted_StatusCallback cb) OVERRIDE; | |
117 virtual bool GetResponseInfoData(URLResponseInfoData* data) OVERRIDE; | |
118 | |
119 // Called when the browser has new up/download progress to report. | |
120 void UpdateProgress(const PPBURLLoader_UpdateProgress_Params& params); | |
121 | |
122 // Called when the browser responds to our ReadResponseBody request. | |
123 void ReadResponseBodyAck(int32_t result, const char* data); | |
124 | |
125 // Called when any callback other than the read callback has been executed. | |
126 void CallbackComplete(int32_t result); | |
127 | |
128 private: | |
129 // Reads the give bytes out of the buffer_, placing them in the given output | |
130 // buffer, and removes the bytes from the buffer. | |
131 // | |
132 // The size must be not more than the current size of the buffer. | |
133 void PopBuffer(void* output_buffer, int32_t output_size); | |
134 | |
135 PluginDispatcher* GetDispatcher() const { | |
136 return PluginDispatcher::GetForResource(this); | |
137 } | |
138 | |
139 // Initialized to -1. Will be set to nonnegative values by the UpdateProgress | |
140 // message when the values are known. | |
141 int64_t bytes_sent_; | |
142 int64_t total_bytes_to_be_sent_; | |
143 int64_t bytes_received_; | |
144 int64_t total_bytes_to_be_received_; | |
145 | |
146 // Current completion callback for the current phase of loading. We have only | |
147 // one thing (open, follow redirect, read, etc.) outstanding at once. | |
148 scoped_refptr<TrackedCallback> current_callback_; | |
149 | |
150 // When an asynchronous read is pending, this will contain the buffer to put | |
151 // the data. The current_callback_ will identify the read callback. | |
152 void* current_read_buffer_; | |
153 int32_t current_read_buffer_size_; | |
154 | |
155 // A buffer of all the data that's been sent to us from the host that we | |
156 // have yet to send out to the plugin. | |
157 std::deque<char> buffer_; | |
158 | |
159 // Cached copy of the response info. When nonzero, we're holding a reference | |
160 // to this resource. | |
161 PP_Resource response_info_; | |
162 | |
163 private: | |
164 DISALLOW_COPY_AND_ASSIGN(URLLoader); | |
165 }; | |
166 | |
167 URLLoader::URLLoader(const HostResource& resource) | |
168 : Resource(OBJECT_IS_PROXY, resource), | |
169 bytes_sent_(-1), | |
170 total_bytes_to_be_sent_(-1), | |
171 bytes_received_(-1), | |
172 total_bytes_to_be_received_(-1), | |
173 current_read_buffer_(NULL), | |
174 current_read_buffer_size_(0), | |
175 response_info_(0) { | |
176 } | |
177 | |
178 URLLoader::~URLLoader() { | |
179 if (response_info_) | |
180 PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(response_info_); | |
181 } | |
182 | |
183 PPB_URLLoader_API* URLLoader::AsPPB_URLLoader_API() { | |
184 return this; | |
185 } | |
186 | |
187 int32_t URLLoader::Open(PP_Resource request_id, | |
188 scoped_refptr<TrackedCallback> callback) { | |
189 EnterResourceNoLock<thunk::PPB_URLRequestInfo_API> enter(request_id, true); | |
190 if (enter.failed()) { | |
191 Log(PP_LOGLEVEL_ERROR, "PPB_URLLoader.Open: The URL you're requesting is " | |
192 " on a different security origin than your plugin. To request " | |
193 " cross-origin resources, see " | |
194 " PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS."); | |
195 return PP_ERROR_BADRESOURCE; | |
196 } | |
197 return Open(enter.object()->GetData(), 0, callback); | |
198 } | |
199 | |
200 int32_t URLLoader::Open(const URLRequestInfoData& data, | |
201 int requestor_pid, | |
202 scoped_refptr<TrackedCallback> callback) { | |
203 DCHECK_EQ(0, requestor_pid); // Used in-process only. | |
204 | |
205 if (TrackedCallback::IsPending(current_callback_)) | |
206 return PP_ERROR_INPROGRESS; | |
207 | |
208 current_callback_ = callback; | |
209 | |
210 GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_Open( | |
211 API_ID_PPB_URL_LOADER, host_resource(), data)); | |
212 return PP_OK_COMPLETIONPENDING; | |
213 } | |
214 | |
215 int32_t URLLoader::FollowRedirect(scoped_refptr<TrackedCallback> callback) { | |
216 if (TrackedCallback::IsPending(current_callback_)) | |
217 return PP_ERROR_INPROGRESS; | |
218 | |
219 current_callback_ = callback; | |
220 | |
221 GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_FollowRedirect( | |
222 API_ID_PPB_URL_LOADER, host_resource())); | |
223 return PP_OK_COMPLETIONPENDING; | |
224 } | |
225 | |
226 PP_Bool URLLoader::GetUploadProgress(int64_t* bytes_sent, | |
227 int64_t* total_bytes_to_be_sent) { | |
228 if (bytes_sent_ == -1) { | |
229 *bytes_sent = 0; | |
230 *total_bytes_to_be_sent = 0; | |
231 return PP_FALSE; | |
232 } | |
233 *bytes_sent = bytes_sent_; | |
234 *total_bytes_to_be_sent = total_bytes_to_be_sent_; | |
235 return PP_TRUE; | |
236 } | |
237 | |
238 PP_Bool URLLoader::GetDownloadProgress( | |
239 int64_t* bytes_received, | |
240 int64_t* total_bytes_to_be_received) { | |
241 if (bytes_received_ == -1) { | |
242 *bytes_received = 0; | |
243 *total_bytes_to_be_received = 0; | |
244 return PP_FALSE; | |
245 } | |
246 *bytes_received = bytes_received_; | |
247 *total_bytes_to_be_received = total_bytes_to_be_received_; | |
248 return PP_TRUE; | |
249 } | |
250 | |
251 PP_Resource URLLoader::GetResponseInfo() { | |
252 if (!response_info_) { | |
253 bool success = false; | |
254 URLResponseInfoData data; | |
255 GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_GetResponseInfo( | |
256 API_ID_PPB_URL_LOADER, host_resource(), &success, &data)); | |
257 if (!success) | |
258 return 0; | |
259 | |
260 // Create a proxy resource for the the file ref host resource if needed. | |
261 PP_Resource body_as_file_ref = 0; | |
262 if (!data.body_as_file_ref.resource.is_null()) { | |
263 body_as_file_ref = | |
264 PPB_FileRef_Proxy::DeserializeFileRef(data.body_as_file_ref); | |
265 } | |
266 | |
267 // Assumes ownership of body_as_file_ref. | |
268 thunk::EnterResourceCreationNoLock enter(pp_instance()); | |
269 response_info_ = enter.functions()->CreateURLResponseInfo( | |
270 pp_instance(), data, body_as_file_ref); | |
271 } | |
272 | |
273 // The caller expects to get a ref, and we want to keep holding ours. | |
274 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(response_info_); | |
275 return response_info_; | |
276 } | |
277 | |
278 int32_t URLLoader::ReadResponseBody(void* buffer, | |
279 int32_t bytes_to_read, | |
280 scoped_refptr<TrackedCallback> callback) { | |
281 if (!buffer || bytes_to_read <= 0) | |
282 return PP_ERROR_BADARGUMENT; // Must specify an output buffer. | |
283 if (TrackedCallback::IsPending(current_callback_)) | |
284 return PP_ERROR_INPROGRESS; // Can only have one request pending. | |
285 | |
286 if (buffer_.size()) { | |
287 // Special case: we've already buffered some data that we can synchronously | |
288 // return to the caller. Do so without making IPCs. | |
289 int32_t bytes_to_return = | |
290 std::min(bytes_to_read, static_cast<int32_t>(buffer_.size())); | |
291 PopBuffer(buffer, bytes_to_return); | |
292 return bytes_to_return; | |
293 } | |
294 | |
295 current_callback_ = callback; | |
296 current_read_buffer_ = buffer; | |
297 current_read_buffer_size_ = bytes_to_read; | |
298 | |
299 GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_ReadResponseBody( | |
300 API_ID_PPB_URL_LOADER, host_resource(), bytes_to_read)); | |
301 return PP_OK_COMPLETIONPENDING; | |
302 } | |
303 | |
304 int32_t URLLoader::FinishStreamingToFile( | |
305 scoped_refptr<TrackedCallback> callback) { | |
306 if (TrackedCallback::IsPending(current_callback_)) | |
307 return PP_ERROR_INPROGRESS; | |
308 | |
309 current_callback_ = callback; | |
310 | |
311 GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_FinishStreamingToFile( | |
312 API_ID_PPB_URL_LOADER, host_resource())); | |
313 return PP_OK_COMPLETIONPENDING; | |
314 } | |
315 | |
316 void URLLoader::Close() { | |
317 GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_Close( | |
318 API_ID_PPB_URL_LOADER, host_resource())); | |
319 } | |
320 | |
321 void URLLoader::GrantUniversalAccess() { | |
322 GetDispatcher()->Send( | |
323 new PpapiHostMsg_PPBURLLoader_GrantUniversalAccess( | |
324 API_ID_PPB_URL_LOADER, host_resource())); | |
325 } | |
326 | |
327 void URLLoader::SetStatusCallback( | |
328 PP_URLLoaderTrusted_StatusCallback cb) { | |
329 // Not implemented in the proxied version, this is for implementing the | |
330 // proxy itself in the host. | |
331 } | |
332 | |
333 bool URLLoader::GetResponseInfoData(URLResponseInfoData* data) { | |
334 // Not implemented in the proxied version, this is for implementing the | |
335 // proxy itself in the host. | |
336 return false; | |
337 } | |
338 | |
339 void URLLoader::UpdateProgress( | |
340 const PPBURLLoader_UpdateProgress_Params& params) { | |
341 bytes_sent_ = params.bytes_sent; | |
342 total_bytes_to_be_sent_ = params.total_bytes_to_be_sent; | |
343 bytes_received_ = params.bytes_received; | |
344 total_bytes_to_be_received_ = params.total_bytes_to_be_received; | |
345 } | |
346 | |
347 void URLLoader::ReadResponseBodyAck(int32 result, const char* data) { | |
348 if (!TrackedCallback::IsPending(current_callback_) || !current_read_buffer_) { | |
349 NOTREACHED(); | |
350 return; | |
351 } | |
352 | |
353 if (result >= 0) { | |
354 DCHECK_EQ(0U, buffer_.size()); | |
355 | |
356 int32_t bytes_to_return = std::min(current_read_buffer_size_, result); | |
357 std::copy(data, | |
358 data + bytes_to_return, | |
359 static_cast<char*>(current_read_buffer_)); | |
360 | |
361 if (result > bytes_to_return) { | |
362 // Save what remains to be copied when ReadResponseBody is called again. | |
363 buffer_.insert(buffer_.end(), | |
364 data + bytes_to_return, | |
365 data + result); | |
366 } | |
367 | |
368 result = bytes_to_return; | |
369 } | |
370 | |
371 current_callback_->Run(result); | |
372 } | |
373 | |
374 void URLLoader::CallbackComplete(int32_t result) { | |
375 current_callback_->Run(result); | |
376 } | |
377 | |
378 void URLLoader::PopBuffer(void* output_buffer, int32_t output_size) { | |
379 CHECK(output_size <= static_cast<int32_t>(buffer_.size())); | |
380 std::copy(buffer_.begin(), | |
381 buffer_.begin() + output_size, | |
382 static_cast<char*>(output_buffer)); | |
383 buffer_.erase(buffer_.begin(), | |
384 buffer_.begin() + output_size); | |
385 } | |
386 | |
387 // PPB_URLLoader_Proxy --------------------------------------------------------- | |
388 | |
389 PPB_URLLoader_Proxy::PPB_URLLoader_Proxy(Dispatcher* dispatcher) | |
390 : InterfaceProxy(dispatcher), | |
391 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { | |
392 } | |
393 | |
394 PPB_URLLoader_Proxy::~PPB_URLLoader_Proxy() { | |
395 } | |
396 | |
397 // static | |
398 PP_Resource PPB_URLLoader_Proxy::TrackPluginResource( | |
399 const HostResource& url_loader_resource) { | |
400 return (new URLLoader(url_loader_resource))->GetReference(); | |
401 } | |
402 | |
403 // static | |
404 const InterfaceProxy::Info* PPB_URLLoader_Proxy::GetTrustedInfo() { | |
405 static const Info info = { | |
406 thunk::GetPPB_URLLoaderTrusted_0_3_Thunk(), | |
407 PPB_URLLOADERTRUSTED_INTERFACE_0_3, | |
408 API_ID_NONE, // URL_LOADER is the canonical one. | |
409 false, | |
410 &CreateURLLoaderProxy | |
411 }; | |
412 return &info; | |
413 } | |
414 | |
415 // static | |
416 PP_Resource PPB_URLLoader_Proxy::CreateProxyResource(PP_Instance pp_instance) { | |
417 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(pp_instance); | |
418 if (!dispatcher) | |
419 return 0; | |
420 | |
421 HostResource result; | |
422 dispatcher->Send(new PpapiHostMsg_PPBURLLoader_Create( | |
423 API_ID_PPB_URL_LOADER, pp_instance, &result)); | |
424 if (result.is_null()) | |
425 return 0; | |
426 return PPB_URLLoader_Proxy::TrackPluginResource(result); | |
427 } | |
428 | |
429 bool PPB_URLLoader_Proxy::OnMessageReceived(const IPC::Message& msg) { | |
430 bool handled = true; | |
431 IPC_BEGIN_MESSAGE_MAP(PPB_URLLoader_Proxy, msg) | |
432 #if !defined(OS_NACL) | |
433 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_Create, | |
434 OnMsgCreate) | |
435 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_Open, | |
436 OnMsgOpen) | |
437 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_FollowRedirect, | |
438 OnMsgFollowRedirect) | |
439 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_GetResponseInfo, | |
440 OnMsgGetResponseInfo) | |
441 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_ReadResponseBody, | |
442 OnMsgReadResponseBody) | |
443 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_FinishStreamingToFile, | |
444 OnMsgFinishStreamingToFile) | |
445 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_Close, | |
446 OnMsgClose) | |
447 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_GrantUniversalAccess, | |
448 OnMsgGrantUniversalAccess) | |
449 #endif // !defined(OS_NACL) | |
450 | |
451 IPC_MESSAGE_HANDLER(PpapiMsg_PPBURLLoader_UpdateProgress, | |
452 OnMsgUpdateProgress) | |
453 IPC_MESSAGE_HANDLER(PpapiMsg_PPBURLLoader_ReadResponseBody_Ack, | |
454 OnMsgReadResponseBodyAck) | |
455 IPC_MESSAGE_HANDLER(PpapiMsg_PPBURLLoader_CallbackComplete, | |
456 OnMsgCallbackComplete) | |
457 IPC_MESSAGE_UNHANDLED(handled = false) | |
458 IPC_END_MESSAGE_MAP() | |
459 // TODO(brettw) handle bad messages! | |
460 return handled; | |
461 } | |
462 | |
463 #if !defined(OS_NACL) | |
464 void PPB_URLLoader_Proxy::PrepareURLLoaderForSendingToPlugin( | |
465 PP_Resource resource) { | |
466 // So the plugin can query load status, we need to register our status | |
467 // callback before sending any URLLoader to the plugin. | |
468 EnterResourceNoLock<PPB_URLLoader_API> enter(resource, false); | |
469 if (enter.succeeded()) | |
470 enter.object()->SetStatusCallback(&UpdateResourceLoadStatus); | |
471 else | |
472 NOTREACHED(); // Only called internally, resource should be valid. | |
473 } | |
474 | |
475 void PPB_URLLoader_Proxy::OnMsgCreate(PP_Instance instance, | |
476 HostResource* result) { | |
477 thunk::EnterResourceCreation enter(instance); | |
478 if (enter.succeeded()) { | |
479 result->SetHostResource(instance, | |
480 enter.functions()->CreateURLLoader(instance)); | |
481 PrepareURLLoaderForSendingToPlugin(result->host_resource()); | |
482 } | |
483 } | |
484 | |
485 void PPB_URLLoader_Proxy::OnMsgOpen(const HostResource& loader, | |
486 const URLRequestInfoData& data) { | |
487 int peer_pid = dispatcher()->channel()->peer_pid(); | |
488 | |
489 EnterHostFromHostResourceForceCallback<PPB_URLLoader_API> enter( | |
490 loader, callback_factory_, &PPB_URLLoader_Proxy::OnCallback, loader); | |
491 enter.SetResult(enter.object()->Open(data, peer_pid, enter.callback())); | |
492 // TODO(brettw) bug 73236 register for the status callbacks. | |
493 } | |
494 | |
495 void PPB_URLLoader_Proxy::OnMsgFollowRedirect( | |
496 const HostResource& loader) { | |
497 EnterHostFromHostResourceForceCallback<PPB_URLLoader_API> enter( | |
498 loader, callback_factory_, &PPB_URLLoader_Proxy::OnCallback, loader); | |
499 if (enter.succeeded()) | |
500 enter.SetResult(enter.object()->FollowRedirect(enter.callback())); | |
501 } | |
502 | |
503 void PPB_URLLoader_Proxy::OnMsgGetResponseInfo(const HostResource& loader, | |
504 bool* success, | |
505 URLResponseInfoData* result) { | |
506 EnterHostFromHostResource<PPB_URLLoader_API> enter(loader); | |
507 if (enter.succeeded()) | |
508 *success = enter.object()->GetResponseInfoData(result); | |
509 else | |
510 *success = false; | |
511 } | |
512 | |
513 void PPB_URLLoader_Proxy::OnMsgReadResponseBody( | |
514 const HostResource& loader, | |
515 int32_t bytes_to_read) { | |
516 // The plugin could be sending us malicious messages, don't accept negative | |
517 // sizes. | |
518 if (bytes_to_read < 0) { | |
519 // TODO(brettw) kill plugin. | |
520 bytes_to_read = 0; | |
521 } | |
522 | |
523 // Read more than requested if there are bytes available for synchronous | |
524 // reading. This prevents us from getting too far behind due to IPC message | |
525 // latency. Any extra data will get buffered in the plugin. | |
526 int32_t synchronously_available_bytes = | |
527 static_cast<HostDispatcher*>(dispatcher())->ppb_proxy()-> | |
528 GetURLLoaderBufferedBytes(loader.host_resource()); | |
529 if (bytes_to_read < kMaxReadBufferSize) { | |
530 // Grow the amount to read so we read ahead synchronously, if possible. | |
531 bytes_to_read = | |
532 std::max(bytes_to_read, | |
533 std::min(synchronously_available_bytes, kMaxReadBufferSize)); | |
534 } | |
535 | |
536 // This heap object will get deleted by the callback handler. | |
537 // TODO(brettw) this will be leaked if the plugin closes the resource! | |
538 // (Also including the plugin unloading and having the resource implicitly | |
539 // destroyed. Depending on the cleanup ordering, we may not need the weak | |
540 // pointer here.) | |
541 IPC::Message* message = | |
542 new PpapiMsg_PPBURLLoader_ReadResponseBody_Ack(API_ID_PPB_URL_LOADER); | |
543 IPC::ParamTraits<HostResource>::Write(message, loader); | |
544 | |
545 char* ptr = message->BeginWriteData(bytes_to_read); | |
546 if (!ptr) { | |
547 // TODO(brettw) have a way to check for out-of-memory. | |
548 } | |
549 | |
550 EnterHostFromHostResourceForceCallback<PPB_URLLoader_API> enter( | |
551 loader, callback_factory_, &PPB_URLLoader_Proxy::OnReadCallback, message); | |
552 if (enter.succeeded()) { | |
553 enter.SetResult(enter.object()->ReadResponseBody(ptr, bytes_to_read, | |
554 enter.callback())); | |
555 } | |
556 } | |
557 | |
558 void PPB_URLLoader_Proxy::OnMsgFinishStreamingToFile( | |
559 const HostResource& loader) { | |
560 EnterHostFromHostResourceForceCallback<PPB_URLLoader_API> enter( | |
561 loader, callback_factory_, &PPB_URLLoader_Proxy::OnCallback, loader); | |
562 if (enter.succeeded()) | |
563 enter.SetResult(enter.object()->FinishStreamingToFile(enter.callback()));; | |
564 } | |
565 | |
566 void PPB_URLLoader_Proxy::OnMsgClose(const HostResource& loader) { | |
567 EnterHostFromHostResource<PPB_URLLoader_API> enter(loader); | |
568 if (enter.succeeded()) | |
569 enter.object()->Close(); | |
570 } | |
571 | |
572 void PPB_URLLoader_Proxy::OnMsgGrantUniversalAccess( | |
573 const HostResource& loader) { | |
574 EnterHostFromHostResource<PPB_URLLoader_API> enter(loader); | |
575 if (enter.succeeded()) | |
576 enter.object()->GrantUniversalAccess(); | |
577 } | |
578 #endif // !defined(OS_NACL) | |
579 | |
580 // Called in the Plugin. | |
581 void PPB_URLLoader_Proxy::OnMsgUpdateProgress( | |
582 const PPBURLLoader_UpdateProgress_Params& params) { | |
583 EnterPluginFromHostResource<PPB_URLLoader_API> enter(params.resource); | |
584 if (enter.succeeded()) | |
585 static_cast<URLLoader*>(enter.object())->UpdateProgress(params); | |
586 } | |
587 | |
588 // Called in the Plugin. | |
589 void PPB_URLLoader_Proxy::OnMsgReadResponseBodyAck( | |
590 const IPC::Message& message) { | |
591 PickleIterator iter(message); | |
592 | |
593 HostResource host_resource; | |
594 if (!IPC::ParamTraits<HostResource>::Read(&message, &iter, &host_resource)) { | |
595 NOTREACHED() << "Expecting HostResource"; | |
596 return; | |
597 } | |
598 | |
599 const char* data; | |
600 int data_len; | |
601 if (!iter.ReadData(&data, &data_len)) { | |
602 NOTREACHED() << "Expecting data"; | |
603 return; | |
604 } | |
605 | |
606 int result; | |
607 if (!iter.ReadInt(&result)) { | |
608 NOTREACHED() << "Expecting result"; | |
609 return; | |
610 } | |
611 | |
612 DCHECK(result < 0 || result == data_len); | |
613 | |
614 EnterPluginFromHostResource<PPB_URLLoader_API> enter(host_resource); | |
615 if (enter.succeeded()) | |
616 static_cast<URLLoader*>(enter.object())->ReadResponseBodyAck(result, data); | |
617 } | |
618 | |
619 // Called in the plugin. | |
620 void PPB_URLLoader_Proxy::OnMsgCallbackComplete( | |
621 const HostResource& host_resource, | |
622 int32_t result) { | |
623 EnterPluginFromHostResource<PPB_URLLoader_API> enter(host_resource); | |
624 if (enter.succeeded()) | |
625 static_cast<URLLoader*>(enter.object())->CallbackComplete(result); | |
626 } | |
627 | |
628 #if !defined(OS_NACL) | |
629 void PPB_URLLoader_Proxy::OnReadCallback(int32_t result, | |
630 IPC::Message* message) { | |
631 int32_t bytes_read = 0; | |
632 if (result > 0) | |
633 bytes_read = result; // Positive results indicate bytes read. | |
634 | |
635 message->TrimWriteData(bytes_read); | |
636 message->WriteInt(result); | |
637 | |
638 dispatcher()->Send(message); | |
639 } | |
640 | |
641 void PPB_URLLoader_Proxy::OnCallback(int32_t result, | |
642 const HostResource& resource) { | |
643 dispatcher()->Send(new PpapiMsg_PPBURLLoader_CallbackComplete( | |
644 API_ID_PPB_URL_LOADER, resource, result)); | |
645 } | |
646 #endif // !defined(OS_NACL) | |
647 | |
648 } // namespace proxy | |
649 } // namespace ppapi | |
OLD | NEW |