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#ifndef NET_URL_REQUEST_TEST_URL_FETCHER_FACTORY_H_
6#define NET_URL_REQUEST_TEST_URL_FETCHER_FACTORY_H_
7
8#include <list>
9#include <map>
10#include <string>
11#include <utility>
12
13#include "base/basictypes.h"
14#include "base/callback.h"
15#include "base/compiler_specific.h"
16#include "base/files/file_path.h"
17#include "base/memory/scoped_ptr.h"
18#include "base/memory/weak_ptr.h"
19#include "base/threading/non_thread_safe.h"
20#include "net/http/http_request_headers.h"
21#include "net/http/http_status_code.h"
22#include "net/url_request/url_fetcher_factory.h"
23#include "net/url_request/url_request_status.h"
24#include "url/gurl.h"
25
26namespace net {
27
28// Changes URLFetcher's Factory for the lifetime of the object.
29// Note that this scoper cannot be nested (to make it even harder to misuse).
30class ScopedURLFetcherFactory : public base::NonThreadSafe {
31 public:
32  explicit ScopedURLFetcherFactory(URLFetcherFactory* factory);
33  virtual ~ScopedURLFetcherFactory();
34
35 private:
36  DISALLOW_COPY_AND_ASSIGN(ScopedURLFetcherFactory);
37};
38
39// TestURLFetcher and TestURLFetcherFactory are used for testing consumers of
40// URLFetcher. TestURLFetcherFactory is a URLFetcherFactory that creates
41// TestURLFetchers. TestURLFetcher::Start is overriden to do nothing. It is
42// expected that you'll grab the delegate from the TestURLFetcher and invoke
43// the callback method when appropriate. In this way it's easy to mock a
44// URLFetcher.
45// Typical usage:
46//   // TestURLFetcher requires a MessageLoop.
47//   MessageLoop message_loop;
48//   // And an IO thread to release URLRequestContextGetter in URLFetcher::Core.
49//   BrowserThreadImpl io_thread(BrowserThread::IO, &message_loop);
50//   // Create factory (it automatically sets itself as URLFetcher's factory).
51//   TestURLFetcherFactory factory;
52//   // Do something that triggers creation of a URLFetcher.
53//   ...
54//   TestURLFetcher* fetcher = factory.GetFetcherByID(expected_id);
55//   DCHECK(fetcher);
56//   // Notify delegate with whatever data you want.
57//   fetcher->delegate()->OnURLFetchComplete(...);
58//   // Make sure consumer of URLFetcher does the right thing.
59//   ...
60//
61// Note: if you don't know when your request objects will be created you
62// might want to use the FakeURLFetcher and FakeURLFetcherFactory classes
63// below.
64
65class TestURLFetcherFactory;
66class TestURLFetcher : public URLFetcher {
67 public:
68  // Interface for tests to intercept production code classes using URLFetcher.
69  // Allows even-driven mock server classes to analyze the correctness of
70  // requests / uploads events and forge responses back at the right moment.
71  class DelegateForTests {
72   public:
73    // Callback issued correspondingly to the call to the |Start()| method.
74    virtual void OnRequestStart(int fetcher_id) = 0;
75
76    // Callback issued correspondingly to the call to |AppendChunkToUpload|.
77    // Uploaded chunks can be retrieved with the |upload_chunks()| getter.
78    virtual void OnChunkUpload(int fetcher_id) = 0;
79
80    // Callback issued correspondingly to the destructor.
81    virtual void OnRequestEnd(int fetcher_id) = 0;
82  };
83
84  TestURLFetcher(int id,
85                 const GURL& url,
86                 URLFetcherDelegate* d);
87  virtual ~TestURLFetcher();
88
89  // URLFetcher implementation
90  virtual void SetUploadData(const std::string& upload_content_type,
91                             const std::string& upload_content) OVERRIDE;
92  virtual void SetUploadFilePath(
93      const std::string& upload_content_type,
94      const base::FilePath& file_path,
95      uint64 range_offset,
96      uint64 range_length,
97      scoped_refptr<base::TaskRunner> file_task_runner) OVERRIDE;
98  virtual void SetChunkedUpload(
99      const std::string& upload_content_type) OVERRIDE;
100  // Overriden to cache the chunks uploaded. Caller can read back the uploaded
101  // chunks with the upload_chunks() accessor.
102  virtual void AppendChunkToUpload(const std::string& data,
103                                   bool is_last_chunk) OVERRIDE;
104  virtual void SetLoadFlags(int load_flags) OVERRIDE;
105  virtual int GetLoadFlags() const OVERRIDE;
106  virtual void SetReferrer(const std::string& referrer) OVERRIDE;
107  virtual void SetReferrerPolicy(
108      URLRequest::ReferrerPolicy referrer_policy) OVERRIDE;
109  virtual void SetExtraRequestHeaders(
110      const std::string& extra_request_headers) OVERRIDE;
111  virtual void AddExtraRequestHeader(const std::string& header_line) OVERRIDE;
112  virtual void SetRequestContext(
113      URLRequestContextGetter* request_context_getter) OVERRIDE;
114  virtual void SetFirstPartyForCookies(
115      const GURL& first_party_for_cookies) OVERRIDE;
116  virtual void SetURLRequestUserData(
117      const void* key,
118      const CreateDataCallback& create_data_callback) OVERRIDE;
119  virtual void SetStopOnRedirect(bool stop_on_redirect) OVERRIDE;
120  virtual void SetAutomaticallyRetryOn5xx(bool retry) OVERRIDE;
121  virtual void SetMaxRetriesOn5xx(int max_retries) OVERRIDE;
122  virtual int GetMaxRetriesOn5xx() const OVERRIDE;
123  virtual base::TimeDelta GetBackoffDelay() const OVERRIDE;
124  virtual void SetAutomaticallyRetryOnNetworkChanges(int max_retries) OVERRIDE;
125  virtual void SaveResponseToFileAtPath(
126      const base::FilePath& file_path,
127      scoped_refptr<base::SequencedTaskRunner> file_task_runner) OVERRIDE;
128  virtual void SaveResponseToTemporaryFile(
129      scoped_refptr<base::SequencedTaskRunner> file_task_runner) OVERRIDE;
130  virtual void SaveResponseWithWriter(
131      scoped_ptr<URLFetcherResponseWriter> response_writer) OVERRIDE;
132  virtual HttpResponseHeaders* GetResponseHeaders() const OVERRIDE;
133  virtual HostPortPair GetSocketAddress() const OVERRIDE;
134  virtual bool WasFetchedViaProxy() const OVERRIDE;
135  virtual void Start() OVERRIDE;
136
137  // URL we were created with. Because of how we're using URLFetcher GetURL()
138  // always returns an empty URL. Chances are you'll want to use
139  // GetOriginalURL() in your tests.
140  virtual const GURL& GetOriginalURL() const OVERRIDE;
141  virtual const GURL& GetURL() const OVERRIDE;
142  virtual const URLRequestStatus& GetStatus() const OVERRIDE;
143  virtual int GetResponseCode() const OVERRIDE;
144  virtual const ResponseCookies& GetCookies() const OVERRIDE;
145  virtual void ReceivedContentWasMalformed() OVERRIDE;
146  // Override response access functions to return fake data.
147  virtual bool GetResponseAsString(
148      std::string* out_response_string) const OVERRIDE;
149  virtual bool GetResponseAsFilePath(
150      bool take_ownership, base::FilePath* out_response_path) const OVERRIDE;
151
152  void GetExtraRequestHeaders(HttpRequestHeaders* headers) const;
153
154  // Sets owner of this class.  Set it to a non-NULL value if you want
155  // to automatically unregister this fetcher from the owning factory
156  // upon destruction.
157  void set_owner(TestURLFetcherFactory* owner) { owner_ = owner; }
158
159  // Unique ID in our factory.
160  int id() const { return id_; }
161
162  // Returns the data uploaded on this URLFetcher.
163  const std::string& upload_data() const { return upload_data_; }
164  const base::FilePath& upload_file_path() const { return upload_file_path_; }
165
166  // Returns the chunks of data uploaded on this URLFetcher.
167  const std::list<std::string>& upload_chunks() const { return chunks_; }
168
169  // Checks whether the last call to |AppendChunkToUpload(...)| was final.
170  bool did_receive_last_chunk() const { return did_receive_last_chunk_; }
171
172  // Returns the delegate installed on the URLFetcher.
173  URLFetcherDelegate* delegate() const { return delegate_; }
174
175  void set_url(const GURL& url) { fake_url_ = url; }
176  void set_status(const URLRequestStatus& status);
177  void set_response_code(int response_code) {
178    fake_response_code_ = response_code;
179  }
180  void set_cookies(const ResponseCookies& c) { fake_cookies_ = c; }
181  void set_was_fetched_via_proxy(bool flag);
182  void set_response_headers(scoped_refptr<HttpResponseHeaders> headers);
183  void set_backoff_delay(base::TimeDelta backoff_delay);
184  void SetDelegateForTests(DelegateForTests* delegate_for_tests);
185
186  // Set string data.
187  void SetResponseString(const std::string& response);
188
189  // Set File data.
190  void SetResponseFilePath(const base::FilePath& path);
191
192 private:
193  enum ResponseDestinationType {
194    STRING,  // Default: In a std::string
195    TEMP_FILE  // Write to a temp file
196  };
197
198  TestURLFetcherFactory* owner_;
199  const int id_;
200  const GURL original_url_;
201  URLFetcherDelegate* delegate_;
202  DelegateForTests* delegate_for_tests_;
203  std::string upload_data_;
204  base::FilePath upload_file_path_;
205  std::list<std::string> chunks_;
206  bool did_receive_last_chunk_;
207
208  // User can use set_* methods to provide values returned by getters.
209  // Setting the real values is not possible, because the real class
210  // has no setters. The data is a private member of a class defined
211  // in a .cc file, so we can't get at it with friendship.
212  int fake_load_flags_;
213  GURL fake_url_;
214  URLRequestStatus fake_status_;
215  int fake_response_code_;
216  ResponseCookies fake_cookies_;
217  ResponseDestinationType fake_response_destination_;
218  std::string fake_response_string_;
219  base::FilePath fake_response_file_path_;
220  bool fake_was_fetched_via_proxy_;
221  scoped_refptr<HttpResponseHeaders> fake_response_headers_;
222  HttpRequestHeaders fake_extra_request_headers_;
223  int fake_max_retries_;
224  base::TimeDelta fake_backoff_delay_;
225  scoped_ptr<URLFetcherResponseWriter> response_writer_;
226
227  DISALLOW_COPY_AND_ASSIGN(TestURLFetcher);
228};
229
230typedef TestURLFetcher::DelegateForTests TestURLFetcherDelegateForTests;
231
232// Simple URLFetcherFactory method that creates TestURLFetchers. All fetchers
233// are registered in a map by the id passed to the create method.
234// Optionally, a fetcher may be automatically unregistered from the map upon
235// its destruction.
236class TestURLFetcherFactory : public URLFetcherFactory,
237                              public ScopedURLFetcherFactory {
238 public:
239  TestURLFetcherFactory();
240  virtual ~TestURLFetcherFactory();
241
242  virtual URLFetcher* CreateURLFetcher(
243      int id,
244      const GURL& url,
245      URLFetcher::RequestType request_type,
246      URLFetcherDelegate* d) OVERRIDE;
247  TestURLFetcher* GetFetcherByID(int id) const;
248  void RemoveFetcherFromMap(int id);
249  void SetDelegateForTests(TestURLFetcherDelegateForTests* delegate_for_tests);
250  void set_remove_fetcher_on_delete(bool remove_fetcher_on_delete) {
251    remove_fetcher_on_delete_ = remove_fetcher_on_delete;
252  }
253
254 private:
255  // Maps from id passed to create to the returned URLFetcher.
256  typedef std::map<int, TestURLFetcher*> Fetchers;
257  Fetchers fetchers_;
258  TestURLFetcherDelegateForTests* delegate_for_tests_;
259  // Whether to automatically unregister a fetcher from this factory upon its
260  // destruction, false by default.
261  bool remove_fetcher_on_delete_;
262
263  DISALLOW_COPY_AND_ASSIGN(TestURLFetcherFactory);
264};
265
266// The FakeURLFetcher and FakeURLFetcherFactory classes are similar to the
267// ones above but don't require you to know when exactly the URLFetcher objects
268// will be created.
269//
270// These classes let you set pre-baked HTTP responses for particular URLs.
271// E.g., if the user requests http://a.com/ then respond with an HTTP/500.
272//
273// We assume that the thread that is calling Start() on the URLFetcher object
274// has a message loop running.
275
276// FakeURLFetcher can be used to create a URLFetcher that will emit a fake
277// response when started. This class can be used in place of an actual
278// URLFetcher.
279//
280// Example usage:
281//  FakeURLFetcher fake_fetcher("http://a.com", some_delegate,
282//                              "<html><body>hello world</body></html>",
283//                              HTTP_OK);
284//
285// // Will schedule a call to some_delegate->OnURLFetchComplete(&fake_fetcher).
286// fake_fetcher.Start();
287class FakeURLFetcher : public TestURLFetcher {
288 public:
289  // Normal URL fetcher constructor but also takes in a pre-baked response.
290  FakeURLFetcher(const GURL& url,
291                 URLFetcherDelegate* d,
292                 const std::string& response_data,
293                 HttpStatusCode response_code,
294                 URLRequestStatus::Status status);
295
296  // Start the request.  This will call the given delegate asynchronously
297  // with the pre-baked response as parameter.
298  virtual void Start() OVERRIDE;
299
300  virtual const GURL& GetURL() const OVERRIDE;
301
302  virtual ~FakeURLFetcher();
303
304 private:
305  // This is the method which actually calls the delegate that is passed in the
306  // constructor.
307  void RunDelegate();
308
309  base::WeakPtrFactory<FakeURLFetcher> weak_factory_;
310
311  DISALLOW_COPY_AND_ASSIGN(FakeURLFetcher);
312};
313
314
315// FakeURLFetcherFactory is a factory for FakeURLFetcher objects. When
316// instantiated, it sets itself up as the default URLFetcherFactory. Fake
317// responses for given URLs can be set using SetFakeResponse.
318//
319// This class is not thread-safe.  You should not call SetFakeResponse or
320// ClearFakeResponse at the same time you call CreateURLFetcher.  However, it is
321// OK to start URLFetcher objects while setting or clearing fake responses
322// since already created URLFetcher objects will not be affected by any changes
323// made to the fake responses (once a URLFetcher object is created you cannot
324// change its fake response).
325//
326// Example usage:
327//  FakeURLFetcherFactory factory;
328//
329//  // You know that class SomeService will request http://a.com/success and you
330//  // want to respond with a simple html page and an HTTP/200 code.
331//  factory.SetFakeResponse("http://a.com/success",
332//                          "<html><body>hello world</body></html>",
333//                          HTTP_OK,
334//                          URLRequestStatus::SUCCESS);
335//  // You know that class SomeService will request url http://a.com/servererror
336//  // and you want to test the service class by returning a server error.
337//  factory.SetFakeResponse("http://a.com/servererror",
338//                          "",
339//                          HTTP_INTERNAL_SERVER_ERROR,
340//                          URLRequestStatus::SUCCESS);
341//  // You know that class SomeService will request url http://a.com/autherror
342//  // and you want to test the service class by returning a specific error
343//  // code, say, a HTTP/401 error.
344//  factory.SetFakeResponse("http://a.com/autherror",
345//                          "some_response",
346//                          HTTP_UNAUTHORIZED,
347//                          URLRequestStatus::SUCCESS);
348//
349//  // You know that class SomeService will request url http://a.com/failure
350//  // and you want to test the service class by returning a failure in the
351//  // network layer.
352//  factory.SetFakeResponse("http://a.com/failure",
353//                          "",
354//                          HTTP_INTERNAL_SERVER_ERROR,
355//                          URLRequestStatus::FAILURE);
356//
357//  SomeService service;
358//  service.Run();  // Will eventually request these three URLs.
359class FakeURLFetcherFactory : public URLFetcherFactory,
360                              public ScopedURLFetcherFactory {
361 public:
362  // Parameters to FakeURLFetcherCreator: url, delegate, response_data,
363  //                                      response_code
364  // |url| URL for instantiated FakeURLFetcher
365  // |delegate| Delegate for FakeURLFetcher
366  // |response_data| response data for FakeURLFetcher
367  // |response_code| response code for FakeURLFetcher
368  // |status| URL fetch status for FakeURLFetcher
369  // These arguments should by default be used in instantiating FakeURLFetcher
370  // like so:
371  // new FakeURLFetcher(url, delegate, response_data, response_code, status)
372  typedef base::Callback<scoped_ptr<FakeURLFetcher>(
373      const GURL&,
374      URLFetcherDelegate*,
375      const std::string&,
376      HttpStatusCode,
377      URLRequestStatus::Status)> FakeURLFetcherCreator;
378
379  // |default_factory|, which can be NULL, is a URLFetcherFactory that
380  // will be used to construct a URLFetcher in case the URL being created
381  // has no pre-baked response. If it is NULL, a URLFetcherImpl will be
382  // created in this case.
383  explicit FakeURLFetcherFactory(URLFetcherFactory* default_factory);
384
385  // |default_factory|, which can be NULL, is a URLFetcherFactory that
386  // will be used to construct a URLFetcher in case the URL being created
387  // has no pre-baked response. If it is NULL, a URLFetcherImpl will be
388  // created in this case.
389  // |creator| is a callback that returns will be called to create a
390  // FakeURLFetcher if a response is found to a given URL. It can be
391  // set to MakeFakeURLFetcher.
392  FakeURLFetcherFactory(URLFetcherFactory* default_factory,
393                        const FakeURLFetcherCreator& creator);
394
395  virtual ~FakeURLFetcherFactory();
396
397  // If no fake response is set for the given URL this method will delegate the
398  // call to |default_factory_| if it is not NULL, or return NULL if it is
399  // NULL.
400  // Otherwise, it will return a URLFetcher object which will respond with the
401  // pre-baked response that the client has set by calling SetFakeResponse().
402  virtual URLFetcher* CreateURLFetcher(
403      int id,
404      const GURL& url,
405      URLFetcher::RequestType request_type,
406      URLFetcherDelegate* d) OVERRIDE;
407
408  // Sets the fake response for a given URL. The |response_data| may be empty.
409  // The |response_code| may be any HttpStatusCode. For instance, HTTP_OK will
410  // return an HTTP/200 and HTTP_INTERNAL_SERVER_ERROR will return an HTTP/500.
411  // The |status| argument may be any URLRequestStatus::Status value. Typically,
412  // requests that return a valid HttpStatusCode have the SUCCESS status, while
413  // requests that indicate a failure to connect to the server have the FAILED
414  // status.
415  void SetFakeResponse(const GURL& url,
416                       const std::string& response_data,
417                       HttpStatusCode response_code,
418                       URLRequestStatus::Status status);
419
420  // Clear all the fake responses that were previously set via
421  // SetFakeResponse().
422  void ClearFakeResponses();
423
424 private:
425  struct FakeURLResponse {
426    std::string response_data;
427    HttpStatusCode response_code;
428    URLRequestStatus::Status status;
429  };
430  typedef std::map<GURL, FakeURLResponse> FakeResponseMap;
431
432  const FakeURLFetcherCreator creator_;
433  FakeResponseMap fake_responses_;
434  URLFetcherFactory* const default_factory_;
435
436  static scoped_ptr<FakeURLFetcher> DefaultFakeURLFetcherCreator(
437      const GURL& url,
438      URLFetcherDelegate* delegate,
439      const std::string& response_data,
440      HttpStatusCode response_code,
441      URLRequestStatus::Status status);
442  DISALLOW_COPY_AND_ASSIGN(FakeURLFetcherFactory);
443};
444
445// This is an implementation of URLFetcherFactory that will create a
446// URLFetcherImpl. It can be use in conjunction with a FakeURLFetcherFactory in
447// integration tests to control the behavior of some requests but execute
448// all the other ones.
449class URLFetcherImplFactory : public URLFetcherFactory {
450 public:
451  URLFetcherImplFactory();
452  virtual ~URLFetcherImplFactory();
453
454  // This method will create a real URLFetcher.
455  virtual URLFetcher* CreateURLFetcher(
456      int id,
457      const GURL& url,
458      URLFetcher::RequestType request_type,
459      URLFetcherDelegate* d) OVERRIDE;
460};
461
462}  // namespace net
463
464#endif  // NET_URL_REQUEST_TEST_URL_FETCHER_FACTORY_H_
465