1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/url_request/test_url_fetcher_factory.h"
6 
7 #include <memory>
8 #include <string>
9 #include <utility>
10 
11 #include "base/bind.h"
12 #include "base/compiler_specific.h"
13 #include "base/files/file_util.h"
14 #include "base/location.h"
15 #include "base/logging.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/sequenced_task_runner.h"
18 #include "base/threading/sequenced_task_runner_handle.h"
19 #include "base/threading/thread_restrictions.h"
20 #include "net/base/completion_once_callback.h"
21 #include "net/base/io_buffer.h"
22 #include "net/base/net_errors.h"
23 #include "net/base/upload_data_stream.h"
24 #include "net/http/http_response_headers.h"
25 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
26 #include "net/url_request/url_fetcher_delegate.h"
27 #include "net/url_request/url_fetcher_impl.h"
28 #include "net/url_request/url_fetcher_response_writer.h"
29 
30 namespace net {
31 
ScopedURLFetcherFactory(URLFetcherFactory * factory)32 ScopedURLFetcherFactory::ScopedURLFetcherFactory(
33     URLFetcherFactory* factory) {
34   DCHECK(!URLFetcherImpl::factory());
35   URLFetcherImpl::set_factory(factory);
36 }
37 
~ScopedURLFetcherFactory()38 ScopedURLFetcherFactory::~ScopedURLFetcherFactory() {
39   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
40   DCHECK(URLFetcherImpl::factory());
41   URLFetcherImpl::set_factory(nullptr);
42 }
43 
TestURLFetcher(int id,const GURL & url,URLFetcherDelegate * d)44 TestURLFetcher::TestURLFetcher(int id, const GURL& url, URLFetcherDelegate* d)
45     : id_(id),
46       original_url_(url),
47       delegate_(d),
48       delegate_for_tests_(nullptr),
49       did_receive_last_chunk_(false),
50       fake_load_flags_(0),
51       fake_response_code_(-1),
52       fake_response_destination_(STRING),
53       write_response_file_(false),
54       fake_was_cached_(false),
55       fake_response_bytes_(0),
56       fake_max_retries_(0) {
57   CHECK(original_url_.is_valid());
58 }
59 
~TestURLFetcher()60 TestURLFetcher::~TestURLFetcher() {
61   if (delegate_for_tests_)
62     delegate_for_tests_->OnRequestEnd(id_);
63 }
64 
SetUploadData(const std::string & upload_content_type,const std::string & upload_content)65 void TestURLFetcher::SetUploadData(const std::string& upload_content_type,
66                                    const std::string& upload_content) {
67   upload_content_type_ = upload_content_type;
68   upload_data_ = upload_content;
69 }
70 
SetUploadFilePath(const std::string & upload_content_type,const base::FilePath & file_path,uint64_t range_offset,uint64_t range_length,scoped_refptr<base::TaskRunner> file_task_runner)71 void TestURLFetcher::SetUploadFilePath(
72     const std::string& upload_content_type,
73     const base::FilePath& file_path,
74     uint64_t range_offset,
75     uint64_t range_length,
76     scoped_refptr<base::TaskRunner> file_task_runner) {
77   upload_file_path_ = file_path;
78 }
79 
SetUploadStreamFactory(const std::string & upload_content_type,const CreateUploadStreamCallback & factory)80 void TestURLFetcher::SetUploadStreamFactory(
81     const std::string& upload_content_type,
82     const CreateUploadStreamCallback& factory) {
83 }
84 
SetChunkedUpload(const std::string & upload_content_type)85 void TestURLFetcher::SetChunkedUpload(const std::string& upload_content_type) {
86 }
87 
AppendChunkToUpload(const std::string & data,bool is_last_chunk)88 void TestURLFetcher::AppendChunkToUpload(const std::string& data,
89                                          bool is_last_chunk) {
90   DCHECK(!did_receive_last_chunk_);
91   did_receive_last_chunk_ = is_last_chunk;
92   chunks_.push_back(data);
93   if (delegate_for_tests_)
94     delegate_for_tests_->OnChunkUpload(id_);
95 }
96 
SetLoadFlags(int load_flags)97 void TestURLFetcher::SetLoadFlags(int load_flags) {
98   fake_load_flags_= load_flags;
99 }
100 
GetLoadFlags() const101 int TestURLFetcher::GetLoadFlags() const {
102   return fake_load_flags_;
103 }
104 
SetReferrer(const std::string & referrer)105 void TestURLFetcher::SetReferrer(const std::string& referrer) {
106 }
107 
SetReferrerPolicy(ReferrerPolicy referrer_policy)108 void TestURLFetcher::SetReferrerPolicy(ReferrerPolicy referrer_policy) {}
109 
SetExtraRequestHeaders(const std::string & extra_request_headers)110 void TestURLFetcher::SetExtraRequestHeaders(
111     const std::string& extra_request_headers) {
112   fake_extra_request_headers_.Clear();
113   fake_extra_request_headers_.AddHeadersFromString(extra_request_headers);
114 }
115 
AddExtraRequestHeader(const std::string & header_line)116 void TestURLFetcher::AddExtraRequestHeader(const std::string& header_line) {
117   fake_extra_request_headers_.AddHeaderFromString(header_line);
118 }
119 
SetRequestContext(URLRequestContextGetter * request_context_getter)120 void TestURLFetcher::SetRequestContext(
121     URLRequestContextGetter* request_context_getter) {
122 }
123 
SetInitiator(const base::Optional<url::Origin> & initiator)124 void TestURLFetcher::SetInitiator(
125     const base::Optional<url::Origin>& initiator) {}
126 
SetURLRequestUserData(const void * key,const CreateDataCallback & create_data_callback)127 void TestURLFetcher::SetURLRequestUserData(
128     const void* key,
129     const CreateDataCallback& create_data_callback) {
130 }
131 
SetStopOnRedirect(bool stop_on_redirect)132 void TestURLFetcher::SetStopOnRedirect(bool stop_on_redirect) {
133 }
134 
SetAutomaticallyRetryOn5xx(bool retry)135 void TestURLFetcher::SetAutomaticallyRetryOn5xx(bool retry) {
136 }
137 
SetMaxRetriesOn5xx(int max_retries)138 void TestURLFetcher::SetMaxRetriesOn5xx(int max_retries) {
139   fake_max_retries_ = max_retries;
140 }
141 
GetMaxRetriesOn5xx() const142 int TestURLFetcher::GetMaxRetriesOn5xx() const {
143   return fake_max_retries_;
144 }
145 
GetBackoffDelay() const146 base::TimeDelta TestURLFetcher::GetBackoffDelay() const {
147   return fake_backoff_delay_;
148 }
149 
SetAutomaticallyRetryOnNetworkChanges(int max_retries)150 void TestURLFetcher::SetAutomaticallyRetryOnNetworkChanges(int max_retries) {
151 }
152 
SaveResponseToFileAtPath(const base::FilePath & file_path,scoped_refptr<base::SequencedTaskRunner> file_task_runner)153 void TestURLFetcher::SaveResponseToFileAtPath(
154     const base::FilePath& file_path,
155     scoped_refptr<base::SequencedTaskRunner> file_task_runner) {
156   write_response_file_ = true;
157   SetResponseFilePath(file_path);
158   // Asynchronous IO is not supported, so file_task_runner is ignored.
159 }
160 
SaveResponseToTemporaryFile(scoped_refptr<base::SequencedTaskRunner> file_task_runner)161 void TestURLFetcher::SaveResponseToTemporaryFile(
162     scoped_refptr<base::SequencedTaskRunner> file_task_runner) {
163   base::FilePath path;
164   if (!base::CreateTemporaryFile(&path))
165     DLOG(ERROR) << "SaveResponseToTemporaryFile failed creating temp file";
166   SaveResponseToFileAtPath(path, file_task_runner);
167 }
168 
SaveResponseWithWriter(std::unique_ptr<URLFetcherResponseWriter> response_writer)169 void TestURLFetcher::SaveResponseWithWriter(
170     std::unique_ptr<URLFetcherResponseWriter> response_writer) {
171   // In class URLFetcherCore this method is called by all three:
172   // GetResponseAsString() / SaveResponseToFileAtPath() /
173   // SaveResponseToTemporaryFile(). But here (in TestURLFetcher), this method
174   // is never used by any of these three methods. So, file writing is expected
175   // to be done in SaveResponseToFileAtPath(), and this method supports only
176   // URLFetcherStringWriter (for testing of this method only).
177   if (fake_response_destination_ == STRING) {
178     response_writer_ = std::move(response_writer);
179     int response = response_writer_->Initialize(CompletionOnceCallback());
180     // The TestURLFetcher doesn't handle asynchronous writes.
181     DCHECK_EQ(OK, response);
182 
183     scoped_refptr<IOBuffer> buffer =
184         base::MakeRefCounted<StringIOBuffer>(fake_response_string_);
185     response = response_writer_->Write(
186         buffer.get(), fake_response_string_.size(), CompletionOnceCallback());
187     DCHECK_EQ(static_cast<int>(fake_response_string_.size()), response);
188     response = response_writer_->Finish(OK, CompletionOnceCallback());
189     DCHECK_EQ(OK, response);
190   } else if (fake_response_destination_ == TEMP_FILE) {
191     // SaveResponseToFileAtPath() should be called instead of this method to
192     // save file. Asynchronous file writing using URLFetcherFileWriter is not
193     // supported.
194     NOTIMPLEMENTED();
195   } else {
196     NOTREACHED();
197   }
198 }
199 
GetResponseHeaders() const200 HttpResponseHeaders* TestURLFetcher::GetResponseHeaders() const {
201   return fake_response_headers_.get();
202 }
203 
GetSocketAddress() const204 IPEndPoint TestURLFetcher::GetSocketAddress() const {
205   NOTIMPLEMENTED();
206   return IPEndPoint();
207 }
208 
ProxyServerUsed() const209 const ProxyServer& TestURLFetcher::ProxyServerUsed() const {
210   return fake_proxy_server_;
211 }
212 
WasCached() const213 bool TestURLFetcher::WasCached() const {
214   return fake_was_cached_;
215 }
216 
GetReceivedResponseContentLength() const217 int64_t TestURLFetcher::GetReceivedResponseContentLength() const {
218   return fake_response_bytes_;
219 }
220 
GetTotalReceivedBytes() const221 int64_t TestURLFetcher::GetTotalReceivedBytes() const {
222   return fake_was_cached_ ? 0 : fake_response_bytes_;
223 }
224 
Start()225 void TestURLFetcher::Start() {
226   // Overriden to do nothing. It is assumed the caller will notify the delegate.
227   if (delegate_for_tests_)
228     delegate_for_tests_->OnRequestStart(id_);
229 
230   // If the response should go into a file, write it out now.
231   if (fake_error_ == net::OK && fake_response_code_ == net::HTTP_OK &&
232       write_response_file_ && !fake_response_file_path_.empty()) {
233     base::ScopedAllowBlockingForTesting allow_blocking;
234     size_t written_bytes =
235         base::WriteFile(fake_response_file_path_, fake_response_string_.c_str(),
236                         fake_response_string_.size());
237     DCHECK_EQ(fake_response_string_.size(), written_bytes);
238   }
239 }
240 
GetOriginalURL() const241 const GURL& TestURLFetcher::GetOriginalURL() const {
242   return original_url_;
243 }
244 
GetURL() const245 const GURL& TestURLFetcher::GetURL() const {
246   return fake_url_;
247 }
248 
GetError() const249 Error TestURLFetcher::GetError() const {
250   return fake_error_;
251 }
252 
GetResponseCode() const253 int TestURLFetcher::GetResponseCode() const {
254   return fake_response_code_;
255 }
256 
ReceivedContentWasMalformed()257 void TestURLFetcher::ReceivedContentWasMalformed() {
258 }
259 
GetResponseAsString(std::string * out_response_string) const260 bool TestURLFetcher::GetResponseAsString(
261     std::string* out_response_string) const {
262   if (fake_response_destination_ != STRING)
263     return false;
264 
265   *out_response_string = fake_response_string_;
266   return true;
267 }
268 
GetResponseAsFilePath(bool take_ownership,base::FilePath * out_response_path) const269 bool TestURLFetcher::GetResponseAsFilePath(
270     bool take_ownership, base::FilePath* out_response_path) const {
271   if (fake_response_destination_ != TEMP_FILE)
272     return false;
273 
274   *out_response_path = fake_response_file_path_;
275   return true;
276 }
277 
GetExtraRequestHeaders(HttpRequestHeaders * headers) const278 void TestURLFetcher::GetExtraRequestHeaders(
279     HttpRequestHeaders* headers) const {
280   *headers = fake_extra_request_headers_;
281 }
282 
set_was_cached(bool flag)283 void TestURLFetcher::set_was_cached(bool flag) {
284   fake_was_cached_ = flag;
285 }
286 
set_response_headers(scoped_refptr<HttpResponseHeaders> headers)287 void TestURLFetcher::set_response_headers(
288     scoped_refptr<HttpResponseHeaders> headers) {
289   fake_response_headers_ = headers;
290 }
291 
set_backoff_delay(base::TimeDelta backoff_delay)292 void TestURLFetcher::set_backoff_delay(base::TimeDelta backoff_delay) {
293   fake_backoff_delay_ = backoff_delay;
294 }
295 
SetDelegateForTests(DelegateForTests * delegate_for_tests)296 void TestURLFetcher::SetDelegateForTests(DelegateForTests* delegate_for_tests) {
297   delegate_for_tests_ = delegate_for_tests;
298 }
299 
SetResponseString(const std::string & response)300 void TestURLFetcher::SetResponseString(const std::string& response) {
301   fake_response_destination_ = STRING;
302   fake_response_string_ = response;
303   fake_response_bytes_ = response.size();
304 }
305 
SetResponseFilePath(const base::FilePath & path)306 void TestURLFetcher::SetResponseFilePath(const base::FilePath& path) {
307   fake_response_destination_ = TEMP_FILE;
308   fake_response_file_path_ = path;
309 }
310 
FakeURLFetcher(const GURL & url,URLFetcherDelegate * d,const std::string & response_data,HttpStatusCode response_code,Error error)311 FakeURLFetcher::FakeURLFetcher(const GURL& url,
312                                URLFetcherDelegate* d,
313                                const std::string& response_data,
314                                HttpStatusCode response_code,
315                                Error error)
316     : TestURLFetcher(0, url, d) {
317   set_error(error);
318   set_response_code(response_code);
319   SetResponseString(response_data);
320   response_bytes_ = response_data.size();
321 }
322 
323 FakeURLFetcher::~FakeURLFetcher() = default;
324 
Start()325 void FakeURLFetcher::Start() {
326   TestURLFetcher::Start();
327   base::SequencedTaskRunnerHandle::Get()->PostTask(
328       FROM_HERE,
329       base::BindOnce(&FakeURLFetcher::RunDelegate, weak_factory_.GetWeakPtr()));
330 }
331 
RunDelegate()332 void FakeURLFetcher::RunDelegate() {
333   // OnURLFetchDownloadProgress may delete this URLFetcher. We keep track of
334   // this with a weak pointer, and only call OnURLFetchComplete if this still
335   // exists.
336   auto weak_this = weak_factory_.GetWeakPtr();
337   delegate()->OnURLFetchDownloadProgress(this, response_bytes_, response_bytes_,
338                                          response_bytes_);
339   if (weak_this.get())
340     delegate()->OnURLFetchComplete(this);
341 }
342 
GetURL() const343 const GURL& FakeURLFetcher::GetURL() const {
344   return TestURLFetcher::GetOriginalURL();
345 }
346 
FakeURLFetcherFactory(URLFetcherFactory * default_factory)347 FakeURLFetcherFactory::FakeURLFetcherFactory(URLFetcherFactory* default_factory)
348     : ScopedURLFetcherFactory(this),
349       creator_(base::BindRepeating(&DefaultFakeURLFetcherCreator)),
350       default_factory_(default_factory) {}
351 
FakeURLFetcherFactory(URLFetcherFactory * default_factory,const FakeURLFetcherCreator & creator)352 FakeURLFetcherFactory::FakeURLFetcherFactory(
353     URLFetcherFactory* default_factory,
354     const FakeURLFetcherCreator& creator)
355     : ScopedURLFetcherFactory(this),
356       creator_(creator),
357       default_factory_(default_factory) {
358 }
359 
360 std::unique_ptr<FakeURLFetcher>
DefaultFakeURLFetcherCreator(const GURL & url,URLFetcherDelegate * delegate,const std::string & response_data,HttpStatusCode response_code,Error error)361 FakeURLFetcherFactory::DefaultFakeURLFetcherCreator(
362     const GURL& url,
363     URLFetcherDelegate* delegate,
364     const std::string& response_data,
365     HttpStatusCode response_code,
366     Error error) {
367   return std::make_unique<FakeURLFetcher>(url, delegate, response_data,
368                                           response_code, error);
369 }
370 
371 FakeURLFetcherFactory::~FakeURLFetcherFactory() = default;
372 
CreateURLFetcher(int id,const GURL & url,URLFetcher::RequestType request_type,URLFetcherDelegate * d,NetworkTrafficAnnotationTag traffic_annotation)373 std::unique_ptr<URLFetcher> FakeURLFetcherFactory::CreateURLFetcher(
374     int id,
375     const GURL& url,
376     URLFetcher::RequestType request_type,
377     URLFetcherDelegate* d,
378     NetworkTrafficAnnotationTag traffic_annotation) {
379   FakeResponseMap::const_iterator it = fake_responses_.find(url);
380   if (it == fake_responses_.end()) {
381     if (default_factory_ == nullptr) {
382       // If we don't have a baked response for that URL we return NULL.
383       DLOG(ERROR) << "No baked response for URL: " << url.spec();
384       return nullptr;
385     } else {
386       return default_factory_->CreateURLFetcher(id, url, request_type, d,
387                                                 traffic_annotation);
388     }
389   }
390 
391   std::unique_ptr<URLFetcher> fake_fetcher =
392       creator_.Run(url, d, it->second.response_data, it->second.response_code,
393                    it->second.error);
394   return fake_fetcher;
395 }
396 
SetFakeResponse(const GURL & url,const std::string & response_data,HttpStatusCode response_code,Error error)397 void FakeURLFetcherFactory::SetFakeResponse(const GURL& url,
398                                             const std::string& response_data,
399                                             HttpStatusCode response_code,
400                                             Error error) {
401   // Overwrite existing URL if it already exists.
402   FakeURLResponse response;
403   response.response_data = response_data;
404   response.response_code = response_code;
405   response.error = error;
406   fake_responses_[url] = response;
407 }
408 
ClearFakeResponses()409 void FakeURLFetcherFactory::ClearFakeResponses() {
410   fake_responses_.clear();
411 }
412 
413 }  // namespace net
414