17dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
27dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
37dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// found in the LICENSE file.
47dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
57dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/local_discovery/privet_url_fetcher.h"
67dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
7f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include <algorithm>
8f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
91e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/bind.h"
107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/json/json_reader.h"
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/memory/singleton.h"
121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/message_loop/message_loop.h"
131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/rand_util.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/stringprintf.h"
157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/browser_process.h"
167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/local_discovery/privet_constants.h"
17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "net/http/http_status_code.h"
197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "net/url_request/url_request_status.h"
207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochnamespace local_discovery {
227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochnamespace {
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)typedef std::map<std::string, std::string> TokenMap;
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)struct TokenMapHolder {
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public:
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  static TokenMapHolder* GetInstance() {
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return Singleton<TokenMapHolder>::get();
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  TokenMap map;
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)};
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochconst char kXPrivetTokenHeaderPrefix[] = "X-Privet-Token: ";
376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const char kXPrivetAuthTokenHeaderPrefix[] = "X-Privet-Auth: ";
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kRangeHeaderFormat[] = "Range: bytes=%d-%d";
398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)const char kXPrivetEmptyToken[] = "\"\"";
406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const char kPrivetAuthTokenUnknown[] = "Unknown";
411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const int kPrivetMaxRetries = 20;
42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int kPrivetTimeoutOnError = 5;
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kHTTPErrorCodeInvalidXPrivetToken = 418;
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string MakeRangeHeader(int start, int end) {
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_GE(start, 0);
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_GT(end, 0);
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_GT(end, start);
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return base::StringPrintf(kRangeHeaderFormat, start, end);
507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void PrivetURLFetcher::Delegate::OnNeedPrivetToken(
550f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    PrivetURLFetcher* fetcher,
560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    const TokenCallback& callback) {
570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  OnError(fetcher, TOKEN_ERROR);
580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)std::string PrivetURLFetcher::Delegate::GetAuthToken() {
616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return kPrivetAuthTokenUnknown;
626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool PrivetURLFetcher::Delegate::OnRawData(PrivetURLFetcher* fetcher,
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           bool response_is_file,
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           const std::string& data_string,
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           const base::FilePath& data_file) {
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
717dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochPrivetURLFetcher::PrivetURLFetcher(
727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const GURL& url,
737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    net::URLFetcher::RequestType request_type,
747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    net::URLRequestContextGetter* request_context,
757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    PrivetURLFetcher::Delegate* delegate)
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : url_(url),
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      request_type_(request_type),
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      request_context_(request_context),
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      delegate_(delegate),
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      do_not_retry_on_transient_error_(false),
81effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      send_empty_privet_token_(false),
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      has_byte_range_(false),
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      make_response_file_(false),
846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      v3_mode_(false),
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      byte_range_start_(0),
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      byte_range_end_(0),
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      tries_(0),
886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      weak_factory_(this) {
896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
917dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochPrivetURLFetcher::~PrivetURLFetcher() {
927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// static
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void PrivetURLFetcher::SetTokenForHost(const std::string& host,
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                       const std::string& token) {
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  TokenMapHolder::GetInstance()->map[host] = token;
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// static
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void PrivetURLFetcher::ResetTokenMapForTests() {
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  TokenMapHolder::GetInstance()->map.clear();
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void PrivetURLFetcher::DoNotRetryOnTransientError() {
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(tries_ == 0);
1070f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  do_not_retry_on_transient_error_ = true;
1080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
110effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid PrivetURLFetcher::SendEmptyPrivetToken() {
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(tries_ == 0);
112effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  send_empty_privet_token_ = true;
1130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)std::string PrivetURLFetcher::GetPrivetAccessToken() {
116effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (send_empty_privet_token_) {
117effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return std::string();
118effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
119effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  TokenMapHolder* token_map_holder = TokenMapHolder::GetInstance();
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  TokenMap::iterator found = token_map_holder->map.find(GetHostString());
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return found != token_map_holder->map.end() ? found->second : std::string();
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)std::string PrivetURLFetcher::GetHostString() {
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return url_.GetOrigin().spec();
127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void PrivetURLFetcher::SaveResponseToFile() {
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(tries_ == 0);
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  make_response_file_ = true;
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void PrivetURLFetcher::V3Mode() {
1356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  v3_mode_ = true;
1366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
1376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void PrivetURLFetcher::SetByteRange(int start, int end) {
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(tries_ == 0);
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  byte_range_start_ = start;
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  byte_range_end_ = end;
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  has_byte_range_ = true;
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void PrivetURLFetcher::Try() {
1461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  tries_++;
1471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (tries_ < kPrivetMaxRetries) {
1480f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1490f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    url_fetcher_.reset(net::URLFetcher::Create(url_, request_type_, this));
1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    url_fetcher_->SetRequestContext(request_context_.get());
1526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (v3_mode_) {
1546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      std::string auth_token = delegate_->GetAuthToken();
1556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      url_fetcher_->AddExtraRequestHeader(
1576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          std::string(kXPrivetAuthTokenHeaderPrefix) + auth_token);
1586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    } else {
1596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      std::string token = GetPrivetAccessToken();
1606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if (token.empty())
1626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        token = kXPrivetEmptyToken;
1636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      url_fetcher_->AddExtraRequestHeader(
1656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          std::string(kXPrivetTokenHeaderPrefix) + token);
1666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
1676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (has_byte_range_) {
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      url_fetcher_->AddExtraRequestHeader(
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          MakeRangeHeader(byte_range_start_, byte_range_end_));
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (make_response_file_) {
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      url_fetcher_->SaveResponseToTemporaryFile(
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          content::BrowserThread::GetMessageLoopProxyForThread(
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              content::BrowserThread::FILE));
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // URLFetcher requires us to set upload data for POST requests.
180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (request_type_ == net::URLFetcher::POST) {
181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if (!upload_file_path_.empty()) {
182f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        url_fetcher_->SetUploadFilePath(
183f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            upload_content_type_,
184f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            upload_file_path_,
185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            0 /*offset*/,
186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            kuint64max /*length*/,
187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            content::BrowserThread::GetMessageLoopProxyForThread(
188f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                content::BrowserThread::FILE));
189f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      } else {
190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        url_fetcher_->SetUploadData(upload_content_type_, upload_data_);
191f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      }
192f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
1931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    url_fetcher_->Start();
1951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  } else {
1961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    delegate_->OnError(this, RETRY_ERROR);
1971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
1981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid PrivetURLFetcher::Start() {
2011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DCHECK_EQ(tries_, 0);  // We haven't called |Start()| yet.
2020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (!send_empty_privet_token_ && !v3_mode_) {
204effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    std::string privet_access_token;
205effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    privet_access_token = GetPrivetAccessToken();
206effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (privet_access_token.empty()) {
207effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      RequestTokenRefresh();
208effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return;
209effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
2100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
211effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
212effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  Try();
2131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void PrivetURLFetcher::SetUploadData(const std::string& upload_content_type,
2161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                     const std::string& upload_data) {
217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(upload_file_path_.empty());
2181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  upload_content_type_ = upload_content_type;
2191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  upload_data_ = upload_data;
2207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void PrivetURLFetcher::SetUploadFilePath(
223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const std::string& upload_content_type,
224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const base::FilePath& upload_file_path) {
225f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(upload_data_.empty());
226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  upload_content_type_ = upload_content_type;
227f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  upload_file_path_ = upload_file_path;
228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid PrivetURLFetcher::OnURLFetchComplete(const net::URLFetcher* source) {
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (source->GetResponseCode() == net::HTTP_SERVICE_UNAVAILABLE) {
232f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ScheduleRetry(kPrivetTimeoutOnError);
2337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
2347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!OnURLFetchCompleteDoNotParseData(source)) {
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Byte ranges should only be used when we're not parsing the data
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // as JSON.
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(!has_byte_range_);
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // We should only be saving raw data to a file.
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(!make_response_file_);
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OnURLFetchCompleteParseData(source);
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Note that this function returns "true" in error cases to indicate
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// that it has fully handled the responses.
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool PrivetURLFetcher::OnURLFetchCompleteDoNotParseData(
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const net::URLFetcher* source) {
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (source->GetResponseCode() == kHTTPErrorCodeInvalidXPrivetToken) {
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RequestTokenRefresh();
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (source->GetResponseCode() != net::HTTP_OK &&
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      source->GetResponseCode() != net::HTTP_PARTIAL_CONTENT) {
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    delegate_->OnError(this, RESPONSE_CODE_ERROR);
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (make_response_file_) {
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::FilePath response_file_path;
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!source->GetResponseAsFilePath(true, &response_file_path)) {
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      delegate_->OnError(this, URL_FETCH_ERROR);
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return true;
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return delegate_->OnRawData(this, true, std::string(), response_file_path);
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string response_str;
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!source->GetResponseAsString(&response_str)) {
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      delegate_->OnError(this, URL_FETCH_ERROR);
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return true;
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return delegate_->OnRawData(this, false, response_str, base::FilePath());
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void PrivetURLFetcher::OnURLFetchCompleteParseData(
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const net::URLFetcher* source) {
2867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (source->GetResponseCode() != net::HTTP_OK) {
2877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    delegate_->OnError(this, RESPONSE_CODE_ERROR);
2887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
2897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  std::string response_str;
2927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!source->GetResponseAsString(&response_str)) {
2947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    delegate_->OnError(this, URL_FETCH_ERROR);
2957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
2967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::JSONReader json_reader(base::JSON_ALLOW_TRAILING_COMMAS);
2997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  scoped_ptr<base::Value> value;
3007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  value.reset(json_reader.ReadToValue(response_str));
3027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!value) {
3047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    delegate_->OnError(this, JSON_PARSE_ERROR);
3057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
3067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
3077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
308116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const base::DictionaryValue* dictionary_value = NULL;
3097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!value->GetAsDictionary(&dictionary_value)) {
3117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    delegate_->OnError(this, JSON_PARSE_ERROR);
3127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
3137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
3147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  std::string error;
3161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (dictionary_value->GetString(kPrivetKeyError, &error)) {
3170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    if (error == kPrivetErrorInvalidXPrivetToken) {
3180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      RequestTokenRefresh();
3190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      return;
320f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    } else if (PrivetErrorTransient(error)) {
3210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      if (!do_not_retry_on_transient_error_) {
3220f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        int timeout_seconds;
3230f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        if (!dictionary_value->GetInteger(kPrivetKeyTimeout,
3240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                                          &timeout_seconds)) {
3250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          timeout_seconds = kPrivetDefaultTimeout;
3260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        }
3270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
3280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        ScheduleRetry(timeout_seconds);
3290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        return;
3301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      }
3311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    }
3321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
3331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
334116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  delegate_->OnParsedJson(
335116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      this, *dictionary_value, dictionary_value->HasKey(kPrivetKeyError));
3367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
3377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void PrivetURLFetcher::ScheduleRetry(int timeout_seconds) {
3391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  double random_scaling_factor =
3401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      1 + base::RandDouble() * kPrivetMaximumTimeRandomAddition;
3411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  int timeout_seconds_randomized =
3431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      static_cast<int>(timeout_seconds * random_scaling_factor);
3441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  timeout_seconds_randomized =
346f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      std::max(timeout_seconds_randomized, kPrivetMinimumTimeout);
347f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
3491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      FROM_HERE,
3501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      base::Bind(&PrivetURLFetcher::Try, weak_factory_.GetWeakPtr()),
3511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      base::TimeDelta::FromSeconds(timeout_seconds_randomized));
3521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void PrivetURLFetcher::RequestTokenRefresh() {
3550f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  delegate_->OnNeedPrivetToken(
3560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      this,
3570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      base::Bind(&PrivetURLFetcher::RefreshToken, weak_factory_.GetWeakPtr()));
3580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
3590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
3600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void PrivetURLFetcher::RefreshToken(const std::string& token) {
3610f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (token.empty()) {
3620f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    delegate_->OnError(this, TOKEN_ERROR);
3630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  } else {
364a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    SetTokenForHost(GetHostString(), token);
3650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    Try();
3660f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
3670f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
3680f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
3691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)bool PrivetURLFetcher::PrivetErrorTransient(const std::string& error) {
3701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return (error == kPrivetErrorDeviceBusy) ||
371116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch         (error == kPrivetV3ErrorDeviceBusy) ||
372f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)         (error == kPrivetErrorPendingUserAction) ||
373f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)         (error == kPrivetErrorPrinterBusy);
3741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}  // namespace local_discovery
377