| Index: chrome/browser/local_discovery/privet_url_fetcher.cc
|
| diff --git a/chrome/browser/local_discovery/privet_url_fetcher.cc b/chrome/browser/local_discovery/privet_url_fetcher.cc
|
| deleted file mode 100644
|
| index f8cf3912474b8e76081a8c6f90d78ec23d0300a0..0000000000000000000000000000000000000000
|
| --- a/chrome/browser/local_discovery/privet_url_fetcher.cc
|
| +++ /dev/null
|
| @@ -1,389 +0,0 @@
|
| -// Copyright 2013 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "chrome/browser/local_discovery/privet_url_fetcher.h"
|
| -
|
| -#include <stdint.h>
|
| -
|
| -#include <algorithm>
|
| -#include <limits>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/debug/dump_without_crashing.h"
|
| -#include "base/json/json_reader.h"
|
| -#include "base/location.h"
|
| -#include "base/memory/singleton.h"
|
| -#include "base/rand_util.h"
|
| -#include "base/single_thread_task_runner.h"
|
| -#include "base/strings/stringprintf.h"
|
| -#include "base/thread_task_runner_handle.h"
|
| -#include "chrome/browser/browser_process.h"
|
| -#include "chrome/browser/local_discovery/privet_constants.h"
|
| -#include "content/public/browser/browser_thread.h"
|
| -#include "net/base/load_flags.h"
|
| -#include "net/http/http_status_code.h"
|
| -#include "net/url_request/url_request_context.h"
|
| -#include "net/url_request/url_request_status.h"
|
| -
|
| -namespace local_discovery {
|
| -
|
| -namespace {
|
| -
|
| -typedef std::map<std::string, std::string> TokenMap;
|
| -
|
| -struct TokenMapHolder {
|
| - public:
|
| - static TokenMapHolder* GetInstance() {
|
| - return base::Singleton<TokenMapHolder>::get();
|
| - }
|
| -
|
| - TokenMap map;
|
| -};
|
| -
|
| -const char kXPrivetTokenHeaderPrefix[] = "X-Privet-Token: ";
|
| -const char kRangeHeaderFormat[] = "Range: bytes=%d-%d";
|
| -const char kXPrivetEmptyToken[] = "\"\"";
|
| -const int kPrivetMaxRetries = 20;
|
| -const int kPrivetTimeoutOnError = 5;
|
| -const int kHTTPErrorCodeInvalidXPrivetToken = 418;
|
| -
|
| -std::string MakeRangeHeader(int start, int end) {
|
| - DCHECK_GE(start, 0);
|
| - DCHECK_GT(end, 0);
|
| - DCHECK_GT(end, start);
|
| - return base::StringPrintf(kRangeHeaderFormat, start, end);
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -void PrivetURLFetcher::Delegate::OnNeedPrivetToken(
|
| - PrivetURLFetcher* fetcher,
|
| - const TokenCallback& callback) {
|
| - OnError(fetcher, TOKEN_ERROR);
|
| -}
|
| -
|
| -bool PrivetURLFetcher::Delegate::OnRawData(PrivetURLFetcher* fetcher,
|
| - bool response_is_file,
|
| - const std::string& data_string,
|
| - const base::FilePath& data_file) {
|
| - return false;
|
| -}
|
| -
|
| -PrivetURLFetcher::PrivetURLFetcher(
|
| - const GURL& url,
|
| - net::URLFetcher::RequestType request_type,
|
| - const scoped_refptr<net::URLRequestContextGetter>& context_getter,
|
| - PrivetURLFetcher::Delegate* delegate)
|
| - : url_(url),
|
| - request_type_(request_type),
|
| - context_getter_(context_getter),
|
| - delegate_(delegate),
|
| - max_retries_(kPrivetMaxRetries),
|
| - do_not_retry_on_transient_error_(false),
|
| - send_empty_privet_token_(false),
|
| - has_byte_range_(false),
|
| - make_response_file_(false),
|
| - byte_range_start_(0),
|
| - byte_range_end_(0),
|
| - tries_(0),
|
| - weak_factory_(this) {}
|
| -
|
| -PrivetURLFetcher::~PrivetURLFetcher() {
|
| -}
|
| -
|
| -// static
|
| -void PrivetURLFetcher::SetTokenForHost(const std::string& host,
|
| - const std::string& token) {
|
| - TokenMapHolder::GetInstance()->map[host] = token;
|
| -}
|
| -
|
| -// static
|
| -void PrivetURLFetcher::ResetTokenMapForTests() {
|
| - TokenMapHolder::GetInstance()->map.clear();
|
| -}
|
| -
|
| -void PrivetURLFetcher::SetMaxRetries(int max_retries) {
|
| - DCHECK_EQ(tries_, 0);
|
| - max_retries_ = max_retries;
|
| -}
|
| -
|
| -void PrivetURLFetcher::DoNotRetryOnTransientError() {
|
| - DCHECK_EQ(tries_, 0);
|
| - do_not_retry_on_transient_error_ = true;
|
| -}
|
| -
|
| -void PrivetURLFetcher::SendEmptyPrivetToken() {
|
| - DCHECK_EQ(tries_, 0);
|
| - send_empty_privet_token_ = true;
|
| -}
|
| -
|
| -std::string PrivetURLFetcher::GetPrivetAccessToken() {
|
| - if (send_empty_privet_token_) {
|
| - return std::string();
|
| - }
|
| -
|
| - TokenMapHolder* token_map_holder = TokenMapHolder::GetInstance();
|
| - TokenMap::iterator found = token_map_holder->map.find(GetHostString());
|
| - return found != token_map_holder->map.end() ? found->second : std::string();
|
| -}
|
| -
|
| -std::string PrivetURLFetcher::GetHostString() {
|
| - return url_.GetOrigin().spec();
|
| -}
|
| -
|
| -void PrivetURLFetcher::SaveResponseToFile() {
|
| - DCHECK_EQ(tries_, 0);
|
| - make_response_file_ = true;
|
| -}
|
| -
|
| -void PrivetURLFetcher::SetByteRange(int start, int end) {
|
| - DCHECK_EQ(tries_, 0);
|
| - byte_range_start_ = start;
|
| - byte_range_end_ = end;
|
| - has_byte_range_ = true;
|
| -}
|
| -
|
| -void PrivetURLFetcher::Try() {
|
| - tries_++;
|
| - if (tries_ <= max_retries_) {
|
| - DVLOG(1) << "Attempt: " << tries_;
|
| - url_fetcher_ = net::URLFetcher::Create(url_, request_type_, this);
|
| - // Privet requests are relevant to hosts on local network only.
|
| - url_fetcher_->SetLoadFlags(
|
| - url_fetcher_->GetLoadFlags() | net::LOAD_BYPASS_PROXY |
|
| - net::LOAD_DISABLE_CACHE | net::LOAD_DO_NOT_SEND_COOKIES);
|
| - url_fetcher_->SetRequestContext(context_getter_.get());
|
| -
|
| - std::string token = GetPrivetAccessToken();
|
| -
|
| - if (token.empty())
|
| - token = kXPrivetEmptyToken;
|
| -
|
| - url_fetcher_->AddExtraRequestHeader(
|
| - std::string(kXPrivetTokenHeaderPrefix) + token);
|
| -
|
| - if (has_byte_range_) {
|
| - url_fetcher_->AddExtraRequestHeader(
|
| - MakeRangeHeader(byte_range_start_, byte_range_end_));
|
| - }
|
| -
|
| - if (make_response_file_) {
|
| - url_fetcher_->SaveResponseToTemporaryFile(
|
| - content::BrowserThread::GetMessageLoopProxyForThread(
|
| - content::BrowserThread::FILE));
|
| - }
|
| -
|
| - // URLFetcher requires us to set upload data for POST requests.
|
| - if (request_type_ == net::URLFetcher::POST) {
|
| - if (!upload_file_path_.empty()) {
|
| - url_fetcher_->SetUploadFilePath(
|
| - upload_content_type_, upload_file_path_, 0 /*offset*/,
|
| - std::numeric_limits<uint64_t>::max() /*length*/,
|
| - content::BrowserThread::GetMessageLoopProxyForThread(
|
| - content::BrowserThread::FILE));
|
| - } else {
|
| - url_fetcher_->SetUploadData(upload_content_type_, upload_data_);
|
| - }
|
| - }
|
| -
|
| - url_fetcher_->Start();
|
| - } else {
|
| - delegate_->OnError(this, UNKNOWN_ERROR);
|
| - }
|
| -}
|
| -
|
| -void PrivetURLFetcher::Start() {
|
| - DCHECK_EQ(tries_, 0); // We haven't called |Start()| yet.
|
| -
|
| - if (!url_.is_valid()) {
|
| - // Not yet clear why it's possible. crbug.com/513505
|
| - base::debug::DumpWithoutCrashing();
|
| - return delegate_->OnError(this, UNKNOWN_ERROR);
|
| - }
|
| -
|
| - if (!send_empty_privet_token_) {
|
| - std::string privet_access_token;
|
| - privet_access_token = GetPrivetAccessToken();
|
| - if (privet_access_token.empty()) {
|
| - RequestTokenRefresh();
|
| - return;
|
| - }
|
| - }
|
| -
|
| - Try();
|
| -}
|
| -
|
| -void PrivetURLFetcher::SetUploadData(const std::string& upload_content_type,
|
| - const std::string& upload_data) {
|
| - DCHECK(upload_file_path_.empty());
|
| - upload_content_type_ = upload_content_type;
|
| - upload_data_ = upload_data;
|
| -}
|
| -
|
| -void PrivetURLFetcher::SetUploadFilePath(
|
| - const std::string& upload_content_type,
|
| - const base::FilePath& upload_file_path) {
|
| - DCHECK(upload_data_.empty());
|
| - upload_content_type_ = upload_content_type;
|
| - upload_file_path_ = upload_file_path;
|
| -}
|
| -
|
| -void PrivetURLFetcher::OnURLFetchComplete(const net::URLFetcher* source) {
|
| - DVLOG(1) << "Status: " << source->GetStatus().status()
|
| - << ", ResponseCode: " << source->GetResponseCode();
|
| - if (source->GetStatus().status() != net::URLRequestStatus::CANCELED &&
|
| - (source->GetResponseCode() == net::HTTP_SERVICE_UNAVAILABLE ||
|
| - source->GetResponseCode() == net::URLFetcher::RESPONSE_CODE_INVALID)) {
|
| - ScheduleRetry(kPrivetTimeoutOnError);
|
| - return;
|
| - }
|
| -
|
| - if (!OnURLFetchCompleteDoNotParseData(source)) {
|
| - // Byte ranges should only be used when we're not parsing the data
|
| - // as JSON.
|
| - DCHECK(!has_byte_range_);
|
| -
|
| - // We should only be saving raw data to a file.
|
| - DCHECK(!make_response_file_);
|
| -
|
| - OnURLFetchCompleteParseData(source);
|
| - }
|
| -}
|
| -
|
| -// Note that this function returns "true" in error cases to indicate
|
| -// that it has fully handled the responses.
|
| -bool PrivetURLFetcher::OnURLFetchCompleteDoNotParseData(
|
| - const net::URLFetcher* source) {
|
| - if (source->GetStatus().status() == net::URLRequestStatus::CANCELED) {
|
| - delegate_->OnError(this, REQUEST_CANCELED);
|
| - return true;
|
| - }
|
| -
|
| - if (source->GetResponseCode() == kHTTPErrorCodeInvalidXPrivetToken) {
|
| - RequestTokenRefresh();
|
| - return true;
|
| - }
|
| -
|
| - if (source->GetResponseCode() != net::HTTP_OK &&
|
| - source->GetResponseCode() != net::HTTP_PARTIAL_CONTENT &&
|
| - source->GetResponseCode() != net::HTTP_BAD_REQUEST) {
|
| - delegate_->OnError(this, RESPONSE_CODE_ERROR);
|
| - return true;
|
| - }
|
| -
|
| - if (make_response_file_) {
|
| - base::FilePath response_file_path;
|
| -
|
| - if (!source->GetResponseAsFilePath(true, &response_file_path)) {
|
| - delegate_->OnError(this, UNKNOWN_ERROR);
|
| - return true;
|
| - }
|
| -
|
| - return delegate_->OnRawData(this, true, std::string(), response_file_path);
|
| - } else {
|
| - std::string response_str;
|
| -
|
| - if (!source->GetResponseAsString(&response_str)) {
|
| - delegate_->OnError(this, UNKNOWN_ERROR);
|
| - return true;
|
| - }
|
| -
|
| - return delegate_->OnRawData(this, false, response_str, base::FilePath());
|
| - }
|
| -}
|
| -
|
| -void PrivetURLFetcher::OnURLFetchCompleteParseData(
|
| - const net::URLFetcher* source) {
|
| - // Response contains error description.
|
| - bool is_error_response = false;
|
| - if (source->GetResponseCode() != net::HTTP_OK) {
|
| - delegate_->OnError(this, RESPONSE_CODE_ERROR);
|
| - return;
|
| - }
|
| -
|
| - std::string response_str;
|
| - if (!source->GetResponseAsString(&response_str)) {
|
| - delegate_->OnError(this, UNKNOWN_ERROR);
|
| - return;
|
| - }
|
| -
|
| - base::JSONReader json_reader(base::JSON_ALLOW_TRAILING_COMMAS);
|
| - scoped_ptr<base::Value> value = json_reader.ReadToValue(response_str);
|
| - if (!value) {
|
| - delegate_->OnError(this, JSON_PARSE_ERROR);
|
| - return;
|
| - }
|
| -
|
| - const base::DictionaryValue* dictionary_value = NULL;
|
| -
|
| - if (!value->GetAsDictionary(&dictionary_value)) {
|
| - delegate_->OnError(this, JSON_PARSE_ERROR);
|
| - return;
|
| - }
|
| -
|
| - std::string error;
|
| - if (dictionary_value->GetString(kPrivetKeyError, &error)) {
|
| - if (error == kPrivetErrorInvalidXPrivetToken) {
|
| - RequestTokenRefresh();
|
| - return;
|
| - } else if (PrivetErrorTransient(error)) {
|
| - if (!do_not_retry_on_transient_error_) {
|
| - int timeout_seconds;
|
| - if (!dictionary_value->GetInteger(kPrivetKeyTimeout,
|
| - &timeout_seconds)) {
|
| - timeout_seconds = kPrivetDefaultTimeout;
|
| - }
|
| -
|
| - ScheduleRetry(timeout_seconds);
|
| - return;
|
| - }
|
| - }
|
| - is_error_response = true;
|
| - }
|
| -
|
| - delegate_->OnParsedJson(this, *dictionary_value, is_error_response);
|
| -}
|
| -
|
| -void PrivetURLFetcher::ScheduleRetry(int timeout_seconds) {
|
| - double random_scaling_factor =
|
| - 1 + base::RandDouble() * kPrivetMaximumTimeRandomAddition;
|
| -
|
| - int timeout_seconds_randomized =
|
| - static_cast<int>(timeout_seconds * random_scaling_factor);
|
| -
|
| - timeout_seconds_randomized =
|
| - std::max(timeout_seconds_randomized, kPrivetMinimumTimeout);
|
| -
|
| - // Don't wait because only error callback is going to be called.
|
| - if (tries_ >= max_retries_)
|
| - timeout_seconds_randomized = 0;
|
| -
|
| - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
|
| - FROM_HERE, base::Bind(&PrivetURLFetcher::Try, weak_factory_.GetWeakPtr()),
|
| - base::TimeDelta::FromSeconds(timeout_seconds_randomized));
|
| -}
|
| -
|
| -void PrivetURLFetcher::RequestTokenRefresh() {
|
| - delegate_->OnNeedPrivetToken(
|
| - this,
|
| - base::Bind(&PrivetURLFetcher::RefreshToken, weak_factory_.GetWeakPtr()));
|
| -}
|
| -
|
| -void PrivetURLFetcher::RefreshToken(const std::string& token) {
|
| - if (token.empty()) {
|
| - delegate_->OnError(this, TOKEN_ERROR);
|
| - } else {
|
| - SetTokenForHost(GetHostString(), token);
|
| - Try();
|
| - }
|
| -}
|
| -
|
| -bool PrivetURLFetcher::PrivetErrorTransient(const std::string& error) {
|
| - return (error == kPrivetErrorDeviceBusy) ||
|
| - (error == kPrivetV3ErrorDeviceBusy) ||
|
| - (error == kPrivetErrorPendingUserAction) ||
|
| - (error == kPrivetErrorPrinterBusy);
|
| -}
|
| -
|
| -} // namespace local_discovery
|
|
|