Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(65)

Side by Side Diff: experimental/flocking_geese/url_io/web_resource_loader.cc

Issue 10928195: First round of dead file removal (Closed) Base URL: https://github.com/samclegg/nativeclient-sdk.git@master
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « experimental/flocking_geese/url_io/web_resource_loader.h ('k') | experimental/hex/README » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4 #include "url_io/web_resource_loader.h"
5
6 #include <algorithm>
7 #include <cassert>
8 #include <stdio.h>
9 #include "ppapi/c/pp_errors.h"
10 #include "ppapi/cpp/module.h"
11 #include "ppapi/cpp/url_loader.h"
12 #include "ppapi/cpp/url_request_info.h"
13 #include "ppapi/cpp/url_response_info.h"
14
15 #include "threading/scoped_mutex_lock.h"
16 #include "url_io/url_request.h"
17
18 namespace {
19 // Skip white space in string str, starting at index pos. Returns the index of
20 // the first non white-space character found, or str.length() if only
21 // whitespace characters are found.
22 size_t SkipWhiteSpace(const std::string& str, size_t pos) {
23 size_t str_length = str.length();
24 while (pos < str_length && ::isspace(str[pos])) {
25 ++pos;
26 }
27 return pos;
28 }
29 } // anonymous namespace
30
31 namespace url_io {
32
33 WebResourceLoader::WebResourceLoader(pp::Instance* instance,
34 WebResourceLoader::Delegate* delegate)
35 : factory_(this),
36 instance_(instance),
37 url_loader_(*instance),
38 state_(kStateNotConnected),
39 buffer_(NULL),
40 buffer_size_(0),
41 data_size_(0),
42 delegate_(delegate) {
43 assert(delegate != NULL);
44 pthread_mutex_init(&state_mutex_, NULL);
45 }
46
47 void WebResourceLoader::CloseAndDeleteSelf() {
48 // Can't close & delete this instance here. Instead, we schedule a main-thread
49 // callback to delete it later.
50 pp::CompletionCallback cc(DeleteOnMainThread, this);
51 pp::Module::Get()->core()->CallOnMainThread(0, cc, PP_OK);
52 }
53
54 WebResourceLoader::~WebResourceLoader() {
55 Close();
56 pthread_mutex_destroy(&state_mutex_);
57 }
58
59 void WebResourceLoader::LoadURL(const URLRequest& url_request) {
60 // TODO(gwink): add support for stream-to-file.
61 assert(!url_request.stream_to_file() && "Stream-to-file not implemented.");
62 // Check that there is no pending request.
63 assert(state_ == kStateNotConnected);
64
65 if (state_ == kStateNotConnected) {
66 state_ = kStateConnecting;
67 pp::CompletionCallback cc = factory_.NewCallback(
68 &WebResourceLoader::InternalLoadURL, url_request);
69 pp::Module::Get()->core()->CallOnMainThread(0, cc, PP_OK);
70 }
71 }
72
73 bool WebResourceLoader::ReadMoreData() {
74 pthread_mutex_lock(&state_mutex_);
75 assert(state_ == kStateInvokedDelegate || state_ == kStateSuspended);
76
77 if (state_ == kStateSuspended) {
78 // Call resume on the main thread.
79 state_ = kStateDownloading;
80 pthread_mutex_unlock(&state_mutex_);
81 pp::CompletionCallback cc = factory_.NewCallback(
82 &WebResourceLoader::InternalReadMoreData);
83 pp::Module::Get()->core()->CallOnMainThread(0, cc, PP_OK);
84 return true;
85 } else if (state_ == kStateInvokedDelegate) {
86 // We're currently within a delegate function. Advance the state to
87 // will-read-more-data; that insures we'll schedule the next read op when
88 // the delegate returns control to this instance.
89 state_ = kStateWillReadMoreData;
90 pthread_mutex_unlock(&state_mutex_);
91 return true;
92 }
93 state_ = kStateNotConnected;
94 pthread_mutex_unlock(&state_mutex_);
95 return false;
96 }
97
98 void WebResourceLoader::set_content_buffer(uint8_t* buffer, int32_t size) {
99 buffer_ = buffer;
100 buffer_size_ = size;
101 }
102
103 const std::string WebResourceLoader::url() const {
104 pp::URLResponseInfo response = url_loader_.GetResponseInfo();
105 return response.GetURL().AsString();
106 }
107
108 int32_t WebResourceLoader::GetHttpStatus() const {
109 return GetResponseInfo().GetStatusCode();
110 }
111
112 pp::URLResponseInfo WebResourceLoader::GetResponseInfo() const {
113 assert(pp::Module::Get()->core()->IsMainThread());
114 pp::URLResponseInfo response = url_loader_.GetResponseInfo();
115 assert(!response.is_null());
116 return response;
117 }
118
119 int32_t WebResourceLoader::GetContentLength() const {
120 HeaderDictionary::const_iterator it =
121 response_headers_.find("CONTENT-LENGTH");
122 if (it == response_headers_.end()) {
123 return 0;
124 } else {
125 // Return content-length value string, converted to int.
126 return static_cast<int32_t>(atol((*it).second.c_str()));
127 }
128 }
129
130 void WebResourceLoader::Close() {
131 assert(pp::Module::Get()->core()->IsMainThread());
132 url_loader_.Close();
133 buffer_ = NULL;
134 buffer_size_ = 0;
135 data_size_ = 0;
136 state_ = kStateNotConnected;
137 response_headers_.clear();
138 }
139
140 void WebResourceLoader::DoResponseInfoReceived(int32_t result) {
141 pthread_mutex_lock(&state_mutex_);
142 pp::URLResponseInfo response = url_loader_.GetResponseInfo();
143 ParseHeaders(response);
144 state_ = kStateInvokedDelegate;
145 pthread_mutex_unlock(&state_mutex_);
146 delegate_->OnLoaderReceivedResponseInfo(this);
147
148 pthread_mutex_lock(&state_mutex_);
149 if (state_ == kStateWillReadMoreData) {
150 state_ = kStateDownloading;
151 pthread_mutex_unlock(&state_mutex_);
152 pp::CompletionCallback cc = factory_.NewCallback(
153 &WebResourceLoader::InternalReadMoreData);
154 pp::Module::Get()->core()->CallOnMainThread(0, cc, PP_OK);
155 } else {
156 state_ = kStateSuspended;
157 pthread_mutex_unlock(&state_mutex_);
158 }
159 }
160
161 void WebResourceLoader::DoDataReceived(int32_t result) {
162 pthread_mutex_lock(&state_mutex_);
163 if (result == 0) {
164 // No more data; the download completed successfully.
165 state_ = kStateNotConnected;
166 data_size_ = 0;
167 pthread_mutex_unlock(&state_mutex_);
168 delegate_->OnLoaderCompletedDownload(this);
169 delegate_->OnLoaderDone(this);
170 } else {
171 assert(result > 0);
172 // We received a block of data of size |result|.
173 data_size_ = result;
174 state_ = kStateInvokedDelegate;
175 pthread_mutex_unlock(&state_mutex_);
176 delegate_->OnLoaderReceivedData(this);
177
178 pthread_mutex_lock(&state_mutex_);
179 if (state_ == kStateWillReadMoreData) {
180 state_ = kStateDownloading;
181 pthread_mutex_unlock(&state_mutex_);
182 pp::CompletionCallback cc = factory_.NewCallback(
183 &WebResourceLoader::InternalReadMoreData);
184 pp::Module::Get()->core()->CallOnMainThread(0, cc, PP_OK);
185 } else {
186 state_ = kStateSuspended;
187 pthread_mutex_unlock(&state_mutex_);
188 }
189 }
190 }
191
192 void WebResourceLoader::DoDownloadError(int32_t result) {
193 pthread_mutex_lock(&state_mutex_);
194 state_ = kStateNotConnected;
195 pthread_mutex_unlock(&state_mutex_);
196 delegate_->OnLoaderError(result, this);
197 delegate_->OnLoaderDone(this);
198 }
199
200 void WebResourceLoader::CompletionCallbackFunc(int32_t result,
201 CallbackOpCode op_code) {
202 // TODO(gwink): add support for follow-redirect.
203 if (result < 0) {
204 // A negative value indicates an error.
205 DoDownloadError(result);
206 } else if (result == PP_OK && state_ == kStateConnecting) {
207 // If we're not yet connected and result == PP_OK, then we received
208 // the http headers.
209 assert(op_code == kResponseInfoCallback);
210 DoResponseInfoReceived(result);
211 } else {
212 assert(op_code == kDataReceivedCallback);
213 DoDataReceived(result);
214 }
215 }
216
217 pp::CompletionCallback WebResourceLoader::MakeCallback(CallbackOpCode op_code) {
218 return factory_.NewCallback(
219 &WebResourceLoader::CompletionCallbackFunc, op_code);
220 }
221
222 void WebResourceLoader::InternalLoadURL(int32_t result,
223 const URLRequest& url_request) {
224 if (result == PP_OK) {
225 // Only usable from main plugin thread.
226 assert(pp::Module::Get()->core()->IsMainThread());
227
228 pp::CompletionCallback cc = MakeCallback(kResponseInfoCallback);
229 int32_t rv = url_loader_.Open(url_request.GetRequestInfo(instance_), cc);
230 assert(rv == PP_OK_COMPLETIONPENDING);
231 }
232 }
233
234 void WebResourceLoader::InternalReadMoreData(int32_t result) {
235 if (result == PP_OK) {
236 // If a custom buffer has not been set or has been set to NULL, use the
237 // internal buffer.
238 if (buffer_ == NULL) {
239 buffer_ = internal_buffer_;
240 buffer_size_ = kInternalBufferSize;
241 }
242 // Get the next block of data.
243 pp::CompletionCallback cc = MakeCallback(kDataReceivedCallback);
244 int32_t rv = url_loader_.ReadResponseBody(buffer_, buffer_size_, cc);
245 assert(rv == PP_OK_COMPLETIONPENDING);
246 }
247 }
248
249 void WebResourceLoader::ParseHeaders(pp::URLResponseInfo response) {
250 // The headers dictionary should be empty.
251 assert(response_headers_.empty());
252 response_headers_.clear();
253
254 // Get the headers as a string.
255 pp::Var headers_var = response.GetHeaders();
256 assert(headers_var.is_string());
257 if (!headers_var.is_string())
258 return;
259 std::string headers = headers_var.AsString();
260
261 // Parse headers.
262 size_t i_line = 0;
263 size_t headers_length = headers.length();
264 std::string key;
265 while (i_line != std::string::npos && i_line < headers_length) {
266 // A line that starts with space or tab continues the previous line.
267 size_t i_value = i_line;
268 if (!::isspace(headers[i_line])) {
269 // Extract the key.
270 size_t i_key = i_line;
271 size_t i_separator = headers.find(':', i_key);
272 if (i_separator == std::string::npos)
273 return;
274 key = headers.substr(i_key, i_separator - i_key);
275 i_value = i_separator + 1;
276 // Convert key to all upper case.
277 std::transform(key.begin(), key.end(), key.begin(), ::toupper);
278 }
279
280 // Extract the value.
281 i_value = SkipWhiteSpace(headers, i_value);
282 if (i_value >= headers_length)
283 return;
284 size_t i_eol = headers.find_first_of("\r\n", i_value);
285 std::string value = headers.substr(
286 i_value, (i_eol == std::string::npos)? i_eol : i_eol - i_value);
287
288
289 if (!value.empty() && !key.empty()) {
290 // Append the value to what's already in the map; that takes care of
291 // values that are spread over multiple lines.
292 response_headers_[key].append(value);
293 }
294
295 // Skip crlf at eol.
296 while (i_eol < headers_length &&
297 (headers[i_eol] == '\r' || headers[i_eol] == '\n')) {
298 ++i_eol;
299 }
300 i_line = i_eol;
301 }
302 }
303
304 void WebResourceLoader::DeleteOnMainThread(void* user_data, int32_t err) {
305 WebResourceLoader* loader = static_cast<WebResourceLoader*>(user_data);
306 if (loader != NULL) {
307 loader->Close();
308 delete loader;
309 }
310 }
311
312 } // namespace url_io
OLDNEW
« no previous file with comments | « experimental/flocking_geese/url_io/web_resource_loader.h ('k') | experimental/hex/README » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698