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_GE(start, 0); |
| 32 DCHECK_GT(end, 0); |
| 33 DCHECK_GT(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 |
| 45 bool PrivetURLFetcher::Delegate::OnRawData(PrivetURLFetcher* fetcher, |
| 46 bool response_is_file, |
| 47 const std::string& data_string, |
| 48 const base::FilePath& data_file) { |
| 49 return false; |
| 50 } |
| 51 |
34 PrivetURLFetcher::PrivetURLFetcher( | 52 PrivetURLFetcher::PrivetURLFetcher( |
35 const std::string& token, | 53 const std::string& token, |
36 const GURL& url, | 54 const GURL& url, |
37 net::URLFetcher::RequestType request_type, | 55 net::URLFetcher::RequestType request_type, |
38 net::URLRequestContextGetter* request_context, | 56 net::URLRequestContextGetter* request_context, |
39 PrivetURLFetcher::Delegate* delegate) | 57 PrivetURLFetcher::Delegate* delegate) |
40 : privet_access_token_(token), url_(url), request_type_(request_type), | 58 : privet_access_token_(token), |
41 request_context_(request_context), delegate_(delegate), | 59 url_(url), |
42 do_not_retry_on_transient_error_(false), allow_empty_privet_token_(false), | 60 request_type_(request_type), |
43 tries_(0), weak_factory_(this) { | 61 request_context_(request_context), |
| 62 delegate_(delegate), |
| 63 do_not_retry_on_transient_error_(false), |
| 64 allow_empty_privet_token_(false), |
| 65 has_byte_range_(false), |
| 66 make_response_file_(false), |
| 67 byte_range_start_(0), |
| 68 byte_range_end_(0), |
| 69 tries_(0), |
| 70 weak_factory_(this) { |
44 } | 71 } |
45 | 72 |
46 PrivetURLFetcher::~PrivetURLFetcher() { | 73 PrivetURLFetcher::~PrivetURLFetcher() { |
47 } | 74 } |
48 | 75 |
49 void PrivetURLFetcher::DoNotRetryOnTransientError() { | 76 void PrivetURLFetcher::DoNotRetryOnTransientError() { |
| 77 DCHECK(tries_ == 0); |
50 do_not_retry_on_transient_error_ = true; | 78 do_not_retry_on_transient_error_ = true; |
51 } | 79 } |
52 | 80 |
53 void PrivetURLFetcher::AllowEmptyPrivetToken() { | 81 void PrivetURLFetcher::AllowEmptyPrivetToken() { |
| 82 DCHECK(tries_ == 0); |
54 allow_empty_privet_token_ = true; | 83 allow_empty_privet_token_ = true; |
55 } | 84 } |
56 | 85 |
| 86 void PrivetURLFetcher::SaveResponseToFile() { |
| 87 DCHECK(tries_ == 0); |
| 88 make_response_file_ = true; |
| 89 } |
| 90 |
| 91 void PrivetURLFetcher::SetByteRange(int start, int end) { |
| 92 DCHECK(tries_ == 0); |
| 93 byte_range_start_ = start; |
| 94 byte_range_end_ = end; |
| 95 has_byte_range_ = true; |
| 96 } |
| 97 |
57 void PrivetURLFetcher::Try() { | 98 void PrivetURLFetcher::Try() { |
58 tries_++; | 99 tries_++; |
59 if (tries_ < kPrivetMaxRetries) { | 100 if (tries_ < kPrivetMaxRetries) { |
60 std::string token = privet_access_token_; | 101 std::string token = privet_access_token_; |
61 | 102 |
62 if (token.empty()) | 103 if (token.empty()) |
63 token = kXPrivetEmptyToken; | 104 token = kXPrivetEmptyToken; |
64 | 105 |
65 url_fetcher_.reset(net::URLFetcher::Create(url_, request_type_, this)); | 106 url_fetcher_.reset(net::URLFetcher::Create(url_, request_type_, this)); |
66 url_fetcher_->SetRequestContext(request_context_); | 107 url_fetcher_->SetRequestContext(request_context_); |
67 url_fetcher_->AddExtraRequestHeader(std::string(kXPrivetTokenHeaderPrefix) + | 108 url_fetcher_->AddExtraRequestHeader(std::string(kXPrivetTokenHeaderPrefix) + |
68 token); | 109 token); |
| 110 if (has_byte_range_) { |
| 111 url_fetcher_->AddExtraRequestHeader( |
| 112 MakeRangeHeader(byte_range_start_, byte_range_end_)); |
| 113 } |
| 114 |
| 115 if (make_response_file_) { |
| 116 url_fetcher_->SaveResponseToTemporaryFile( |
| 117 content::BrowserThread::GetMessageLoopProxyForThread( |
| 118 content::BrowserThread::FILE)); |
| 119 } |
69 | 120 |
70 // URLFetcher requires us to set upload data for POST requests. | 121 // URLFetcher requires us to set upload data for POST requests. |
71 if (request_type_ == net::URLFetcher::POST) { | 122 if (request_type_ == net::URLFetcher::POST) { |
72 if (!upload_file_path_.empty()) { | 123 if (!upload_file_path_.empty()) { |
73 url_fetcher_->SetUploadFilePath( | 124 url_fetcher_->SetUploadFilePath( |
74 upload_content_type_, | 125 upload_content_type_, |
75 upload_file_path_, | 126 upload_file_path_, |
76 0 /*offset*/, | 127 0 /*offset*/, |
77 kuint64max /*length*/, | 128 kuint64max /*length*/, |
78 content::BrowserThread::GetMessageLoopProxyForThread( | 129 content::BrowserThread::GetMessageLoopProxyForThread( |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
112 upload_content_type_ = upload_content_type; | 163 upload_content_type_ = upload_content_type; |
113 upload_file_path_ = upload_file_path; | 164 upload_file_path_ = upload_file_path; |
114 } | 165 } |
115 | 166 |
116 void PrivetURLFetcher::OnURLFetchComplete(const net::URLFetcher* source) { | 167 void PrivetURLFetcher::OnURLFetchComplete(const net::URLFetcher* source) { |
117 if (source->GetResponseCode() == net::HTTP_SERVICE_UNAVAILABLE) { | 168 if (source->GetResponseCode() == net::HTTP_SERVICE_UNAVAILABLE) { |
118 ScheduleRetry(kPrivetTimeoutOnError); | 169 ScheduleRetry(kPrivetTimeoutOnError); |
119 return; | 170 return; |
120 } | 171 } |
121 | 172 |
| 173 if (!OnURLFetchCompleteDoNotParseData(source)) { |
| 174 // Byte ranges should only be used when we're not parsing the data |
| 175 // as JSON. |
| 176 DCHECK(!has_byte_range_); |
| 177 |
| 178 // We should only be saving raw data to a file. |
| 179 DCHECK(!make_response_file_); |
| 180 |
| 181 OnURLFetchCompleteParseData(source); |
| 182 } |
| 183 } |
| 184 |
| 185 // Note that this function returns "true" in error cases to indicate |
| 186 // that it has fully handled the responses. |
| 187 bool PrivetURLFetcher::OnURLFetchCompleteDoNotParseData( |
| 188 const net::URLFetcher* source) { |
| 189 if (source->GetResponseCode() == kHTTPErrorCodeInvalidXPrivetToken) { |
| 190 RequestTokenRefresh(); |
| 191 return true; |
| 192 } |
| 193 |
| 194 if (source->GetResponseCode() != net::HTTP_OK && |
| 195 source->GetResponseCode() != net::HTTP_PARTIAL_CONTENT) { |
| 196 delegate_->OnError(this, RESPONSE_CODE_ERROR); |
| 197 return true; |
| 198 } |
| 199 |
| 200 if (make_response_file_) { |
| 201 base::FilePath response_file_path; |
| 202 |
| 203 if (!source->GetResponseAsFilePath(true, &response_file_path)) { |
| 204 delegate_->OnError(this, URL_FETCH_ERROR); |
| 205 return true; |
| 206 } |
| 207 |
| 208 return delegate_->OnRawData(this, true, std::string(), response_file_path); |
| 209 } else { |
| 210 std::string response_str; |
| 211 |
| 212 if (!source->GetResponseAsString(&response_str)) { |
| 213 delegate_->OnError(this, URL_FETCH_ERROR); |
| 214 return true; |
| 215 } |
| 216 |
| 217 return delegate_->OnRawData(this, false, response_str, base::FilePath()); |
| 218 } |
| 219 } |
| 220 |
| 221 void PrivetURLFetcher::OnURLFetchCompleteParseData( |
| 222 const net::URLFetcher* source) { |
122 if (source->GetResponseCode() != net::HTTP_OK) { | 223 if (source->GetResponseCode() != net::HTTP_OK) { |
123 delegate_->OnError(this, RESPONSE_CODE_ERROR); | 224 delegate_->OnError(this, RESPONSE_CODE_ERROR); |
124 return; | 225 return; |
125 } | 226 } |
126 | 227 |
127 std::string response_str; | 228 std::string response_str; |
128 | 229 |
129 if (!source->GetResponseAsString(&response_str)) { | 230 if (!source->GetResponseAsString(&response_str)) { |
130 delegate_->OnError(this, URL_FETCH_ERROR); | 231 delegate_->OnError(this, URL_FETCH_ERROR); |
131 return; | 232 return; |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
218 | 319 |
219 scoped_ptr<PrivetURLFetcher> PrivetURLFetcherFactory::CreateURLFetcher( | 320 scoped_ptr<PrivetURLFetcher> PrivetURLFetcherFactory::CreateURLFetcher( |
220 const GURL& url, net::URLFetcher::RequestType request_type, | 321 const GURL& url, net::URLFetcher::RequestType request_type, |
221 PrivetURLFetcher::Delegate* delegate) const { | 322 PrivetURLFetcher::Delegate* delegate) const { |
222 return scoped_ptr<PrivetURLFetcher>( | 323 return scoped_ptr<PrivetURLFetcher>( |
223 new PrivetURLFetcher(token_, url, request_type, request_context_.get(), | 324 new PrivetURLFetcher(token_, url, request_type, request_context_.get(), |
224 delegate)); | 325 delegate)); |
225 } | 326 } |
226 | 327 |
227 } // namespace local_discovery | 328 } // namespace local_discovery |
OLD | NEW |