Convert TestOldCompletionCallback in WebSocketJobTest.
[chromium-blink-merge.git] / ppapi / proxy / ppb_url_loader_proxy.cc
blobbe51288a473498ac12b0bfede9076b0e7e376868
1 // Copyright (c) 2011 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.
5 #include "ppapi/proxy/ppb_url_loader_proxy.h"
7 #include <algorithm>
8 #include <deque>
9 #include <vector>
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_url_response_info_proxy.h"
26 #include "ppapi/shared_impl/scoped_pp_resource.h"
27 #include "ppapi/thunk/enter.h"
28 #include "ppapi/thunk/ppb_url_loader_api.h"
29 #include "ppapi/thunk/resource_creation_api.h"
30 #include "ppapi/thunk/thunk.h"
32 #if defined(OS_LINUX)
33 #include <sys/shm.h>
34 #endif
36 using ppapi::thunk::EnterFunctionNoLock;
37 using ppapi::thunk::EnterResourceNoLock;
38 using ppapi::thunk::PPB_URLLoader_API;
39 using ppapi::thunk::ResourceCreationAPI;
41 namespace ppapi {
42 namespace proxy {
44 namespace {
46 // The maximum size we'll read into the plugin without being explicitly
47 // asked for a larger buffer.
48 const int32_t kMaxReadBufferSize = 16777216; // 16MB
50 // Called in the renderer when the byte counts have changed. We send a message
51 // to the plugin to synchronize its counts so it can respond to status polls
52 // from the plugin.
53 void UpdateResourceLoadStatus(PP_Instance pp_instance,
54 PP_Resource pp_resource,
55 int64 bytes_sent,
56 int64 total_bytes_to_be_sent,
57 int64 bytes_received,
58 int64 total_bytes_to_be_received) {
59 Dispatcher* dispatcher = HostDispatcher::GetForInstance(pp_instance);
60 if (!dispatcher)
61 return;
63 PPBURLLoader_UpdateProgress_Params params;
64 params.instance = pp_instance;
65 params.resource.SetHostResource(pp_instance, pp_resource);
66 params.bytes_sent = bytes_sent;
67 params.total_bytes_to_be_sent = total_bytes_to_be_sent;
68 params.bytes_received = bytes_received;
69 params.total_bytes_to_be_received = total_bytes_to_be_received;
70 dispatcher->Send(new PpapiMsg_PPBURLLoader_UpdateProgress(
71 API_ID_PPB_URL_LOADER, params));
74 InterfaceProxy* CreateURLLoaderProxy(Dispatcher* dispatcher) {
75 return new PPB_URLLoader_Proxy(dispatcher);
78 } // namespace
80 // URLLoader -------------------------------------------------------------------
82 class URLLoader : public Resource, public PPB_URLLoader_API {
83 public:
84 URLLoader(const HostResource& resource);
85 virtual ~URLLoader();
87 // Resource overrides.
88 virtual PPB_URLLoader_API* AsPPB_URLLoader_API() OVERRIDE;
90 // PPB_URLLoader_API implementation.
91 virtual int32_t Open(PP_Resource request_id,
92 PP_CompletionCallback callback) OVERRIDE;
93 virtual int32_t FollowRedirect(PP_CompletionCallback callback) OVERRIDE;
94 virtual PP_Bool GetUploadProgress(int64_t* bytes_sent,
95 int64_t* total_bytes_to_be_sent) OVERRIDE;
96 virtual PP_Bool GetDownloadProgress(
97 int64_t* bytes_received,
98 int64_t* total_bytes_to_be_received) OVERRIDE;
99 virtual PP_Resource GetResponseInfo() OVERRIDE;
100 virtual int32_t ReadResponseBody(void* buffer,
101 int32_t bytes_to_read,
102 PP_CompletionCallback callback) OVERRIDE;
103 virtual int32_t FinishStreamingToFile(
104 PP_CompletionCallback callback) OVERRIDE;
105 virtual void Close() OVERRIDE;
106 virtual void GrantUniversalAccess() OVERRIDE;
107 virtual void SetStatusCallback(
108 PP_URLLoaderTrusted_StatusCallback cb) OVERRIDE;
110 // Called when the browser has new up/download progress to report.
111 void UpdateProgress(const PPBURLLoader_UpdateProgress_Params& params);
113 // Called when the browser responds to our ReadResponseBody request.
114 void ReadResponseBodyAck(int32_t result, const std::string& data);
116 // Called when any callback other than the read callback has been executed.
117 void CallbackComplete(int32_t result);
119 private:
120 // Reads the give bytes out of the buffer_, placing them in the given output
121 // buffer, and removes the bytes from the buffer.
123 // The size must be not more than the current size of the buffer.
124 void PopBuffer(void* output_buffer, int32_t output_size);
126 PluginDispatcher* GetDispatcher() const {
127 return PluginDispatcher::GetForResource(this);
130 // Initialized to -1. Will be set to nonnegative values by the UpdateProgress
131 // message when the values are known.
132 int64_t bytes_sent_;
133 int64_t total_bytes_to_be_sent_;
134 int64_t bytes_received_;
135 int64_t total_bytes_to_be_received_;
137 // Current completion callback for the current phase of loading. We have only
138 // one thing (open, follow redirect, read, etc.) outstanding at once.
139 PP_CompletionCallback current_callback_;
141 // When an asynchronous read is pending, this will contain the buffer to put
142 // the data. The current_callback_ will identify the read callback.
143 void* current_read_buffer_;
144 int32_t current_read_buffer_size_;
146 // A buffer of all the data that's been sent to us from the host that we
147 // have yet to send out to the plugin.
148 std::deque<char> buffer_;
150 // Cached copy of the response info. When nonzero, we're holding a reference
151 // to this resource.
152 PP_Resource response_info_;
154 private:
155 DISALLOW_COPY_AND_ASSIGN(URLLoader);
158 URLLoader::URLLoader(const HostResource& resource)
159 : Resource(resource),
160 bytes_sent_(-1),
161 total_bytes_to_be_sent_(-1),
162 bytes_received_(-1),
163 total_bytes_to_be_received_(-1),
164 current_callback_(PP_MakeCompletionCallback(NULL, NULL)),
165 current_read_buffer_(NULL),
166 current_read_buffer_size_(0),
167 response_info_(0) {
170 URLLoader::~URLLoader() {
171 // Always need to fire completion callbacks to prevent a leak in the plugin.
172 if (current_callback_.func) {
173 // TODO(brettw) the callbacks at this level should be refactored with a
174 // more automatic tracking system like we have in the renderer.
175 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
176 current_callback_.func, current_callback_.user_data,
177 static_cast<int32_t>(PP_ERROR_ABORTED)));
180 if (response_info_)
181 PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(response_info_);
184 PPB_URLLoader_API* URLLoader::AsPPB_URLLoader_API() {
185 return this;
188 int32_t URLLoader::Open(PP_Resource request_id,
189 PP_CompletionCallback callback) {
190 EnterResourceNoLock<thunk::PPB_URLRequestInfo_API> enter(request_id, true);
191 if (enter.failed())
192 return PP_ERROR_BADRESOURCE;
194 if (current_callback_.func)
195 return PP_ERROR_INPROGRESS;
197 if (!callback.func)
198 return PP_ERROR_BLOCKS_MAIN_THREAD;
199 current_callback_ = callback;
201 GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_Open(
202 API_ID_PPB_URL_LOADER, host_resource(), enter.object()->GetData()));
203 return PP_OK_COMPLETIONPENDING;
206 int32_t URLLoader::FollowRedirect(PP_CompletionCallback callback) {
207 if (current_callback_.func)
208 return PP_ERROR_INPROGRESS;
210 if (!callback.func)
211 return PP_ERROR_BLOCKS_MAIN_THREAD;
212 current_callback_ = callback;
214 GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_FollowRedirect(
215 API_ID_PPB_URL_LOADER, host_resource()));
216 return PP_OK_COMPLETIONPENDING;
219 PP_Bool URLLoader::GetUploadProgress(int64_t* bytes_sent,
220 int64_t* total_bytes_to_be_sent) {
221 if (bytes_sent_ == -1) {
222 *bytes_sent = 0;
223 *total_bytes_to_be_sent = 0;
224 return PP_FALSE;
226 *bytes_sent = bytes_sent_;
227 *total_bytes_to_be_sent = total_bytes_to_be_sent_;
228 return PP_TRUE;
231 PP_Bool URLLoader::GetDownloadProgress(
232 int64_t* bytes_received,
233 int64_t* total_bytes_to_be_received) {
234 if (bytes_received_ == -1) {
235 *bytes_received = 0;
236 *total_bytes_to_be_received = 0;
237 return PP_FALSE;
239 *bytes_received = bytes_received_;
240 *total_bytes_to_be_received = total_bytes_to_be_received_;
241 return PP_TRUE;
244 PP_Resource URLLoader::GetResponseInfo() {
245 if (!response_info_) {
246 HostResource response_id;
247 GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_GetResponseInfo(
248 API_ID_PPB_URL_LOADER, host_resource(), &response_id));
249 if (response_id.is_null())
250 return 0;
252 response_info_ = PPB_URLResponseInfo_Proxy::CreateResponseForResource(
253 response_id);
256 // The caller expects to get a ref, and we want to keep holding ours.
257 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(response_info_);
258 return response_info_;
261 int32_t URLLoader::ReadResponseBody(void* buffer,
262 int32_t bytes_to_read,
263 PP_CompletionCallback callback) {
264 if (!buffer || bytes_to_read <= 0)
265 return PP_ERROR_BADARGUMENT; // Must specify an output buffer.
266 if (current_callback_.func)
267 return PP_ERROR_INPROGRESS; // Can only have one request pending.
269 // Currently we don't support sync calls to read. We'll need to revisit
270 // how this works when we allow blocking calls (from background threads).
271 if (!callback.func)
272 return PP_ERROR_BADARGUMENT;
274 if (static_cast<size_t>(bytes_to_read) <= buffer_.size()) {
275 // Special case: we've buffered enough data to be able to synchronously
276 // return data to the caller. Do so without making IPCs.
277 PopBuffer(buffer, bytes_to_read);
278 return bytes_to_read;
281 current_callback_ = callback;
282 current_read_buffer_ = buffer;
283 current_read_buffer_size_ = bytes_to_read;
285 GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_ReadResponseBody(
286 API_ID_PPB_URL_LOADER, host_resource(), bytes_to_read));
287 return PP_OK_COMPLETIONPENDING;
290 int32_t URLLoader::FinishStreamingToFile(PP_CompletionCallback callback) {
291 if (current_callback_.func)
292 return PP_ERROR_INPROGRESS;
294 if (!callback.func)
295 return PP_ERROR_BLOCKS_MAIN_THREAD;
296 current_callback_ = callback;
298 GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_FinishStreamingToFile(
299 API_ID_PPB_URL_LOADER, host_resource()));
300 return PP_OK_COMPLETIONPENDING;
303 void URLLoader::Close() {
304 GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_Close(
305 API_ID_PPB_URL_LOADER, host_resource()));
308 void URLLoader::GrantUniversalAccess() {
309 GetDispatcher()->Send(
310 new PpapiHostMsg_PPBURLLoader_GrantUniversalAccess(
311 API_ID_PPB_URL_LOADER, host_resource()));
314 void URLLoader::SetStatusCallback(
315 PP_URLLoaderTrusted_StatusCallback cb) {
316 // Not implemented in the proxied version, this is for implementing the
317 // proxy itself in the host.
320 void URLLoader::UpdateProgress(
321 const PPBURLLoader_UpdateProgress_Params& params) {
322 bytes_sent_ = params.bytes_sent;
323 total_bytes_to_be_sent_ = params.total_bytes_to_be_sent;
324 bytes_received_ = params.bytes_received;
325 total_bytes_to_be_received_ = params.total_bytes_to_be_received;
328 void URLLoader::ReadResponseBodyAck(int32 result, const std::string& data) {
329 if (!current_callback_.func || !current_read_buffer_) {
330 NOTREACHED();
331 return;
334 // Append the data we requested to the internal buffer.
335 // TODO(brettw) avoid double-copying data that's coming from IPC and going
336 // into the plugin buffer (we can skip the internal buffer in this case).
337 buffer_.insert(buffer_.end(), data.begin(), data.end());
339 if (result >= 0) {
340 // Fill the user buffer. We may get fewer bytes than requested in the
341 // case of stream end.
342 int32_t bytes_to_return = std::min(current_read_buffer_size_,
343 static_cast<int32_t>(buffer_.size()));
344 PopBuffer(current_read_buffer_, bytes_to_return);
345 result = bytes_to_return;
348 // The plugin should be able to make a new request from their callback, so
349 // we have to clear our copy first.
350 PP_RunAndClearCompletionCallback(&current_callback_, result);
353 void URLLoader::CallbackComplete(int32_t result) {
354 PP_RunAndClearCompletionCallback(&current_callback_, result);
357 void URLLoader::PopBuffer(void* output_buffer, int32_t output_size) {
358 CHECK(output_size <= static_cast<int32_t>(buffer_.size()));
359 std::copy(buffer_.begin(),
360 buffer_.begin() + output_size,
361 static_cast<char*>(output_buffer));
362 buffer_.erase(buffer_.begin(),
363 buffer_.begin() + output_size);
366 // PPB_URLLoader_Proxy ---------------------------------------------------------
368 struct PPB_URLLoader_Proxy::ReadCallbackInfo {
369 HostResource resource;
370 std::string read_buffer;
373 PPB_URLLoader_Proxy::PPB_URLLoader_Proxy(Dispatcher* dispatcher)
374 : InterfaceProxy(dispatcher),
375 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
376 host_urlloader_trusted_interface_(NULL) {
379 PPB_URLLoader_Proxy::~PPB_URLLoader_Proxy() {
382 // static
383 PP_Resource PPB_URLLoader_Proxy::TrackPluginResource(
384 const HostResource& url_loader_resource) {
385 return (new URLLoader(url_loader_resource))->GetReference();
388 // static
389 const InterfaceProxy::Info* PPB_URLLoader_Proxy::GetTrustedInfo() {
390 static const Info info = {
391 thunk::GetPPB_URLLoaderTrusted_Thunk(),
392 PPB_URLLOADERTRUSTED_INTERFACE,
393 API_ID_NONE, // URL_LOADER is the canonical one.
394 false,
395 &CreateURLLoaderProxy
397 return &info;
400 // static
401 PP_Resource PPB_URLLoader_Proxy::CreateProxyResource(PP_Instance pp_instance) {
402 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(pp_instance);
403 if (!dispatcher)
404 return 0;
406 HostResource result;
407 dispatcher->Send(new PpapiHostMsg_PPBURLLoader_Create(
408 API_ID_PPB_URL_LOADER, pp_instance, &result));
409 if (result.is_null())
410 return 0;
411 return PPB_URLLoader_Proxy::TrackPluginResource(result);
414 bool PPB_URLLoader_Proxy::OnMessageReceived(const IPC::Message& msg) {
415 bool handled = true;
416 IPC_BEGIN_MESSAGE_MAP(PPB_URLLoader_Proxy, msg)
417 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_Create,
418 OnMsgCreate)
419 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_Open,
420 OnMsgOpen)
421 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_FollowRedirect,
422 OnMsgFollowRedirect)
423 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_GetResponseInfo,
424 OnMsgGetResponseInfo)
425 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_ReadResponseBody,
426 OnMsgReadResponseBody)
427 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_FinishStreamingToFile,
428 OnMsgFinishStreamingToFile)
429 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_Close,
430 OnMsgClose)
431 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_GrantUniversalAccess,
432 OnMsgGrantUniversalAccess)
434 IPC_MESSAGE_HANDLER(PpapiMsg_PPBURLLoader_UpdateProgress,
435 OnMsgUpdateProgress)
436 IPC_MESSAGE_HANDLER(PpapiMsg_PPBURLLoader_ReadResponseBody_Ack,
437 OnMsgReadResponseBodyAck)
438 IPC_MESSAGE_HANDLER(PpapiMsg_PPBURLLoader_CallbackComplete,
439 OnMsgCallbackComplete)
440 IPC_MESSAGE_UNHANDLED(handled = false)
441 IPC_END_MESSAGE_MAP()
442 // TODO(brettw) handle bad messages!
443 return handled;
446 void PPB_URLLoader_Proxy::PrepareURLLoaderForSendingToPlugin(
447 PP_Resource resource) {
448 // So the plugin can query load status, we need to register our status
449 // callback before sending any URLLoader to the plugin.
450 EnterResourceNoLock<PPB_URLLoader_API> enter(resource, false);
451 if (enter.succeeded())
452 enter.object()->SetStatusCallback(&UpdateResourceLoadStatus);
453 else
454 NOTREACHED(); // Only called internally, resource should be valid.
457 void PPB_URLLoader_Proxy::OnMsgCreate(PP_Instance instance,
458 HostResource* result) {
459 thunk::EnterResourceCreation enter(instance);
460 if (enter.succeeded()) {
461 result->SetHostResource(instance,
462 enter.functions()->CreateURLLoader(instance));
463 PrepareURLLoaderForSendingToPlugin(result->host_resource());
467 void PPB_URLLoader_Proxy::OnMsgOpen(const HostResource& loader,
468 const PPB_URLRequestInfo_Data& data) {
469 EnterHostFromHostResourceForceCallback<PPB_URLLoader_API> enter(
470 loader, callback_factory_, &PPB_URLLoader_Proxy::OnCallback, loader);
471 thunk::EnterResourceCreation enter_creation(loader.instance());
472 if (enter.failed() || enter_creation.failed())
473 return;
475 ScopedPPResource request_resource(
476 ScopedPPResource::PassRef(),
477 enter_creation.functions()->CreateURLRequestInfo(loader.instance(),
478 data));
479 enter.SetResult(enter.object()->Open(request_resource, enter.callback()));
480 // TODO(brettw) bug 73236 register for the status callbacks.
483 void PPB_URLLoader_Proxy::OnMsgFollowRedirect(
484 const HostResource& loader) {
485 EnterHostFromHostResourceForceCallback<PPB_URLLoader_API> enter(
486 loader, callback_factory_, &PPB_URLLoader_Proxy::OnCallback, loader);
487 if (enter.succeeded())
488 enter.SetResult(enter.object()->FollowRedirect(enter.callback()));
491 void PPB_URLLoader_Proxy::OnMsgGetResponseInfo(const HostResource& loader,
492 HostResource* result) {
493 EnterHostFromHostResource<PPB_URLLoader_API> enter(loader);
494 if (enter.succeeded()) {
495 result->SetHostResource(loader.instance(),
496 enter.object()->GetResponseInfo());
500 void PPB_URLLoader_Proxy::OnMsgReadResponseBody(
501 const HostResource& loader,
502 int32_t bytes_to_read) {
503 // The plugin could be sending us malicious messages, don't accept negative
504 // sizes.
505 if (bytes_to_read < 0) {
506 // TODO(brettw) kill plugin.
507 bytes_to_read = 0;
510 // Read more than requested if there are bytes available for synchronous
511 // reading. This prevents us from getting too far behind due to IPC message
512 // latency. Any extra data will get buffered in the plugin.
513 int32_t synchronously_available_bytes =
514 static_cast<HostDispatcher*>(dispatcher())->ppb_proxy()->
515 GetURLLoaderBufferedBytes(loader.host_resource());
516 if (bytes_to_read < kMaxReadBufferSize) {
517 // Grow the amount to read so we read ahead synchronously, if possible.
518 bytes_to_read =
519 std::max(bytes_to_read,
520 std::min(synchronously_available_bytes, kMaxReadBufferSize));
523 // This heap object will get deleted by the callback handler.
524 // TODO(brettw) this will be leaked if the plugin closes the resource!
525 // (Also including the plugin unloading and having the resource implicitly
526 // destroyed. Depending on the cleanup ordering, we may not need the weak
527 // pointer here.)
528 ReadCallbackInfo* info = new ReadCallbackInfo;
529 info->resource = loader;
530 // TODO(brettw) have a way to check for out-of-memory.
531 info->read_buffer.resize(bytes_to_read);
533 EnterHostFromHostResourceForceCallback<PPB_URLLoader_API> enter(
534 loader, callback_factory_, &PPB_URLLoader_Proxy::OnReadCallback, info);
535 if (enter.succeeded()) {
536 enter.SetResult(enter.object()->ReadResponseBody(
537 const_cast<char*>(info->read_buffer.c_str()),
538 bytes_to_read, enter.callback()));
542 void PPB_URLLoader_Proxy::OnMsgFinishStreamingToFile(
543 const HostResource& loader) {
544 EnterHostFromHostResourceForceCallback<PPB_URLLoader_API> enter(
545 loader, callback_factory_, &PPB_URLLoader_Proxy::OnCallback, loader);
546 if (enter.succeeded())
547 enter.SetResult(enter.object()->FinishStreamingToFile(enter.callback()));;
550 void PPB_URLLoader_Proxy::OnMsgClose(const HostResource& loader) {
551 EnterHostFromHostResource<PPB_URLLoader_API> enter(loader);
552 if (enter.succeeded())
553 enter.object()->Close();
556 void PPB_URLLoader_Proxy::OnMsgGrantUniversalAccess(
557 const HostResource& loader) {
558 EnterHostFromHostResource<PPB_URLLoader_API> enter(loader);
559 if (enter.succeeded())
560 enter.object()->GrantUniversalAccess();
563 // Called in the Plugin.
564 void PPB_URLLoader_Proxy::OnMsgUpdateProgress(
565 const PPBURLLoader_UpdateProgress_Params& params) {
566 EnterPluginFromHostResource<PPB_URLLoader_API> enter(params.resource);
567 if (enter.succeeded())
568 static_cast<URLLoader*>(enter.object())->UpdateProgress(params);
571 // Called in the Plugin.
572 void PPB_URLLoader_Proxy::OnMsgReadResponseBodyAck(
573 const HostResource& host_resource,
574 int32 result,
575 const std::string& data) {
576 EnterPluginFromHostResource<PPB_URLLoader_API> enter(host_resource);
577 if (enter.succeeded())
578 static_cast<URLLoader*>(enter.object())->ReadResponseBodyAck(result, data);
581 // Called in the plugin.
582 void PPB_URLLoader_Proxy::OnMsgCallbackComplete(
583 const HostResource& host_resource,
584 int32_t result) {
585 EnterPluginFromHostResource<PPB_URLLoader_API> enter(host_resource);
586 if (enter.succeeded())
587 static_cast<URLLoader*>(enter.object())->CallbackComplete(result);
590 void PPB_URLLoader_Proxy::OnReadCallback(int32_t result,
591 ReadCallbackInfo* info) {
592 int32_t bytes_read = 0;
593 if (result > 0)
594 bytes_read = result; // Positive results indicate bytes read.
595 info->read_buffer.resize(bytes_read);
597 dispatcher()->Send(new PpapiMsg_PPBURLLoader_ReadResponseBody_Ack(
598 API_ID_PPB_URL_LOADER, info->resource, result, info->read_buffer));
600 delete info;
603 void PPB_URLLoader_Proxy::OnCallback(int32_t result,
604 const HostResource& resource) {
605 dispatcher()->Send(new PpapiMsg_PPBURLLoader_CallbackComplete(
606 API_ID_PPB_URL_LOADER, resource, result));
609 } // namespace proxy
610 } // namespace ppapi