Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / native_client_sdk / src / examples / api / url_loader / url_loader_handler.cc
blob66363620ca925bf4b2ffe9887b1f3a47298c9e67
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.
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <algorithm>
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"
15 #ifdef WIN32
16 #undef min
17 #undef max
18 #undef PostMessage
20 // Allow 'this' in initializer list
21 #pragma warning(disable : 4355)
22 #endif
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),
32 url_(url),
33 url_request_(instance),
34 url_loader_(instance),
35 buffer_(new char[READ_BUFFER_SIZE]),
36 cc_factory_(this) {
37 url_request_.SetURL(url);
38 url_request_.SetMethod("GET");
39 url_request_.SetRecordDownloadProgress(true);
42 URLLoaderHandler::~URLLoaderHandler() {
43 delete[] buffer_;
44 buffer_ = NULL;
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);
56 return;
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);
79 // Start streaming.
80 ReadBody();
83 void URLLoaderHandler::AppendDataBytes(const char* buffer, int32_t num_bytes) {
84 if (num_bytes <= 0)
85 return;
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
98 // no longer needed.
99 delete[] buffer_;
100 buffer_ = NULL;
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);
106 ReadBody();
107 } else {
108 // A read error occurred.
109 ReportResultAndDie(
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;
124 do {
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.
130 if (result > 0) {
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
140 // asynchronously.
141 cc.Run(result);
145 void URLLoaderHandler::ReportResultAndDie(const std::string& fname,
146 const std::string& text,
147 bool success) {
148 ReportResult(fname, text, success);
149 delete this;
152 void URLLoaderHandler::ReportResult(const std::string& fname,
153 const std::string& text,
154 bool success) {
155 if (success)
156 printf("URLLoaderHandler::ReportResult(Ok).\n");
157 else
158 printf("URLLoaderHandler::ReportResult(Err). %s\n", text.c_str());
159 fflush(stdout);
160 if (instance_) {
161 pp::Var var_result(fname + "\n" + text);
162 instance_->PostMessage(var_result);