Chromium Code Reviews| 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/message_loop/message_loop.h" | 11 #include "base/message_loop/message_loop.h" |
| 12 #include "base/rand_util.h" | 12 #include "base/rand_util.h" |
| 13 #include "base/strings/stringprintf.h" | |
| 13 #include "chrome/browser/browser_process.h" | 14 #include "chrome/browser/browser_process.h" |
| 14 #include "chrome/browser/local_discovery/privet_constants.h" | 15 #include "chrome/browser/local_discovery/privet_constants.h" |
| 15 #include "content/public/browser/browser_thread.h" | 16 #include "content/public/browser/browser_thread.h" |
| 16 #include "net/http/http_status_code.h" | 17 #include "net/http/http_status_code.h" |
| 17 #include "net/url_request/url_request_status.h" | 18 #include "net/url_request/url_request_status.h" |
| 18 | 19 |
| 19 namespace local_discovery { | 20 namespace local_discovery { |
| 20 | 21 |
| 21 namespace { | 22 namespace { |
| 22 const char kXPrivetTokenHeaderPrefix[] = "X-Privet-Token: "; | 23 const char kXPrivetTokenHeaderPrefix[] = "X-Privet-Token: "; |
| 24 const char kRangeHeaderFormat[] = "Range: bytes=%d-%d"; | |
| 23 const char kXPrivetEmptyToken[] = "\"\""; | 25 const char kXPrivetEmptyToken[] = "\"\""; |
| 24 const int kPrivetMaxRetries = 20; | 26 const int kPrivetMaxRetries = 20; |
| 25 const int kPrivetTimeoutOnError = 5; | 27 const int kPrivetTimeoutOnError = 5; |
| 28 const int kHTTPErrorCodeInvalidXPrivetToken = 418; | |
| 29 | |
| 30 std::string MakeRangeHeader(int start, int end) { | |
| 31 DCHECK(start >= 0); | |
|
Vitaly Buka (NO REVIEWS)
2014/02/07 19:47:39
DCHECK_GT?
Noam Samuel
2014/02/12 20:25:16
Done.
| |
| 32 DCHECK(end > 0); | |
| 33 DCHECK(end > start); | |
| 34 return base::StringPrintf(kRangeHeaderFormat, start, end); | |
| 26 } | 35 } |
| 27 | 36 |
| 37 } // namespace | |
| 38 | |
| 28 void PrivetURLFetcher::Delegate::OnNeedPrivetToken( | 39 void PrivetURLFetcher::Delegate::OnNeedPrivetToken( |
| 29 PrivetURLFetcher* fetcher, | 40 PrivetURLFetcher* fetcher, |
| 30 const TokenCallback& callback) { | 41 const TokenCallback& callback) { |
| 31 OnError(fetcher, TOKEN_ERROR); | 42 OnError(fetcher, TOKEN_ERROR); |
| 32 } | 43 } |
| 33 | 44 |
| 34 PrivetURLFetcher::PrivetURLFetcher( | 45 PrivetURLFetcher::PrivetURLFetcher( |
| 35 const std::string& token, | 46 const std::string& token, |
| 36 const GURL& url, | 47 const GURL& url, |
| 37 net::URLFetcher::RequestType request_type, | 48 net::URLFetcher::RequestType request_type, |
| 38 net::URLRequestContextGetter* request_context, | 49 net::URLRequestContextGetter* request_context, |
| 39 PrivetURLFetcher::Delegate* delegate) | 50 PrivetURLFetcher::Delegate* delegate) |
| 40 : privet_access_token_(token), url_(url), request_type_(request_type), | 51 : privet_access_token_(token), url_(url), request_type_(request_type), |
|
Vitaly Buka (NO REVIEWS)
2014/02/07 19:47:39
one per line might be more readable.
Noam Samuel
2014/02/12 20:25:16
Done.
| |
| 41 request_context_(request_context), delegate_(delegate), | 52 request_context_(request_context), delegate_(delegate), |
| 42 do_not_retry_on_transient_error_(false), allow_empty_privet_token_(false), | 53 do_not_retry_on_transient_error_(false), allow_empty_privet_token_(false), |
| 43 tries_(0), weak_factory_(this) { | 54 do_not_parse_data_(false), has_byte_range_(false), |
|
Vitaly Buka (NO REVIEWS)
2014/02/07 19:47:39
probably do_not_parse_data_ is depends on delegate
Noam Samuel
2014/02/12 20:25:16
Done.
| |
| 55 make_response_file_(false), byte_range_start_(0), | |
| 56 byte_range_end_(0), tries_(0), weak_factory_(this) { | |
| 44 } | 57 } |
| 45 | 58 |
| 46 PrivetURLFetcher::~PrivetURLFetcher() { | 59 PrivetURLFetcher::~PrivetURLFetcher() { |
| 47 } | 60 } |
| 48 | 61 |
| 49 void PrivetURLFetcher::DoNotRetryOnTransientError() { | 62 void PrivetURLFetcher::DoNotRetryOnTransientError() { |
| 63 DCHECK(tries_ == 0); | |
| 50 do_not_retry_on_transient_error_ = true; | 64 do_not_retry_on_transient_error_ = true; |
| 51 } | 65 } |
| 52 | 66 |
| 53 void PrivetURLFetcher::AllowEmptyPrivetToken() { | 67 void PrivetURLFetcher::AllowEmptyPrivetToken() { |
| 68 DCHECK(tries_ == 0); | |
| 54 allow_empty_privet_token_ = true; | 69 allow_empty_privet_token_ = true; |
| 55 } | 70 } |
| 56 | 71 |
| 72 void PrivetURLFetcher::DoNotParseData() { | |
| 73 DCHECK(tries_ == 0); | |
| 74 do_not_parse_data_ = true; | |
| 75 } | |
| 76 | |
| 77 void PrivetURLFetcher::SaveResponseToFile() { | |
| 78 DCHECK(tries_ == 0); | |
| 79 make_response_file_ = true; | |
| 80 } | |
| 81 | |
| 82 void PrivetURLFetcher::SetByteRange(int start, int end) { | |
| 83 DCHECK(tries_ == 0); | |
| 84 byte_range_start_ = start; | |
| 85 byte_range_end_ = end; | |
| 86 has_byte_range_ = true; | |
| 87 } | |
| 88 | |
| 57 void PrivetURLFetcher::Try() { | 89 void PrivetURLFetcher::Try() { |
| 58 tries_++; | 90 tries_++; |
| 59 if (tries_ < kPrivetMaxRetries) { | 91 if (tries_ < kPrivetMaxRetries) { |
| 60 std::string token = privet_access_token_; | 92 std::string token = privet_access_token_; |
| 61 | 93 |
| 62 if (token.empty()) | 94 if (token.empty()) |
| 63 token = kXPrivetEmptyToken; | 95 token = kXPrivetEmptyToken; |
| 64 | 96 |
| 65 url_fetcher_.reset(net::URLFetcher::Create(url_, request_type_, this)); | 97 url_fetcher_.reset(net::URLFetcher::Create(url_, request_type_, this)); |
| 66 url_fetcher_->SetRequestContext(request_context_); | 98 url_fetcher_->SetRequestContext(request_context_); |
| 67 url_fetcher_->AddExtraRequestHeader(std::string(kXPrivetTokenHeaderPrefix) + | 99 url_fetcher_->AddExtraRequestHeader(std::string(kXPrivetTokenHeaderPrefix) + |
| 68 token); | 100 token); |
| 101 if (has_byte_range_) { | |
| 102 url_fetcher_->AddExtraRequestHeader( | |
| 103 MakeRangeHeader(byte_range_start_, byte_range_end_)); | |
| 104 } | |
| 105 | |
| 106 if (make_response_file_) { | |
| 107 url_fetcher_->SaveResponseToTemporaryFile( | |
| 108 content::BrowserThread::GetMessageLoopProxyForThread( | |
| 109 content::BrowserThread::FILE)); | |
| 110 } | |
| 69 | 111 |
| 70 // URLFetcher requires us to set upload data for POST requests. | 112 // URLFetcher requires us to set upload data for POST requests. |
| 71 if (request_type_ == net::URLFetcher::POST) { | 113 if (request_type_ == net::URLFetcher::POST) { |
| 72 if (!upload_file_path_.empty()) { | 114 if (!upload_file_path_.empty()) { |
| 73 url_fetcher_->SetUploadFilePath( | 115 url_fetcher_->SetUploadFilePath( |
| 74 upload_content_type_, | 116 upload_content_type_, |
| 75 upload_file_path_, | 117 upload_file_path_, |
| 76 0 /*offset*/, | 118 0 /*offset*/, |
| 77 kuint64max /*length*/, | 119 kuint64max /*length*/, |
| 78 content::BrowserThread::GetMessageLoopProxyForThread( | 120 content::BrowserThread::GetMessageLoopProxyForThread( |
| 79 content::BrowserThread::FILE)); | 121 content::BrowserThread::FILE)); |
| 80 } else { | 122 } else { |
| 81 url_fetcher_->SetUploadData(upload_content_type_, upload_data_); | 123 url_fetcher_->SetUploadData(upload_content_type_, upload_data_); |
| 82 } | 124 } |
| 83 } | 125 } |
| 84 | 126 |
| 85 url_fetcher_->Start(); | 127 url_fetcher_->Start(); |
| 86 } else { | 128 } else { |
| 87 delegate_->OnError(this, RETRY_ERROR); | 129 delegate_->OnError(this, RETRY_ERROR); |
| 88 } | 130 } |
| 89 } | 131 } |
| 90 | 132 |
| 91 void PrivetURLFetcher::Start() { | 133 void PrivetURLFetcher::Start() { |
| 92 DCHECK_EQ(tries_, 0); // We haven't called |Start()| yet. | 134 DCHECK_EQ(tries_, 0); // We haven't called |Start()| yet. |
| 93 | 135 |
| 136 // Byte ranges should only be used when we're not parsing the data | |
| 137 // as JSON. | |
| 138 DCHECK(!has_byte_range_ || do_not_parse_data_); | |
| 139 | |
| 140 // We should only be saving raw data to a file. | |
| 141 DCHECK(!make_response_file_ || do_not_parse_data_); | |
| 142 | |
| 94 if (privet_access_token_.empty() && !allow_empty_privet_token_) { | 143 if (privet_access_token_.empty() && !allow_empty_privet_token_) { |
| 95 RequestTokenRefresh(); | 144 RequestTokenRefresh(); |
| 96 } else { | 145 } else { |
| 97 Try(); | 146 Try(); |
| 98 } | 147 } |
| 99 } | 148 } |
| 100 | 149 |
| 101 void PrivetURLFetcher::SetUploadData(const std::string& upload_content_type, | 150 void PrivetURLFetcher::SetUploadData(const std::string& upload_content_type, |
| 102 const std::string& upload_data) { | 151 const std::string& upload_data) { |
| 103 DCHECK(upload_file_path_.empty()); | 152 DCHECK(upload_file_path_.empty()); |
| 104 upload_content_type_ = upload_content_type; | 153 upload_content_type_ = upload_content_type; |
| 105 upload_data_ = upload_data; | 154 upload_data_ = upload_data; |
| 106 } | 155 } |
| 107 | 156 |
| 108 void PrivetURLFetcher::SetUploadFilePath( | 157 void PrivetURLFetcher::SetUploadFilePath( |
| 109 const std::string& upload_content_type, | 158 const std::string& upload_content_type, |
| 110 const base::FilePath& upload_file_path) { | 159 const base::FilePath& upload_file_path) { |
| 111 DCHECK(upload_data_.empty()); | 160 DCHECK(upload_data_.empty()); |
| 112 upload_content_type_ = upload_content_type; | 161 upload_content_type_ = upload_content_type; |
| 113 upload_file_path_ = upload_file_path; | 162 upload_file_path_ = upload_file_path; |
| 114 } | 163 } |
| 115 | 164 |
| 116 void PrivetURLFetcher::OnURLFetchComplete(const net::URLFetcher* source) { | 165 void PrivetURLFetcher::OnURLFetchComplete(const net::URLFetcher* source) { |
| 117 if (source->GetResponseCode() == net::HTTP_SERVICE_UNAVAILABLE) { | 166 if (source->GetResponseCode() == net::HTTP_SERVICE_UNAVAILABLE) { |
| 118 ScheduleRetry(kPrivetTimeoutOnError); | 167 ScheduleRetry(kPrivetTimeoutOnError); |
| 119 return; | 168 return; |
| 120 } | 169 } |
| 121 | 170 |
| 171 if (do_not_parse_data_) { | |
| 172 OnURLFetchCompleteDoNotParseData(source); | |
| 173 } else { | |
| 174 OnURLFetchCompleteParseData(source); | |
| 175 } | |
| 176 } | |
| 177 | |
| 178 void PrivetURLFetcher::OnURLFetchCompleteDoNotParseData( | |
| 179 const net::URLFetcher* source) { | |
| 180 if (source->GetResponseCode() == kHTTPErrorCodeInvalidXPrivetToken) { | |
| 181 RequestTokenRefresh(); | |
| 182 return; | |
| 183 } | |
| 184 | |
| 185 if (source->GetResponseCode() != net::HTTP_OK && | |
| 186 source->GetResponseCode() != net::HTTP_PARTIAL_CONTENT) { | |
| 187 delegate_->OnError(this, RESPONSE_CODE_ERROR); | |
| 188 return; | |
| 189 } | |
| 190 | |
| 191 if (make_response_file_) { | |
| 192 base::FilePath response_file_path; | |
| 193 | |
| 194 if (!source->GetResponseAsFilePath(true, &response_file_path)) { | |
| 195 delegate_->OnError(this, URL_FETCH_ERROR); | |
| 196 return; | |
| 197 } | |
| 198 | |
| 199 delegate_->OnRawData(this, true, std::string(), response_file_path); | |
| 200 } else { | |
| 201 std::string response_str; | |
| 202 | |
| 203 if (!source->GetResponseAsString(&response_str)) { | |
| 204 delegate_->OnError(this, URL_FETCH_ERROR); | |
| 205 return; | |
| 206 } | |
| 207 | |
| 208 delegate_->OnRawData(this, false, response_str, base::FilePath()); | |
| 209 } | |
| 210 } | |
| 211 | |
| 212 void PrivetURLFetcher::OnURLFetchCompleteParseData( | |
| 213 const net::URLFetcher* source) { | |
| 122 if (source->GetResponseCode() != net::HTTP_OK) { | 214 if (source->GetResponseCode() != net::HTTP_OK) { |
| 123 delegate_->OnError(this, RESPONSE_CODE_ERROR); | 215 delegate_->OnError(this, RESPONSE_CODE_ERROR); |
| 124 return; | 216 return; |
| 125 } | 217 } |
| 126 | 218 |
| 127 std::string response_str; | 219 std::string response_str; |
| 128 | 220 |
| 129 if (!source->GetResponseAsString(&response_str)) { | 221 if (!source->GetResponseAsString(&response_str)) { |
| 130 delegate_->OnError(this, URL_FETCH_ERROR); | 222 delegate_->OnError(this, URL_FETCH_ERROR); |
| 131 return; | 223 return; |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 218 | 310 |
| 219 scoped_ptr<PrivetURLFetcher> PrivetURLFetcherFactory::CreateURLFetcher( | 311 scoped_ptr<PrivetURLFetcher> PrivetURLFetcherFactory::CreateURLFetcher( |
| 220 const GURL& url, net::URLFetcher::RequestType request_type, | 312 const GURL& url, net::URLFetcher::RequestType request_type, |
| 221 PrivetURLFetcher::Delegate* delegate) const { | 313 PrivetURLFetcher::Delegate* delegate) const { |
| 222 return scoped_ptr<PrivetURLFetcher>( | 314 return scoped_ptr<PrivetURLFetcher>( |
| 223 new PrivetURLFetcher(token_, url, request_type, request_context_.get(), | 315 new PrivetURLFetcher(token_, url, request_type, request_context_.get(), |
| 224 delegate)); | 316 delegate)); |
| 225 } | 317 } |
| 226 | 318 |
| 227 } // namespace local_discovery | 319 } // namespace local_discovery |
| OLD | NEW |