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