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.
8 #include "ppapi/c/pp_errors.h"
9 #include "ppapi/c/ppb_instance.h"
10 #include "ppapi/cpp/module.h"
11 #include "ppapi/cpp/var.h"
13 #include "url_loader_handler.h"
20 // Allow 'this' in initializer list
21 #pragma warning(disable : 4355)
24 URLLoaderHandler
* URLLoaderHandler::Create(pp::Instance
* instance
,
25 const std::string
& url
) {
26 return new URLLoaderHandler(instance
, url
);
29 URLLoaderHandler::URLLoaderHandler(pp::Instance
* instance
,
30 const std::string
& url
)
31 : instance_(instance
),
33 url_request_(instance
),
34 url_loader_(instance
),
35 buffer_(new char[READ_BUFFER_SIZE
]),
37 url_request_
.SetURL(url
);
38 url_request_
.SetMethod("GET");
39 url_request_
.SetRecordDownloadProgress(true);
42 URLLoaderHandler::~URLLoaderHandler() {
47 void URLLoaderHandler::Start() {
48 pp::CompletionCallback cc
=
49 cc_factory_
.NewCallback(&URLLoaderHandler::OnOpen
);
50 url_loader_
.Open(url_request_
, cc
);
53 void URLLoaderHandler::OnOpen(int32_t result
) {
54 if (result
!= PP_OK
) {
55 ReportResultAndDie(url_
, "pp::URLLoader::Open() failed", false);
58 // Here you would process the headers. A real program would want to at least
59 // check the HTTP code and potentially cancel the request.
60 // pp::URLResponseInfo response = loader_.GetResponseInfo();
62 // Try to figure out how many bytes of data are going to be downloaded in
63 // order to allocate memory for the response body in advance (this will
64 // reduce heap traffic and also the amount of memory allocated).
65 // It is not a problem if this fails, it just means that the
66 // url_response_body_.insert() call in URLLoaderHandler::AppendDataBytes()
67 // will allocate the memory later on.
68 int64_t bytes_received
= 0;
69 int64_t total_bytes_to_be_received
= 0;
70 if (url_loader_
.GetDownloadProgress(&bytes_received
,
71 &total_bytes_to_be_received
)) {
72 if (total_bytes_to_be_received
> 0) {
73 url_response_body_
.reserve(total_bytes_to_be_received
);
76 // We will not use the download progress anymore, so just disable it.
77 url_request_
.SetRecordDownloadProgress(false);
83 void URLLoaderHandler::AppendDataBytes(const char* buffer
, int32_t num_bytes
) {
86 // Make sure we don't get a buffer overrun.
87 num_bytes
= std::min(READ_BUFFER_SIZE
, num_bytes
);
88 // Note that we do *not* try to minimally increase the amount of allocated
89 // memory here by calling url_response_body_.reserve(). Doing so causes a
90 // lot of string reallocations that kills performance for large files.
91 url_response_body_
.insert(
92 url_response_body_
.end(), buffer
, buffer
+ num_bytes
);
95 void URLLoaderHandler::OnRead(int32_t result
) {
96 if (result
== PP_OK
) {
97 // Streaming the file is complete, delete the read buffer since it is
101 ReportResultAndDie(url_
, url_response_body_
, true);
102 } else if (result
> 0) {
103 // The URLLoader just filled "result" number of bytes into our buffer.
104 // Save them and perform another read.
105 AppendDataBytes(buffer_
, result
);
108 // A read error occurred.
110 url_
, "pp::URLLoader::ReadResponseBody() result<0", false);
114 void URLLoaderHandler::ReadBody() {
115 // Note that you specifically want an "optional" callback here. This will
116 // allow ReadBody() to return synchronously, ignoring your completion
117 // callback, if data is available. For fast connections and large files,
118 // reading as fast as we can will make a large performance difference
119 // However, in the case of a synchronous return, we need to be sure to run
120 // the callback we created since the loader won't do anything with it.
121 pp::CompletionCallback cc
=
122 cc_factory_
.NewOptionalCallback(&URLLoaderHandler::OnRead
);
123 int32_t result
= PP_OK
;
125 result
= url_loader_
.ReadResponseBody(buffer_
, READ_BUFFER_SIZE
, cc
);
126 // Handle streaming data directly. Note that we *don't* want to call
127 // OnRead here, since in the case of result > 0 it will schedule
128 // another call to this function. If the network is very fast, we could
129 // end up with a deeply recursive stack.
131 AppendDataBytes(buffer_
, result
);
133 } while (result
> 0);
135 if (result
!= PP_OK_COMPLETIONPENDING
) {
136 // Either we reached the end of the stream (result == PP_OK) or there was
137 // an error. We want OnRead to get called no matter what to handle
138 // that case, whether the error is synchronous or asynchronous. If the
139 // result code *is* COMPLETIONPENDING, our callback will be called
145 void URLLoaderHandler::ReportResultAndDie(const std::string
& fname
,
146 const std::string
& text
,
148 ReportResult(fname
, text
, success
);
152 void URLLoaderHandler::ReportResult(const std::string
& fname
,
153 const std::string
& text
,
156 printf("URLLoaderHandler::ReportResult(Ok).\n");
158 printf("URLLoaderHandler::ReportResult(Err). %s\n", text
.c_str());
161 pp::Var
var_result(fname
+ "\n" + text
);
162 instance_
->PostMessage(var_result
);