| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium 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 "chrome/browser/local_discovery/privet_url_fetcher.h" | 5 #include "chrome/browser/local_discovery/privet_url_fetcher.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/json/json_reader.h" | 10 #include "base/json/json_reader.h" |
| 11 #include "base/location.h" | 11 #include "base/location.h" |
| 12 #include "base/memory/singleton.h" | 12 #include "base/memory/singleton.h" |
| 13 #include "base/rand_util.h" | 13 #include "base/rand_util.h" |
| 14 #include "base/single_thread_task_runner.h" | 14 #include "base/single_thread_task_runner.h" |
| 15 #include "base/strings/stringprintf.h" | 15 #include "base/strings/stringprintf.h" |
| 16 #include "base/thread_task_runner_handle.h" | 16 #include "base/thread_task_runner_handle.h" |
| 17 #include "chrome/browser/browser_process.h" | 17 #include "chrome/browser/browser_process.h" |
| 18 #include "chrome/browser/local_discovery/privet_constants.h" | 18 #include "chrome/browser/local_discovery/privet_constants.h" |
| 19 #include "content/public/browser/browser_thread.h" | 19 #include "content/public/browser/browser_thread.h" |
| 20 #include "net/base/load_flags.h" | 20 #include "net/base/load_flags.h" |
| 21 #include "net/http/http_status_code.h" | 21 #include "net/http/http_status_code.h" |
| 22 #include "net/url_request/url_request_context.h" |
| 22 #include "net/url_request/url_request_status.h" | 23 #include "net/url_request/url_request_status.h" |
| 23 | 24 |
| 24 namespace local_discovery { | 25 namespace local_discovery { |
| 25 | 26 |
| 26 namespace { | 27 namespace { |
| 27 | 28 |
| 28 typedef std::map<std::string, std::string> TokenMap; | 29 typedef std::map<std::string, std::string> TokenMap; |
| 29 | 30 |
| 30 struct TokenMapHolder { | 31 struct TokenMapHolder { |
| 31 public: | 32 public: |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 67 bool PrivetURLFetcher::Delegate::OnRawData(PrivetURLFetcher* fetcher, | 68 bool PrivetURLFetcher::Delegate::OnRawData(PrivetURLFetcher* fetcher, |
| 68 bool response_is_file, | 69 bool response_is_file, |
| 69 const std::string& data_string, | 70 const std::string& data_string, |
| 70 const base::FilePath& data_file) { | 71 const base::FilePath& data_file) { |
| 71 return false; | 72 return false; |
| 72 } | 73 } |
| 73 | 74 |
| 74 PrivetURLFetcher::PrivetURLFetcher( | 75 PrivetURLFetcher::PrivetURLFetcher( |
| 75 const GURL& url, | 76 const GURL& url, |
| 76 net::URLFetcher::RequestType request_type, | 77 net::URLFetcher::RequestType request_type, |
| 77 net::URLRequestContextGetter* request_context, | 78 const scoped_refptr<net::URLRequestContextGetter>& context_getter, |
| 78 PrivetURLFetcher::Delegate* delegate) | 79 PrivetURLFetcher::Delegate* delegate) |
| 79 : url_(url), | 80 : url_(url), |
| 80 request_type_(request_type), | 81 request_type_(request_type), |
| 81 request_context_(request_context), | 82 context_getter_(context_getter), |
| 82 delegate_(delegate), | 83 delegate_(delegate), |
| 84 max_retries_(kPrivetMaxRetries), |
| 83 do_not_retry_on_transient_error_(false), | 85 do_not_retry_on_transient_error_(false), |
| 84 send_empty_privet_token_(false), | 86 send_empty_privet_token_(false), |
| 85 has_byte_range_(false), | 87 has_byte_range_(false), |
| 86 make_response_file_(false), | 88 make_response_file_(false), |
| 87 v3_mode_(false), | 89 v3_mode_(false), |
| 88 byte_range_start_(0), | 90 byte_range_start_(0), |
| 89 byte_range_end_(0), | 91 byte_range_end_(0), |
| 90 tries_(0), | 92 tries_(0), |
| 91 weak_factory_(this) { | 93 weak_factory_(this) {} |
| 92 } | |
| 93 | 94 |
| 94 PrivetURLFetcher::~PrivetURLFetcher() { | 95 PrivetURLFetcher::~PrivetURLFetcher() { |
| 95 } | 96 } |
| 96 | 97 |
| 97 // static | 98 // static |
| 98 void PrivetURLFetcher::SetTokenForHost(const std::string& host, | 99 void PrivetURLFetcher::SetTokenForHost(const std::string& host, |
| 99 const std::string& token) { | 100 const std::string& token) { |
| 100 TokenMapHolder::GetInstance()->map[host] = token; | 101 TokenMapHolder::GetInstance()->map[host] = token; |
| 101 } | 102 } |
| 102 | 103 |
| 103 // static | 104 // static |
| 104 void PrivetURLFetcher::ResetTokenMapForTests() { | 105 void PrivetURLFetcher::ResetTokenMapForTests() { |
| 105 TokenMapHolder::GetInstance()->map.clear(); | 106 TokenMapHolder::GetInstance()->map.clear(); |
| 106 } | 107 } |
| 107 | 108 |
| 109 void PrivetURLFetcher::SetMaxRetries(int max_retries) { |
| 110 DCHECK_EQ(tries_, 0); |
| 111 max_retries_ = max_retries; |
| 112 } |
| 113 |
| 108 void PrivetURLFetcher::DoNotRetryOnTransientError() { | 114 void PrivetURLFetcher::DoNotRetryOnTransientError() { |
| 109 DCHECK(tries_ == 0); | 115 DCHECK_EQ(tries_, 0); |
| 110 do_not_retry_on_transient_error_ = true; | 116 do_not_retry_on_transient_error_ = true; |
| 111 } | 117 } |
| 112 | 118 |
| 113 void PrivetURLFetcher::SendEmptyPrivetToken() { | 119 void PrivetURLFetcher::SendEmptyPrivetToken() { |
| 114 DCHECK(tries_ == 0); | 120 DCHECK_EQ(tries_, 0); |
| 115 send_empty_privet_token_ = true; | 121 send_empty_privet_token_ = true; |
| 116 } | 122 } |
| 117 | 123 |
| 118 std::string PrivetURLFetcher::GetPrivetAccessToken() { | 124 std::string PrivetURLFetcher::GetPrivetAccessToken() { |
| 119 if (send_empty_privet_token_) { | 125 if (send_empty_privet_token_) { |
| 120 return std::string(); | 126 return std::string(); |
| 121 } | 127 } |
| 122 | 128 |
| 123 TokenMapHolder* token_map_holder = TokenMapHolder::GetInstance(); | 129 TokenMapHolder* token_map_holder = TokenMapHolder::GetInstance(); |
| 124 TokenMap::iterator found = token_map_holder->map.find(GetHostString()); | 130 TokenMap::iterator found = token_map_holder->map.find(GetHostString()); |
| 125 return found != token_map_holder->map.end() ? found->second : std::string(); | 131 return found != token_map_holder->map.end() ? found->second : std::string(); |
| 126 } | 132 } |
| 127 | 133 |
| 128 std::string PrivetURLFetcher::GetHostString() { | 134 std::string PrivetURLFetcher::GetHostString() { |
| 129 return url_.GetOrigin().spec(); | 135 return url_.GetOrigin().spec(); |
| 130 } | 136 } |
| 131 | 137 |
| 132 void PrivetURLFetcher::SaveResponseToFile() { | 138 void PrivetURLFetcher::SaveResponseToFile() { |
| 133 DCHECK(tries_ == 0); | 139 DCHECK_EQ(tries_, 0); |
| 134 make_response_file_ = true; | 140 make_response_file_ = true; |
| 135 } | 141 } |
| 136 | 142 |
| 137 void PrivetURLFetcher::V3Mode() { | 143 void PrivetURLFetcher::V3Mode() { |
| 138 v3_mode_ = true; | 144 v3_mode_ = true; |
| 139 } | 145 } |
| 140 | 146 |
| 141 void PrivetURLFetcher::SetByteRange(int start, int end) { | 147 void PrivetURLFetcher::SetByteRange(int start, int end) { |
| 142 DCHECK(tries_ == 0); | 148 DCHECK_EQ(tries_, 0); |
| 143 byte_range_start_ = start; | 149 byte_range_start_ = start; |
| 144 byte_range_end_ = end; | 150 byte_range_end_ = end; |
| 145 has_byte_range_ = true; | 151 has_byte_range_ = true; |
| 146 } | 152 } |
| 147 | 153 |
| 148 void PrivetURLFetcher::Try() { | 154 void PrivetURLFetcher::Try() { |
| 149 tries_++; | 155 tries_++; |
| 150 if (tries_ < kPrivetMaxRetries) { | 156 if (tries_ <= max_retries_) { |
| 157 DVLOG(1) << "Try number: " << tries_; |
| 151 url_fetcher_ = net::URLFetcher::Create(url_, request_type_, this); | 158 url_fetcher_ = net::URLFetcher::Create(url_, request_type_, this); |
| 152 // Privet requests are relevant to hosts on local network only. | 159 // Privet requests are relevant to hosts on local network only. |
| 153 url_fetcher_->SetLoadFlags(url_fetcher_->GetLoadFlags() | | 160 url_fetcher_->SetLoadFlags( |
| 154 net::LOAD_BYPASS_PROXY | | 161 url_fetcher_->GetLoadFlags() | net::LOAD_BYPASS_PROXY | |
| 155 net::LOAD_DISABLE_CACHE); | 162 net::LOAD_DISABLE_CACHE | net::LOAD_DO_NOT_SEND_COOKIES); |
| 156 url_fetcher_->SetRequestContext(request_context_.get()); | 163 url_fetcher_->SetRequestContext(context_getter_.get()); |
| 157 | 164 |
| 158 if (v3_mode_) { | 165 if (v3_mode_) { |
| 159 url_fetcher_->AddExtraRequestHeader( | 166 url_fetcher_->AddExtraRequestHeader( |
| 160 std::string(kPrivetV3AuthTokenHeaderPrefix) + | 167 std::string(kPrivetV3AuthTokenHeaderPrefix) + |
| 161 delegate_->GetAuthToken()); | 168 delegate_->GetAuthToken()); |
| 162 } else { | 169 } else { |
| 163 std::string token = GetPrivetAccessToken(); | 170 std::string token = GetPrivetAccessToken(); |
| 164 | 171 |
| 165 if (token.empty()) | 172 if (token.empty()) |
| 166 token = kXPrivetEmptyToken; | 173 token = kXPrivetEmptyToken; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 190 kuint64max /*length*/, | 197 kuint64max /*length*/, |
| 191 content::BrowserThread::GetMessageLoopProxyForThread( | 198 content::BrowserThread::GetMessageLoopProxyForThread( |
| 192 content::BrowserThread::FILE)); | 199 content::BrowserThread::FILE)); |
| 193 } else { | 200 } else { |
| 194 url_fetcher_->SetUploadData(upload_content_type_, upload_data_); | 201 url_fetcher_->SetUploadData(upload_content_type_, upload_data_); |
| 195 } | 202 } |
| 196 } | 203 } |
| 197 | 204 |
| 198 url_fetcher_->Start(); | 205 url_fetcher_->Start(); |
| 199 } else { | 206 } else { |
| 200 delegate_->OnError(this, RETRY_ERROR); | 207 delegate_->OnError(this, UNKNOWN_ERROR); |
| 201 } | 208 } |
| 202 } | 209 } |
| 203 | 210 |
| 204 void PrivetURLFetcher::Start() { | 211 void PrivetURLFetcher::Start() { |
| 205 DCHECK_EQ(tries_, 0); // We haven't called |Start()| yet. | 212 DCHECK_EQ(tries_, 0); // We haven't called |Start()| yet. |
| 206 | 213 |
| 207 if (!send_empty_privet_token_ && !v3_mode_) { | 214 if (!send_empty_privet_token_ && !v3_mode_) { |
| 208 std::string privet_access_token; | 215 std::string privet_access_token; |
| 209 privet_access_token = GetPrivetAccessToken(); | 216 privet_access_token = GetPrivetAccessToken(); |
| 210 if (privet_access_token.empty()) { | 217 if (privet_access_token.empty()) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 225 | 232 |
| 226 void PrivetURLFetcher::SetUploadFilePath( | 233 void PrivetURLFetcher::SetUploadFilePath( |
| 227 const std::string& upload_content_type, | 234 const std::string& upload_content_type, |
| 228 const base::FilePath& upload_file_path) { | 235 const base::FilePath& upload_file_path) { |
| 229 DCHECK(upload_data_.empty()); | 236 DCHECK(upload_data_.empty()); |
| 230 upload_content_type_ = upload_content_type; | 237 upload_content_type_ = upload_content_type; |
| 231 upload_file_path_ = upload_file_path; | 238 upload_file_path_ = upload_file_path; |
| 232 } | 239 } |
| 233 | 240 |
| 234 void PrivetURLFetcher::OnURLFetchComplete(const net::URLFetcher* source) { | 241 void PrivetURLFetcher::OnURLFetchComplete(const net::URLFetcher* source) { |
| 235 if (source->GetResponseCode() == net::HTTP_SERVICE_UNAVAILABLE || | 242 DVLOG(1) << "Status: " << source->GetStatus().status() |
| 236 source->GetResponseCode() == net::URLFetcher::RESPONSE_CODE_INVALID) { | 243 << ", ResponseCode: " << source->GetResponseCode(); |
| 244 if (source->GetStatus().status() != net::URLRequestStatus::CANCELED && |
| 245 (source->GetResponseCode() == net::HTTP_SERVICE_UNAVAILABLE || |
| 246 source->GetResponseCode() == net::URLFetcher::RESPONSE_CODE_INVALID)) { |
| 237 ScheduleRetry(kPrivetTimeoutOnError); | 247 ScheduleRetry(kPrivetTimeoutOnError); |
| 238 return; | 248 return; |
| 239 } | 249 } |
| 240 | 250 |
| 241 if (!OnURLFetchCompleteDoNotParseData(source)) { | 251 if (!OnURLFetchCompleteDoNotParseData(source)) { |
| 242 // Byte ranges should only be used when we're not parsing the data | 252 // Byte ranges should only be used when we're not parsing the data |
| 243 // as JSON. | 253 // as JSON. |
| 244 DCHECK(!has_byte_range_); | 254 DCHECK(!has_byte_range_); |
| 245 | 255 |
| 246 // We should only be saving raw data to a file. | 256 // We should only be saving raw data to a file. |
| 247 DCHECK(!make_response_file_); | 257 DCHECK(!make_response_file_); |
| 248 | 258 |
| 249 OnURLFetchCompleteParseData(source); | 259 OnURLFetchCompleteParseData(source); |
| 250 } | 260 } |
| 251 } | 261 } |
| 252 | 262 |
| 253 // Note that this function returns "true" in error cases to indicate | 263 // Note that this function returns "true" in error cases to indicate |
| 254 // that it has fully handled the responses. | 264 // that it has fully handled the responses. |
| 255 bool PrivetURLFetcher::OnURLFetchCompleteDoNotParseData( | 265 bool PrivetURLFetcher::OnURLFetchCompleteDoNotParseData( |
| 256 const net::URLFetcher* source) { | 266 const net::URLFetcher* source) { |
| 267 if (source->GetStatus().status() == net::URLRequestStatus::CANCELED) { |
| 268 delegate_->OnError(this, REQUEST_CANCELED); |
| 269 return true; |
| 270 } |
| 271 |
| 257 if (source->GetResponseCode() == kHTTPErrorCodeInvalidXPrivetToken) { | 272 if (source->GetResponseCode() == kHTTPErrorCodeInvalidXPrivetToken) { |
| 258 RequestTokenRefresh(); | 273 RequestTokenRefresh(); |
| 259 return true; | 274 return true; |
| 260 } | 275 } |
| 261 | 276 |
| 262 if (source->GetResponseCode() != net::HTTP_OK && | 277 if (source->GetResponseCode() != net::HTTP_OK && |
| 263 source->GetResponseCode() != net::HTTP_PARTIAL_CONTENT && | 278 source->GetResponseCode() != net::HTTP_PARTIAL_CONTENT && |
| 264 source->GetResponseCode() != net::HTTP_BAD_REQUEST) { | 279 source->GetResponseCode() != net::HTTP_BAD_REQUEST) { |
| 265 delegate_->OnError(this, RESPONSE_CODE_ERROR); | 280 delegate_->OnError(this, RESPONSE_CODE_ERROR); |
| 266 return true; | 281 return true; |
| 267 } | 282 } |
| 268 | 283 |
| 269 if (make_response_file_) { | 284 if (make_response_file_) { |
| 270 base::FilePath response_file_path; | 285 base::FilePath response_file_path; |
| 271 | 286 |
| 272 if (!source->GetResponseAsFilePath(true, &response_file_path)) { | 287 if (!source->GetResponseAsFilePath(true, &response_file_path)) { |
| 273 delegate_->OnError(this, URL_FETCH_ERROR); | 288 delegate_->OnError(this, UNKNOWN_ERROR); |
| 274 return true; | 289 return true; |
| 275 } | 290 } |
| 276 | 291 |
| 277 return delegate_->OnRawData(this, true, std::string(), response_file_path); | 292 return delegate_->OnRawData(this, true, std::string(), response_file_path); |
| 278 } else { | 293 } else { |
| 279 std::string response_str; | 294 std::string response_str; |
| 280 | 295 |
| 281 if (!source->GetResponseAsString(&response_str)) { | 296 if (!source->GetResponseAsString(&response_str)) { |
| 282 delegate_->OnError(this, URL_FETCH_ERROR); | 297 delegate_->OnError(this, UNKNOWN_ERROR); |
| 283 return true; | 298 return true; |
| 284 } | 299 } |
| 285 | 300 |
| 286 return delegate_->OnRawData(this, false, response_str, base::FilePath()); | 301 return delegate_->OnRawData(this, false, response_str, base::FilePath()); |
| 287 } | 302 } |
| 288 } | 303 } |
| 289 | 304 |
| 290 void PrivetURLFetcher::OnURLFetchCompleteParseData( | 305 void PrivetURLFetcher::OnURLFetchCompleteParseData( |
| 291 const net::URLFetcher* source) { | 306 const net::URLFetcher* source) { |
| 292 // Response contains error description. | 307 // Response contains error description. |
| 293 bool is_error_response = false; | 308 bool is_error_response = false; |
| 294 if (v3_mode_ && source->GetResponseCode() == net::HTTP_BAD_REQUEST) { | 309 if (v3_mode_ && source->GetResponseCode() == net::HTTP_BAD_REQUEST) { |
| 295 is_error_response = true; | 310 is_error_response = true; |
| 296 } else if (source->GetResponseCode() != net::HTTP_OK) { | 311 } else if (source->GetResponseCode() != net::HTTP_OK) { |
| 297 delegate_->OnError(this, RESPONSE_CODE_ERROR); | 312 delegate_->OnError(this, RESPONSE_CODE_ERROR); |
| 298 return; | 313 return; |
| 299 } | 314 } |
| 300 | 315 |
| 301 std::string response_str; | 316 std::string response_str; |
| 302 if (!source->GetResponseAsString(&response_str)) { | 317 if (!source->GetResponseAsString(&response_str)) { |
| 303 delegate_->OnError(this, URL_FETCH_ERROR); | 318 delegate_->OnError(this, UNKNOWN_ERROR); |
| 304 return; | 319 return; |
| 305 } | 320 } |
| 306 | 321 |
| 307 base::JSONReader json_reader(base::JSON_ALLOW_TRAILING_COMMAS); | 322 base::JSONReader json_reader(base::JSON_ALLOW_TRAILING_COMMAS); |
| 308 scoped_ptr<base::Value> value = json_reader.ReadToValue(response_str); | 323 scoped_ptr<base::Value> value = json_reader.ReadToValue(response_str); |
| 309 if (!value) { | 324 if (!value) { |
| 310 delegate_->OnError(this, JSON_PARSE_ERROR); | 325 delegate_->OnError(this, JSON_PARSE_ERROR); |
| 311 return; | 326 return; |
| 312 } | 327 } |
| 313 | 328 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 344 void PrivetURLFetcher::ScheduleRetry(int timeout_seconds) { | 359 void PrivetURLFetcher::ScheduleRetry(int timeout_seconds) { |
| 345 double random_scaling_factor = | 360 double random_scaling_factor = |
| 346 1 + base::RandDouble() * kPrivetMaximumTimeRandomAddition; | 361 1 + base::RandDouble() * kPrivetMaximumTimeRandomAddition; |
| 347 | 362 |
| 348 int timeout_seconds_randomized = | 363 int timeout_seconds_randomized = |
| 349 static_cast<int>(timeout_seconds * random_scaling_factor); | 364 static_cast<int>(timeout_seconds * random_scaling_factor); |
| 350 | 365 |
| 351 timeout_seconds_randomized = | 366 timeout_seconds_randomized = |
| 352 std::max(timeout_seconds_randomized, kPrivetMinimumTimeout); | 367 std::max(timeout_seconds_randomized, kPrivetMinimumTimeout); |
| 353 | 368 |
| 369 // Don't wait because only error callback is going to be called. |
| 370 if (tries_ >= max_retries_) |
| 371 timeout_seconds_randomized = 0; |
| 372 |
| 354 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 373 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| 355 FROM_HERE, base::Bind(&PrivetURLFetcher::Try, weak_factory_.GetWeakPtr()), | 374 FROM_HERE, base::Bind(&PrivetURLFetcher::Try, weak_factory_.GetWeakPtr()), |
| 356 base::TimeDelta::FromSeconds(timeout_seconds_randomized)); | 375 base::TimeDelta::FromSeconds(timeout_seconds_randomized)); |
| 357 } | 376 } |
| 358 | 377 |
| 359 void PrivetURLFetcher::RequestTokenRefresh() { | 378 void PrivetURLFetcher::RequestTokenRefresh() { |
| 360 delegate_->OnNeedPrivetToken( | 379 delegate_->OnNeedPrivetToken( |
| 361 this, | 380 this, |
| 362 base::Bind(&PrivetURLFetcher::RefreshToken, weak_factory_.GetWeakPtr())); | 381 base::Bind(&PrivetURLFetcher::RefreshToken, weak_factory_.GetWeakPtr())); |
| 363 } | 382 } |
| 364 | 383 |
| 365 void PrivetURLFetcher::RefreshToken(const std::string& token) { | 384 void PrivetURLFetcher::RefreshToken(const std::string& token) { |
| 366 if (token.empty()) { | 385 if (token.empty()) { |
| 367 delegate_->OnError(this, TOKEN_ERROR); | 386 delegate_->OnError(this, TOKEN_ERROR); |
| 368 } else { | 387 } else { |
| 369 SetTokenForHost(GetHostString(), token); | 388 SetTokenForHost(GetHostString(), token); |
| 370 Try(); | 389 Try(); |
| 371 } | 390 } |
| 372 } | 391 } |
| 373 | 392 |
| 374 bool PrivetURLFetcher::PrivetErrorTransient(const std::string& error) { | 393 bool PrivetURLFetcher::PrivetErrorTransient(const std::string& error) { |
| 375 return (error == kPrivetErrorDeviceBusy) || | 394 return (error == kPrivetErrorDeviceBusy) || |
| 376 (error == kPrivetV3ErrorDeviceBusy) || | 395 (error == kPrivetV3ErrorDeviceBusy) || |
| 377 (error == kPrivetErrorPendingUserAction) || | 396 (error == kPrivetErrorPendingUserAction) || |
| 378 (error == kPrivetErrorPrinterBusy); | 397 (error == kPrivetErrorPrinterBusy); |
| 379 } | 398 } |
| 380 | 399 |
| 381 } // namespace local_discovery | 400 } // namespace local_discovery |
| OLD | NEW |