| OLD | NEW |
| 1 // Copyright (c) 2011 The Native Client Authors. All rights reserved. | 1 // Copyright (c) 2011 The Native Client Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "examples/geturl/geturl_handler.h" | 5 #include "examples/geturl/geturl_handler.h" |
| 6 | 6 |
| 7 #include <stdio.h> | 7 #include <stdio.h> |
| 8 #include <stdlib.h> | 8 #include <stdlib.h> |
| 9 #include "ppapi/c/pp_errors.h" | 9 #include "ppapi/c/pp_errors.h" |
| 10 #include "ppapi/c/ppb_instance.h" | 10 #include "ppapi/c/ppb_instance.h" |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 const std::string& url) { | 21 const std::string& url) { |
| 22 return new GetURLHandler(instance, url); | 22 return new GetURLHandler(instance, url); |
| 23 } | 23 } |
| 24 | 24 |
| 25 GetURLHandler::GetURLHandler(pp::Instance* instance, | 25 GetURLHandler::GetURLHandler(pp::Instance* instance, |
| 26 const std::string& url) | 26 const std::string& url) |
| 27 : instance_(instance), | 27 : instance_(instance), |
| 28 url_(url), | 28 url_(url), |
| 29 url_request_(instance), | 29 url_request_(instance), |
| 30 url_loader_(instance), | 30 url_loader_(instance), |
| 31 buffer_(new char[READ_BUFFER_SIZE]), |
| 31 cc_factory_(this) { | 32 cc_factory_(this) { |
| 32 url_request_.SetURL(url); | 33 url_request_.SetURL(url); |
| 33 url_request_.SetMethod("GET"); | 34 url_request_.SetMethod("GET"); |
| 35 url_request_.SetRecordDownloadProgress(true); |
| 34 } | 36 } |
| 35 | 37 |
| 36 GetURLHandler::~GetURLHandler() { | 38 GetURLHandler::~GetURLHandler() { |
| 39 delete [] buffer_; |
| 40 buffer_ = NULL; |
| 37 } | 41 } |
| 38 | 42 |
| 39 void GetURLHandler::Start() { | 43 void GetURLHandler::Start() { |
| 40 pp::CompletionCallback cc = | 44 pp::CompletionCallback cc = |
| 41 cc_factory_.NewRequiredCallback(&GetURLHandler::OnOpen); | 45 cc_factory_.NewRequiredCallback(&GetURLHandler::OnOpen); |
| 42 url_loader_.Open(url_request_, cc); | 46 url_loader_.Open(url_request_, cc); |
| 43 } | 47 } |
| 44 | 48 |
| 45 void GetURLHandler::OnOpen(int32_t result) { | 49 void GetURLHandler::OnOpen(int32_t result) { |
| 46 if (result != PP_OK) { | 50 if (result != PP_OK) { |
| 47 ReportResultAndDie(url_, "pp::URLLoader::Open() failed", false); | 51 ReportResultAndDie(url_, "pp::URLLoader::Open() failed", false); |
| 48 return; | 52 return; |
| 49 } | 53 } |
| 50 // Here you would process the headers. A real program would want to at least | 54 // Here you would process the headers. A real program would want to at least |
| 51 // check the HTTP code and potentially cancel the request. | 55 // check the HTTP code and potentially cancel the request. |
| 52 // pp::URLResponseInfo response = loader_.GetResponseInfo(); | 56 // pp::URLResponseInfo response = loader_.GetResponseInfo(); |
| 53 | 57 |
| 58 // Try to figure out how many bytes of data are going to be downloaded in |
| 59 // order to allocate memory for the response body in advance (this will |
| 60 // reduce heap traffic and also the amount of memory allocated). |
| 61 // It is not a problem if this fails, it just means that the |
| 62 // url_response_body_.insert() call in GetURLHandler::AppendDataBytes() |
| 63 // will allocate the memory later on. |
| 64 int64_t bytes_received = 0; |
| 65 int64_t total_bytes_to_be_received = 0; |
| 66 if (url_loader_.GetDownloadProgress(&bytes_received, |
| 67 &total_bytes_to_be_received)) { |
| 68 if (total_bytes_to_be_received > 0) { |
| 69 url_response_body_.reserve(total_bytes_to_be_received); |
| 70 } |
| 71 } |
| 72 // We will not use the download progress anymore, so just disable it. |
| 73 url_request_.SetRecordDownloadProgress(false); |
| 74 |
| 54 // Start streaming. | 75 // Start streaming. |
| 55 ReadBody(); | 76 ReadBody(); |
| 56 } | 77 } |
| 57 | 78 |
| 58 void GetURLHandler::AppendDataBytes(const char* buffer, int32_t num_bytes) { | 79 void GetURLHandler::AppendDataBytes(const char* buffer, int32_t num_bytes) { |
| 59 if (num_bytes <= 0) | 80 if (num_bytes <= 0) |
| 60 return; | 81 return; |
| 61 // Make sure we don't get a buffer overrun. | 82 // Make sure we don't get a buffer overrun. |
| 62 num_bytes = std::min(READ_BUFFER_SIZE, num_bytes); | 83 num_bytes = std::min(READ_BUFFER_SIZE, num_bytes); |
| 63 url_response_body_.reserve(url_response_body_.size() + num_bytes); | 84 // Note that we do *not* try to minimally increase the amount of allocated |
| 85 // memory here by calling url_response_body_.reserve(). Doing so causes a |
| 86 // lot of string reallocations that kills performance for large files. |
| 64 url_response_body_.insert(url_response_body_.end(), | 87 url_response_body_.insert(url_response_body_.end(), |
| 65 buffer, | 88 buffer, |
| 66 buffer + num_bytes); | 89 buffer + num_bytes); |
| 67 } | 90 } |
| 68 | 91 |
| 69 void GetURLHandler::OnRead(int32_t result) { | 92 void GetURLHandler::OnRead(int32_t result) { |
| 70 if (result == PP_OK) { | 93 if (result == PP_OK) { |
| 71 // Streaming the file is complete. | 94 // Streaming the file is complete, delete the read buffer since it is |
| 95 // no longer needed. |
| 96 delete [] buffer_; |
| 97 buffer_ = NULL; |
| 72 ReportResultAndDie(url_, url_response_body_, true); | 98 ReportResultAndDie(url_, url_response_body_, true); |
| 73 } else if (result > 0) { | 99 } else if (result > 0) { |
| 74 // The URLLoader just filled "result" number of bytes into our buffer. | 100 // The URLLoader just filled "result" number of bytes into our buffer. |
| 75 // Save them and perform another read. | 101 // Save them and perform another read. |
| 76 AppendDataBytes(buffer_, result); | 102 AppendDataBytes(buffer_, result); |
| 77 ReadBody(); | 103 ReadBody(); |
| 78 } else { | 104 } else { |
| 79 // A read error occurred. | 105 // A read error occurred. |
| 80 ReportResultAndDie(url_, | 106 ReportResultAndDie(url_, |
| 81 "pp::URLLoader::ReadResponseBody() result<0", | 107 "pp::URLLoader::ReadResponseBody() result<0", |
| 82 false); | 108 false); |
| 83 } | 109 } |
| 84 } | 110 } |
| 85 | 111 |
| 86 void GetURLHandler::ReadBody() { | 112 void GetURLHandler::ReadBody() { |
| 87 // Note that you specifically want an "optional" callback here. This will | 113 // Note that you specifically want an "optional" callback here. This will |
| 88 // allow ReadBody() to return synchronously, ignoring your completion | 114 // allow ReadBody() to return synchronously, ignoring your completion |
| 89 // callback, if data is available. For fast connections and large files, | 115 // callback, if data is available. For fast connections and large files, |
| 90 // reading as fast as we can will make a large performance difference | 116 // reading as fast as we can will make a large performance difference |
| 91 // However, in the case of a synchronous return, we need to be sure to run | 117 // However, in the case of a synchronous return, we need to be sure to run |
| 92 // the callback we created since the loader won't do anything with it. | 118 // the callback we created since the loader won't do anything with it. |
| 93 pp::CompletionCallback cc = | 119 pp::CompletionCallback cc = |
| 94 cc_factory_.NewOptionalCallback(&GetURLHandler::OnRead); | 120 cc_factory_.NewOptionalCallback(&GetURLHandler::OnRead); |
| 95 int32_t result = PP_OK; | 121 int32_t result = PP_OK; |
| 96 do { | 122 do { |
| 97 result = url_loader_.ReadResponseBody(buffer_, sizeof(buffer_), cc); | 123 result = url_loader_.ReadResponseBody(buffer_, READ_BUFFER_SIZE, cc); |
| 98 // Handle streaming data directly. Note that we *don't* want to call | 124 // Handle streaming data directly. Note that we *don't* want to call |
| 99 // OnRead here, since in the case of result > 0 it will schedule | 125 // OnRead here, since in the case of result > 0 it will schedule |
| 100 // another call to this function. If the network is very fast, we could | 126 // another call to this function. If the network is very fast, we could |
| 101 // end up with a deeply recursive stack. | 127 // end up with a deeply recursive stack. |
| 102 if (result > 0) { | 128 if (result > 0) { |
| 103 AppendDataBytes(buffer_, result); | 129 AppendDataBytes(buffer_, result); |
| 104 } | 130 } |
| 105 } while (result > 0); | 131 } while (result > 0); |
| 106 | 132 |
| 107 if (result != PP_OK_COMPLETIONPENDING) { | 133 if (result != PP_OK_COMPLETIONPENDING) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 128 printf("GetURLHandler::ReportResult(Ok).\n"); | 154 printf("GetURLHandler::ReportResult(Ok).\n"); |
| 129 else | 155 else |
| 130 printf("GetURLHandler::ReportResult(Err). %s\n", text.c_str()); | 156 printf("GetURLHandler::ReportResult(Err). %s\n", text.c_str()); |
| 131 fflush(stdout); | 157 fflush(stdout); |
| 132 if (instance_) { | 158 if (instance_) { |
| 133 pp::Var var_result(fname + "\n" + text); | 159 pp::Var var_result(fname + "\n" + text); |
| 134 instance_->PostMessage(var_result); | 160 instance_->PostMessage(var_result); |
| 135 } | 161 } |
| 136 } | 162 } |
| 137 | 163 |
| OLD | NEW |