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 |